From 073b03d90c8f0648ba135f0b30d8e72fd871478f Mon Sep 17 00:00:00 2001 From: Christian Parpart Date: Fri, 30 Nov 2018 14:34:08 +0100 Subject: liblangutil: refactor SourceReferenceFormatter, splitting out retrieval and making use of new SourceLocation's CharStream knowledge --- libsolidity/interface/StandardCompiler.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) (limited to 'libsolidity/interface/StandardCompiler.cpp') diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 0eef50d2..862b6633 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -69,12 +69,11 @@ Json::Value formatErrorWithException( bool const& _warning, string const& _type, string const& _component, - string const& _message, - function const& _scannerFromSourceName + string const& _message ) { string message; - string formattedMessage = SourceReferenceFormatter::formatExceptionInformation(_exception, _type, _scannerFromSourceName); + string formattedMessage = SourceReferenceFormatter::formatExceptionInformation(_exception, _type); // NOTE: the below is partially a copy from SourceReferenceFormatter SourceLocation const* location = boost::get_error_info(_exception); @@ -433,8 +432,6 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) Json::Value outputSelection = settings.get("outputSelection", Json::Value()); m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection)); - auto scannerFromSourceName = [&](string const& _sourceName) -> Scanner const& { return m_compilerStack.scanner(_sourceName); }; - try { m_compilerStack.compile(); @@ -448,8 +445,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) err.type() == Error::Type::Warning, err.typeName(), "general", - "", - scannerFromSourceName + "" )); } } @@ -461,8 +457,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) false, _error.typeName(), "general", - "Uncaught error: ", - scannerFromSourceName + "Uncaught error: " )); } /// This should not be leaked from compile(). @@ -482,8 +477,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) false, "CompilerError", "general", - "Compiler error (" + _exception.lineInfo() + ")", - scannerFromSourceName + "Compiler error (" + _exception.lineInfo() + ")" )); } catch (InternalCompilerError const& _exception) @@ -493,8 +487,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) false, "InternalCompilerError", "general", - "Internal compiler error (" + _exception.lineInfo() + ")", - scannerFromSourceName + "Internal compiler error (" + _exception.lineInfo() + ")" )); } catch (UnimplementedFeatureError const& _exception) @@ -504,8 +497,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) false, "UnimplementedFeatureError", "general", - "Unimplemented feature (" + _exception.lineInfo() + ")", - scannerFromSourceName + "Unimplemented feature (" + _exception.lineInfo() + ")" )); } catch (Exception const& _exception) -- cgit v1.2.3 From 8cd2ac84622185a59ee61439289d1defe58dec99 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Tue, 11 Dec 2018 15:47:19 +0100 Subject: Disallow unknown JSON keys in standard-json --- libsolidity/interface/StandardCompiler.cpp | 68 ++++++++++++++++++++++++++++++ 1 file changed, 68 insertions(+) (limited to 'libsolidity/interface/StandardCompiler.cpp') diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 862b6633..21d213e7 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -27,7 +27,10 @@ #include #include +#include + #include +#include using namespace std; using namespace dev; @@ -225,6 +228,50 @@ Json::Value collectEVMObject(eth::LinkerObject const& _object, string const* _so return output; } +boost::optional checkKeys(Json::Value const& _input, set const& _keys) +{ + for (auto const& member: _input.getMemberNames()) + if (!_keys.count(member)) + return formatFatalError("JSONError", "Unknown key \"" + member + "\""); + return boost::none; +} + +boost::optional checkRootKeys(Json::Value const& _input) +{ + static set keys{"auxiliaryInput", "language", "settings", "sources"}; + return checkKeys(_input, keys); +} + +boost::optional checkSourceKeys(Json::Value const& _input) +{ + static set keys{"content", "keccak256", "urls"}; + return checkKeys(_input, keys); +} + +boost::optional checkAuxiliaryInputKeys(Json::Value const& _input) +{ + static set keys{"smtlib2responses"}; + return checkKeys(_input, keys); +} + +boost::optional checkSettingsKeys(Json::Value const& _input) +{ + static set keys{"evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"}; + return checkKeys(_input, keys); +} + +boost::optional checkOptimizerKeys(Json::Value const& _input) +{ + static set keys{"enabled", "runs"}; + return checkKeys(_input, keys); +} + +boost::optional checkMetadataKeys(Json::Value const& _input) +{ + static set keys{"useLiteralContent"}; + return checkKeys(_input, keys); +} + } Json::Value StandardCompiler::compileInternal(Json::Value const& _input) @@ -234,6 +281,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) if (!_input.isObject()) return formatFatalError("JSONError", "Input is not a JSON object."); + if (auto result = checkRootKeys(_input)) + return *result; + if (_input["language"] != "Solidity") return formatFatalError("JSONError", "Only \"Solidity\" is supported as a language."); @@ -254,6 +304,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) if (!sources[sourceName].isObject()) return formatFatalError("JSONError", "Source input is not a JSON object."); + if (auto result = checkSourceKeys(sources[sourceName])) + return *result; + if (sources[sourceName]["keccak256"].isString()) hash = sources[sourceName]["keccak256"].asString(); @@ -319,6 +372,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) } Json::Value const& auxInputs = _input["auxiliaryInput"]; + + if (auto result = checkAuxiliaryInputKeys(auxInputs)) + return *result; + if (!!auxInputs) { Json::Value const& smtlib2Responses = auxInputs["smtlib2responses"]; @@ -341,6 +398,9 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) Json::Value const& settings = _input.get("settings", Json::Value()); + if (auto result = checkSettingsKeys(settings)) + return *result; + if (settings.isMember("evmVersion")) { if (!settings["evmVersion"].isString()) @@ -366,6 +426,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) if (settings.isMember("optimizer")) { Json::Value optimizerSettings = settings["optimizer"]; + + if (auto result = checkOptimizerKeys(optimizerSettings)) + return *result; + if (optimizerSettings.isMember("enabled")) { if (!optimizerSettings["enabled"].isBool()) @@ -427,6 +491,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.setLibraries(libraries); Json::Value metadataSettings = settings.get("metadata", Json::Value()); + + if (auto result = checkMetadataKeys(metadataSettings)) + return *result; + m_compilerStack.useMetadataLiteralSources(metadataSettings.get("useLiteralContent", Json::Value(false)).asBool()); Json::Value outputSelection = settings.get("outputSelection", Json::Value()); -- cgit v1.2.3 From 340ee4156d6c133a40ebb50284ab49ae0ebb7d69 Mon Sep 17 00:00:00 2001 From: Leonardo Alt Date: Mon, 17 Dec 2018 19:24:42 +0100 Subject: Sort includes in libsolidity/interface --- libsolidity/interface/StandardCompiler.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'libsolidity/interface/StandardCompiler.cpp') diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 21d213e7..5be267e9 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -21,16 +21,16 @@ */ #include -#include + #include +#include #include #include #include -#include - #include #include +#include using namespace std; using namespace dev; -- cgit v1.2.3 From c43d96f2bf5614136bfbcaf45d0850c914bf81ee Mon Sep 17 00:00:00 2001 From: Mathias Baumann Date: Wed, 12 Dec 2018 15:49:10 +0100 Subject: Json: Provide better error messages for wrong types --- libsolidity/interface/StandardCompiler.cpp | 90 +++++++++++++++++++++++++----- 1 file changed, 77 insertions(+), 13 deletions(-) (limited to 'libsolidity/interface/StandardCompiler.cpp') diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 5be267e9..e99b1324 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -228,48 +228,97 @@ Json::Value collectEVMObject(eth::LinkerObject const& _object, string const* _so return output; } -boost::optional checkKeys(Json::Value const& _input, set const& _keys) +boost::optional checkKeys(Json::Value const& _input, set const& _keys, string const& _name) { + if (!!_input && !_input.isObject()) + return formatFatalError("JSONError", "\"" + _name + "\" must be an object"); + for (auto const& member: _input.getMemberNames()) if (!_keys.count(member)) return formatFatalError("JSONError", "Unknown key \"" + member + "\""); + return boost::none; } boost::optional checkRootKeys(Json::Value const& _input) { static set keys{"auxiliaryInput", "language", "settings", "sources"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "root"); } -boost::optional checkSourceKeys(Json::Value const& _input) +boost::optional checkSourceKeys(Json::Value const& _input, string const& _name) { static set keys{"content", "keccak256", "urls"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "sources." + _name); } boost::optional checkAuxiliaryInputKeys(Json::Value const& _input) { static set keys{"smtlib2responses"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "auxiliaryInput"); } boost::optional checkSettingsKeys(Json::Value const& _input) { static set keys{"evmVersion", "libraries", "metadata", "optimizer", "outputSelection", "remappings"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "settings"); } boost::optional checkOptimizerKeys(Json::Value const& _input) { static set keys{"enabled", "runs"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "settings.optimizer"); } boost::optional checkMetadataKeys(Json::Value const& _input) { static set keys{"useLiteralContent"}; - return checkKeys(_input, keys); + return checkKeys(_input, keys, "settings.metadata"); +} + +boost::optional checkOutputSelection(Json::Value const& _outputSelection) +{ + if (!!_outputSelection && !_outputSelection.isObject()) + return formatFatalError("JSONError", "\"settings.outputSelection\" must be an object"); + + for (auto const& sourceName: _outputSelection.getMemberNames()) + { + auto const& sourceVal = _outputSelection[sourceName]; + + if (!sourceVal.isObject()) + return formatFatalError( + "JSONError", + "\"settings.outputSelection." + sourceName + "\" must be an object" + ); + + for (auto const& contractName: sourceVal.getMemberNames()) + { + auto const& contractVal = sourceVal[contractName]; + + if (!contractVal.isArray()) + return formatFatalError( + "JSONError", + "\"settings.outputSelection." + + sourceName + + "." + + contractName + + "\" must be a string array" + ); + + for (auto const& output: contractVal) + if (!output.isString()) + return formatFatalError( + "JSONError", + "\"settings.outputSelection." + + sourceName + + "." + + contractName + + "\" must be a string array" + ); + } + } + + return boost::none; } } @@ -301,10 +350,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) { string hash; - if (!sources[sourceName].isObject()) - return formatFatalError("JSONError", "Source input is not a JSON object."); - - if (auto result = checkSourceKeys(sources[sourceName])) + if (auto result = checkSourceKeys(sources[sourceName], sourceName)) return *result; if (sources[sourceName]["keccak256"].isString()) @@ -380,6 +426,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) { Json::Value const& smtlib2Responses = auxInputs["smtlib2responses"]; if (!!smtlib2Responses) + { + if (!smtlib2Responses.isObject()) + return formatFatalError("JSONError", "\"auxiliaryInput.smtlib2responses\" must be an object."); + for (auto const& hashString: smtlib2Responses.getMemberNames()) { h256 hash; @@ -392,8 +442,15 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) return formatFatalError("JSONError", "Invalid hex encoding of SMTLib2 auxiliary input."); } + if (!smtlib2Responses[hashString].isString()) + return formatFatalError( + "JSONError", + "\"smtlib2Responses." + hashString + "\" must be a string." + ); + m_compilerStack.addSMTLib2Response(hash, smtlib2Responses[hashString].asString()); } + } } Json::Value const& settings = _input.get("settings", Json::Value()); @@ -411,11 +468,14 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.setEVMVersion(*version); } + if (settings.isMember("remappings") && !settings["remappings"].isArray()) + return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings."); + vector remappings; for (auto const& remapping: settings.get("remappings", Json::Value())) { if (!remapping.isString()) - return formatFatalError("JSONError", "Remapping entry must be a string."); + return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings"); if (auto r = CompilerStack::parseRemapping(remapping.asString())) remappings.emplace_back(std::move(*r)); else @@ -498,6 +558,10 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.useMetadataLiteralSources(metadataSettings.get("useLiteralContent", Json::Value(false)).asBool()); Json::Value outputSelection = settings.get("outputSelection", Json::Value()); + + if (auto jsonError = checkOutputSelection(outputSelection)) + return *jsonError; + m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection)); try -- cgit v1.2.3 From beae2a608ba09cfdf1720fa8655cb22cf2d6c051 Mon Sep 17 00:00:00 2001 From: chriseth Date: Tue, 18 Dec 2018 18:28:14 +0100 Subject: Only fully compile if binaries requested. --- libsolidity/interface/StandardCompiler.cpp | 49 ++++++++++++++++++++++++------ 1 file changed, 40 insertions(+), 9 deletions(-) (limited to 'libsolidity/interface/StandardCompiler.cpp') diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index e99b1324..6415e732 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -28,6 +28,7 @@ #include #include +#include #include #include #include @@ -191,6 +192,31 @@ bool isArtifactRequested(Json::Value const& _outputSelection, string const& _fil return false; } +/// @returns true if any binary was requested, i.e. we actually have to perform compilation. +bool isBinaryRequested(Json::Value const& _outputSelection) +{ + if (!_outputSelection.isObject()) + return false; + + // This does not inculde "evm.methodIdentifiers" on purpose! + static vector const outputsThatRequireBinaries{ + "*", + "metadata", // This is only generated at the end of compilation, but could be generated earlier. + "evm.deployedBytecode", "evm.deployedBytecode.object", "evm.deployedBytecode.opcodes", + "evm.deployedBytecode.sourceMap", "evm.deployedBytecode.linkReferences", + "evm.bytecode", "evm.bytecode.object", "evm.bytecode.opcodes", "evm.bytecode.sourceMap", + "evm.bytecode.linkReferences", + "evm.gasEstimates", "evm.legacyAssembly", "evm.assembly" + }; + + for (auto const& fileRequests: _outputSelection) + for (auto const& requests: fileRequests) + for (auto const& output: outputsThatRequireBinaries) + if (isArtifactRequested(requests, output)) + return true; + return false; +} + Json::Value formatLinkReferences(std::map const& linkReferences) { Json::Value ret(Json::objectValue); @@ -564,9 +590,14 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.setRequestedContractNames(requestedContractNames(outputSelection)); + bool const binariesRequested = isBinaryRequested(outputSelection); + try { - m_compilerStack.compile(); + if (binariesRequested) + m_compilerStack.compile(); + else + m_compilerStack.parseAndAnalyze(); for (auto const& error: m_compilerStack.errors()) { @@ -655,7 +686,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) bool const compilationSuccess = m_compilerStack.state() == CompilerStack::State::CompilationSuccessful; /// Inconsistent state - stop here to receive error reports from users - if (!compilationSuccess && errors.empty()) + if (((binariesRequested && !compilationSuccess) || !analysisSuccess) && errors.empty()) return formatFatalError("InternalCompilerError", "No error reported, but compilation failed."); Json::Value output = Json::objectValue; @@ -681,7 +712,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) } Json::Value contractsOutput = Json::objectValue; - for (string const& contractName: compilationSuccess ? m_compilerStack.contractNames() : vector()) + for (string const& contractName: analysisSuccess ? m_compilerStack.contractNames() : vector()) { size_t colon = contractName.rfind(':'); solAssert(colon != string::npos, ""); @@ -692,7 +723,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) Json::Value contractData(Json::objectValue); if (isArtifactRequested(outputSelection, file, name, "abi")) contractData["abi"] = m_compilerStack.contractABI(contractName); - if (isArtifactRequested(outputSelection, file, name, "metadata")) + if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "metadata")) contractData["metadata"] = m_compilerStack.metadata(contractName); if (isArtifactRequested(outputSelection, file, name, "userdoc")) contractData["userdoc"] = m_compilerStack.natspecUser(contractName); @@ -702,16 +733,16 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) // EVM Json::Value evmData(Json::objectValue); // @TODO: add ir - if (isArtifactRequested(outputSelection, file, name, "evm.assembly")) + if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "evm.assembly")) evmData["assembly"] = m_compilerStack.assemblyString(contractName, createSourceList(_input)); - if (isArtifactRequested(outputSelection, file, name, "evm.legacyAssembly")) + if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "evm.legacyAssembly")) evmData["legacyAssembly"] = m_compilerStack.assemblyJSON(contractName, createSourceList(_input)); if (isArtifactRequested(outputSelection, file, name, "evm.methodIdentifiers")) evmData["methodIdentifiers"] = m_compilerStack.methodIdentifiers(contractName); - if (isArtifactRequested(outputSelection, file, name, "evm.gasEstimates")) + if (compilationSuccess && isArtifactRequested(outputSelection, file, name, "evm.gasEstimates")) evmData["gasEstimates"] = m_compilerStack.gasEstimates(contractName); - if (isArtifactRequested( + if (compilationSuccess && isArtifactRequested( outputSelection, file, name, @@ -722,7 +753,7 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.sourceMapping(contractName) ); - if (isArtifactRequested( + if (compilationSuccess && isArtifactRequested( outputSelection, file, name, -- cgit v1.2.3 From 4c7151e57f90c2b0d7a47ff7d6470da54bae00f0 Mon Sep 17 00:00:00 2001 From: chriseth Date: Wed, 19 Dec 2018 12:22:19 +0100 Subject: Do not include empty JSON objects in output. --- libsolidity/interface/StandardCompiler.cpp | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) (limited to 'libsolidity/interface/StandardCompiler.cpp') diff --git a/libsolidity/interface/StandardCompiler.cpp b/libsolidity/interface/StandardCompiler.cpp index 6415e732..137a4439 100644 --- a/libsolidity/interface/StandardCompiler.cpp +++ b/libsolidity/interface/StandardCompiler.cpp @@ -764,14 +764,18 @@ Json::Value StandardCompiler::compileInternal(Json::Value const& _input) m_compilerStack.runtimeSourceMapping(contractName) ); - contractData["evm"] = evmData; + if (!evmData.empty()) + contractData["evm"] = evmData; - if (!contractsOutput.isMember(file)) - contractsOutput[file] = Json::objectValue; - - contractsOutput[file][name] = contractData; + if (!contractData.empty()) + { + if (!contractsOutput.isMember(file)) + contractsOutput[file] = Json::objectValue; + contractsOutput[file][name] = contractData; + } } - output["contracts"] = contractsOutput; + if (!contractsOutput.empty()) + output["contracts"] = contractsOutput; return output; } -- cgit v1.2.3