Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Changelog.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,9 @@

Features:
* Code Generator: Assert that ``k != 0`` for ``molmod(a, b, k)`` and ``addmod(a, b, k)`` as experimental 0.5.0 feature.
* Standard JSON: Reject badly formatted invalid JSON inputs.
* Type Checker: Disallow uninitialized storage pointers as experimental 0.5.0 feature.


Bugfixes:
* JSON-AST: Add "documentation" property to function, event and modifier definition.
* Resolver: Properly determine shadowing for imports with aliases.
Expand Down
4 changes: 3 additions & 1 deletion libdevcore/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,9 @@ file(GLOB sources "*.cpp")
file(GLOB headers "*.h")

add_library(devcore ${sources} ${headers})
target_link_libraries(devcore PRIVATE ${Boost_FILESYSTEM_LIBRARIES} ${Boost_REGEX_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
target_link_libraries(devcore PRIVATE ${JSONCPP_LIBRARY} ${Boost_FILESYSTEM_LIBRARIES} ${Boost_REGEX_LIBRARIES} ${Boost_SYSTEM_LIBRARIES} ${CMAKE_THREAD_LIBS_INIT})
target_include_directories(devcore SYSTEM PUBLIC ${Boost_INCLUDE_DIRS})
target_include_directories(devcore PUBLIC "${CMAKE_SOURCE_DIR}")
target_include_directories(devcore PUBLIC "${JSONCPP_INCLUDE_DIR}")
add_dependencies(devcore jsoncpp)
add_dependencies(devcore solidity_BuildInfo.h)
109 changes: 109 additions & 0 deletions libdevcore/JSON.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
/*
This file is part of solidity.

solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.

solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
/** @file JSON.cpp
* @author Alexander Arlt <alexander.arlt@arlt-labs.com>
* @date 2018
*/

#include "JSON.h"

#include <sstream>
#include <map>
#include <memory>

using namespace std;

namespace dev
{

namespace
{

/// StreamWriterBuilder that can be constructed with specific settings
class StreamWriterBuilder: public Json::StreamWriterBuilder
{
public:
explicit StreamWriterBuilder(map<string, string> const& _settings)
{
for (auto const& iter :_settings)
this->settings_[iter.first] = iter.second;
}
};

/// CharReaderBuilder with strict-mode settings
class StrictModeCharReaderBuilder: public Json::CharReaderBuilder
{
public:
StrictModeCharReaderBuilder()
{
Json::CharReaderBuilder::strictMode(&this->settings_);
}
};

/// Serialise the JSON object (@a _input) with specific builder (@a _builder)
/// \param _input JSON input string
/// \param _builder StreamWriterBuilder that is used to create new Json::StreamWriter
/// \return serialized json object
string print(Json::Value const& _input, Json::StreamWriterBuilder const& _builder)
{
stringstream stream;
unique_ptr<Json::StreamWriter> writer(_builder.newStreamWriter());
writer->write(_input, &stream);
return stream.str();
}

/// Parse a JSON string (@a _input) with specified builder (@ _builder) and writes resulting JSON object to (@a _json)
/// \param _builder CharReaderBuilder that is used to create new Json::CharReaders
/// \param _input JSON input string
/// \param _json [out] resulting JSON object
/// \param _errs [out] Formatted error messages
/// \return \c true if the document was successfully parsed, \c false if an error occurred.
bool parse(Json::CharReaderBuilder& _builder, string const& _input, Json::Value& _json, string* _errs)
{
unique_ptr<Json::CharReader> reader(_builder.newCharReader());
return reader->parse(_input.c_str(), _input.c_str() + _input.length(), &_json, _errs);
}

} // end anonymous namespace

string jsonPrettyPrint(Json::Value const& _input)
{
static map<string, string> settings{{"indentation", " "}};
static StreamWriterBuilder writerBuilder(settings);
return print(_input, writerBuilder);
}

string jsonCompactPrint(Json::Value const& _input)
{
static map<string, string> settings{{"indentation", ""}};
static StreamWriterBuilder writerBuilder(settings);
return print(_input, writerBuilder);
}

bool jsonParseStrict(string const& _input, Json::Value& _json, string* _errs /* = nullptr */)
{
static StrictModeCharReaderBuilder readerBuilder;
return parse(readerBuilder, _input, _json, _errs);
}

bool jsonParse(string const& _input, Json::Value& _json, string *_errs /* = nullptr */)
{
static Json::CharReaderBuilder readerBuilder;
return parse(readerBuilder, _input, _json, _errs);
}

} // namespace dev
31 changes: 19 additions & 12 deletions libdevcore/JSON.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,21 +24,28 @@

#include <json/json.h>

namespace dev
{
#include <string>

namespace dev {

/// Serialise the JSON object (@a _input) with indentation
inline std::string jsonPrettyPrint(Json::Value const& _input)
{
return Json::StyledWriter().write(_input);
}
std::string jsonPrettyPrint(Json::Value const& _input);

/// Serialise the JSON object (@a _input) without indentation
inline std::string jsonCompactPrint(Json::Value const& _input)
{
Json::FastWriter writer;
writer.omitEndingLineFeed();
return writer.write(_input);
}
std::string jsonCompactPrint(Json::Value const& _input);

/// Parse a JSON string (@a _input) with enabled strict-mode and writes resulting JSON object to (@a _json)
/// \param _input JSON input string
/// \param _json [out] resulting JSON object
/// \param _errs [out] Formatted error messages
/// \return \c true if the document was successfully parsed, \c false if an error occurred.
bool jsonParseStrict(std::string const& _input, Json::Value& _json, std::string* _errs = nullptr);

/// Parse a JSON string (@a _input) and writes resulting JSON object to (@a _json)
/// \param _input JSON input string
/// \param _json [out] resulting JSON object
/// \param _errs [out] Formatted error messages
/// \return \c true if the document was successfully parsed, \c false if an error occurred.
bool jsonParse(std::string const& _input, Json::Value& _json, std::string* _errs = nullptr);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Every use cases uses strict mode - do we want to keep this non-strict helper?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good question.. will we need to parse non-strict JSON in the future?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't think so, though it's small we can keep it.


}
16 changes: 8 additions & 8 deletions libsolc/libsolc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback
{
Json::Value contractInput = ret["contracts"][sourceName][contractName];
Json::Value contractOutput = Json::objectValue;
contractOutput["interface"] = dev::jsonCompactPrint(contractInput["abi"]);
contractOutput["interface"] = jsonCompactPrint(contractInput["abi"]);
contractOutput["metadata"] = contractInput["metadata"];
contractOutput["functionHashes"] = contractInput["evm"]["methodIdentifiers"];
contractOutput["gasEstimates"] = translateGasEstimates(contractInput["evm"]["gasEstimates"]);
Expand All @@ -219,7 +219,7 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback

try
{
return dev::jsonCompactPrint(output);
return jsonCompactPrint(output);
}
catch (...)
{
Expand All @@ -229,15 +229,15 @@ string compile(StringMap const& _sources, bool _optimize, CStyleReadFileCallback

string compileMulti(string const& _input, bool _optimize, CStyleReadFileCallback _readCallback = nullptr)
{
Json::Reader reader;
string errors;
Json::Value input;
if (!reader.parse(_input, input, false))
if (!jsonParseStrict(_input, input, &errors))
{
Json::Value errors(Json::arrayValue);
errors.append("Error parsing input JSON: " + reader.getFormattedErrorMessages());
Json::Value jsonErrors(Json::arrayValue);
jsonErrors.append("Error parsing input JSON: " + errors);
Json::Value output(Json::objectValue);
output["errors"] = errors;
return dev::jsonCompactPrint(output);
output["errors"] = jsonErrors;
return jsonCompactPrint(output);
}
else
{
Expand Down
7 changes: 3 additions & 4 deletions libsolidity/interface/StandardCompiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -554,12 +554,11 @@ Json::Value StandardCompiler::compile(Json::Value const& _input)
string StandardCompiler::compile(string const& _input)
{
Json::Value input;
Json::Reader reader;

string errors;
try
{
if (!reader.parse(_input, input, false))
return jsonCompactPrint(formatFatalError("JSONError", reader.getFormattedErrorMessages()));
if (!jsonParseStrict(_input, input, &errors))
return jsonCompactPrint(formatFatalError("JSONError", errors));
}
catch(...)
{
Expand Down
2 changes: 1 addition & 1 deletion test/Metadata.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ string bytecodeSansMetadata(string const& _bytecode)
bool isValidMetadata(string const& _metadata)
{
Json::Value metadata;
if (!Json::Reader().parse(_metadata, metadata, false))
if (!jsonParseStrict(_metadata, metadata))
return false;

if (
Expand Down
14 changes: 6 additions & 8 deletions test/RPCSession.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,7 @@

#include <libdevcore/CommonData.h>

#include <json/reader.h>
#include <json/writer.h>
#include <libdevcore/JSON.h>

#include <string>
#include <stdio.h>
Expand Down Expand Up @@ -216,7 +215,7 @@ string RPCSession::personal_newAccount(string const& _password)

void RPCSession::test_setChainParams(vector<string> const& _accounts)
{
static std::string const c_configString = R"(
static string const c_configString = R"(
{
"sealEngine": "NoProof",
"params": {
Expand Down Expand Up @@ -249,10 +248,10 @@ void RPCSession::test_setChainParams(vector<string> const& _accounts)
)";

Json::Value config;
BOOST_REQUIRE(Json::Reader().parse(c_configString, config));
BOOST_REQUIRE(jsonParseStrict(c_configString, config));
for (auto const& account: _accounts)
config["accounts"][account]["wei"] = "0x100000000000000000000000000000000000000000";
test_setChainParams(Json::FastWriter().write(config));
test_setChainParams(jsonCompactPrint(config));
}

void RPCSession::test_setChainParams(string const& _config)
Expand Down Expand Up @@ -328,7 +327,7 @@ Json::Value RPCSession::rpcCall(string const& _methodName, vector<string> const&
BOOST_TEST_MESSAGE("Reply: " + reply);

Json::Value result;
BOOST_REQUIRE(Json::Reader().parse(reply, result, false));
BOOST_REQUIRE(jsonParseStrict(reply, result));

if (result.isMember("error"))
{
Expand Down Expand Up @@ -371,6 +370,5 @@ string RPCSession::TransactionData::toJson() const
json["gasprice"] = gasPrice;
json["value"] = value;
json["data"] = data;
return Json::FastWriter().write(json);

return jsonCompactPrint(json);
}
6 changes: 3 additions & 3 deletions test/fuzzer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@
#include <libevmasm/ConstantOptimiser.h>
#include <libsolc/libsolc.h>

#include <json/json.h>
#include <libdevcore/JSON.h>

#include <boost/program_options.hpp>

Expand Down Expand Up @@ -101,7 +101,7 @@ void testStandardCompiler()
string input = readInput();
string outputString(compileStandard(input.c_str(), NULL));
Json::Value output;
if (!Json::Reader().parse(outputString, output))
if (!jsonParseStrict(outputString, output))
{
cout << "Compiler produced invalid JSON output." << endl;
abort();
Expand Down Expand Up @@ -129,7 +129,7 @@ void testCompiler(bool optimize)

string outputString(compileJSON(input.c_str(), optimize));
Json::Value outputJson;
if (!Json::Reader().parse(outputString, outputJson))
if (!jsonParseStrict(outputString, outputJson))
{
cout << "Compiler produced invalid JSON output." << endl;
abort();
Expand Down
Loading