diff --git a/doc/release-notes.md b/doc/release-notes.md --- a/doc/release-notes.md +++ b/doc/release-notes.md @@ -4,3 +4,4 @@ This release includes the following features and fixes: - Removed deprecated `getinfo` RPC. + - Update univalue to 1.0.5 diff --git a/src/univalue/Makefile.am b/src/univalue/Makefile.am --- a/src/univalue/Makefile.am +++ b/src/univalue/Makefile.am @@ -95,6 +95,7 @@ $(TEST_DATA_DIR)/fail41.json \ $(TEST_DATA_DIR)/fail42.json \ $(TEST_DATA_DIR)/fail44.json \ + $(TEST_DATA_DIR)/fail45.json \ $(TEST_DATA_DIR)/fail3.json \ $(TEST_DATA_DIR)/fail4.json \ $(TEST_DATA_DIR)/fail5.json \ @@ -105,6 +106,7 @@ $(TEST_DATA_DIR)/pass1.json \ $(TEST_DATA_DIR)/pass2.json \ $(TEST_DATA_DIR)/pass3.json \ + $(TEST_DATA_DIR)/pass4.json \ $(TEST_DATA_DIR)/round1.json \ $(TEST_DATA_DIR)/round2.json \ $(TEST_DATA_DIR)/round3.json \ diff --git a/src/univalue/README.md b/src/univalue/README.md --- a/src/univalue/README.md +++ b/src/univalue/README.md @@ -12,6 +12,12 @@ This class is aligned with the JSON standard, [RFC 7159](https://tools.ietf.org/html/rfc7159.html). +## Motivation + +UniValue is a reaction to json_spirit, seeking to minimize template +and memory use, providing a straightforward RAII class compatible with +link-time optimization and embedded uses. + ## Installation This project is a standard GNU @@ -25,8 +31,3 @@ $ make ``` -## Design - -UniValue provides a single dynamic RAII C++ object class, -and minimizes template use (contra json_spirit). - diff --git a/src/univalue/configure.ac b/src/univalue/configure.ac --- a/src/univalue/configure.ac +++ b/src/univalue/configure.ac @@ -14,7 +14,7 @@ m4_define([libunivalue_version], [libunivalue_major_version().libunivalue_minor_version().libunivalue_micro_version()libunivalue_extraversion()]) -AC_INIT([univalue], [1.0.4], +AC_INIT([univalue], [1.0.5], [http://github.com/jgarzik/univalue/]) dnl make the compilation flags quiet unless V=1 is used diff --git a/src/univalue/include/univalue.h b/src/univalue/include/univalue.h --- a/src/univalue/include/univalue.h +++ b/src/univalue/include/univalue.h @@ -14,7 +14,7 @@ #include #include -#include // .get_int64() +#include // std::pair class UniValue { public: @@ -176,9 +176,76 @@ const UniValue& get_array() const; enum VType type() const { return getType(); } + bool push_back(std::pair pear) { + return pushKV(pear.first, pear.second); + } friend const UniValue& find_value( const UniValue& obj, const std::string& name); }; +// +// The following were added for compatibility with json_spirit. +// Most duplicate other methods, and should be removed. +// +static inline std::pair Pair(const char *cKey, const char *cVal) +{ + std::string key(cKey); + UniValue uVal(cVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, std::string strVal) +{ + std::string key(cKey); + UniValue uVal(strVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, uint64_t u64Val) +{ + std::string key(cKey); + UniValue uVal(u64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int64_t i64Val) +{ + std::string key(cKey); + UniValue uVal(i64Val); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, bool iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, int iVal) +{ + std::string key(cKey); + UniValue uVal(iVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, double dVal) +{ + std::string key(cKey); + UniValue uVal(dVal); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(const char *cKey, const UniValue& uVal) +{ + std::string key(cKey); + return std::make_pair(key, uVal); +} + +static inline std::pair Pair(std::string key, const UniValue& uVal) +{ + return std::make_pair(key, uVal); +} + enum jtokentype { JTOK_ERR = -1, JTOK_NONE = 0, // eof diff --git a/src/univalue/lib/univalue_get.cpp b/src/univalue/lib/univalue_get.cpp --- a/src/univalue/lib/univalue_get.cpp +++ b/src/univalue/lib/univalue_get.cpp @@ -11,6 +11,7 @@ #include #include #include +#include #include "univalue.h" diff --git a/src/univalue/lib/univalue_read.cpp b/src/univalue/lib/univalue_read.cpp --- a/src/univalue/lib/univalue_read.cpp +++ b/src/univalue/lib/univalue_read.cpp @@ -8,6 +8,14 @@ #include "univalue.h" #include "univalue_utffilter.h" +/* + * According to stackexchange, the original json test suite wanted + * to limit depth to 22. Widely-deployed PHP bails at depth 512, + * so we will follow PHP's lead, which should be more than sufficient + * (further stackexchange comments indicate depth > 32 rarely occurs). + */ +static const size_t MAX_JSON_DEPTH = 512; + static bool json_isdigit(int ch) { return ((ch >= '0') && (ch <= '9')); @@ -265,7 +273,7 @@ tok = getJsonToken(tokenVal, consumed, raw, end); if (tok == JTOK_NONE || tok == JTOK_ERR) - return false; + goto return_fail; raw += consumed; bool isValueOpen = jsonTokenIsValue(tok) || @@ -273,33 +281,33 @@ if (expect(VALUE)) { if (!isValueOpen) - return false; + goto return_fail; clearExpect(VALUE); } else if (expect(ARR_VALUE)) { bool isArrValue = isValueOpen || (tok == JTOK_ARR_CLOSE); if (!isArrValue) - return false; + goto return_fail; clearExpect(ARR_VALUE); } else if (expect(OBJ_NAME)) { bool isObjName = (tok == JTOK_OBJ_CLOSE || tok == JTOK_STRING); if (!isObjName) - return false; + goto return_fail; } else if (expect(COLON)) { if (tok != JTOK_COLON) - return false; + goto return_fail; clearExpect(COLON); } else if (!expect(COLON) && (tok == JTOK_COLON)) { - return false; + goto return_fail; } if (expect(NOT_VALUE)) { if (isValueOpen) - return false; + goto return_fail; clearExpect(NOT_VALUE); } @@ -323,6 +331,9 @@ stack.push_back(newTop); } + if (stack.size() > MAX_JSON_DEPTH) + goto return_fail; + if (utyp == VOBJ) setExpect(OBJ_NAME); else @@ -333,12 +344,12 @@ case JTOK_OBJ_CLOSE: case JTOK_ARR_CLOSE: { if (!stack.size() || (last_tok == JTOK_COMMA)) - return false; + goto return_fail; VType utyp = (tok == JTOK_OBJ_CLOSE ? VOBJ : VARR); UniValue *top = stack.back(); if (utyp != top->getType()) - return false; + goto return_fail; stack.pop_back(); clearExpect(OBJ_NAME); @@ -348,11 +359,11 @@ case JTOK_COLON: { if (!stack.size()) - return false; + goto return_fail; UniValue *top = stack.back(); if (top->getType() != VOBJ) - return false; + goto return_fail; setExpect(VALUE); break; @@ -361,7 +372,7 @@ case JTOK_COMMA: { if (!stack.size() || (last_tok == JTOK_COMMA) || (last_tok == JTOK_ARR_OPEN)) - return false; + goto return_fail; UniValue *top = stack.back(); if (top->getType() == VOBJ) @@ -435,15 +446,19 @@ } default: - return false; + goto return_fail; } } while (!stack.empty ()); /* Check that nothing follows the initial construct (parsed above). */ tok = getJsonToken(tokenVal, consumed, raw, end); if (tok != JTOK_NONE) - return false; + goto return_fail; return true; + +return_fail: + clear(); + return false; } diff --git a/src/univalue/lib/univalue_write.cpp b/src/univalue/lib/univalue_write.cpp --- a/src/univalue/lib/univalue_write.cpp +++ b/src/univalue/lib/univalue_write.cpp @@ -3,7 +3,6 @@ // file COPYING or https://opensource.org/licenses/mit-license.php. #include -#include #include #include "univalue.h" #include "univalue_escapes.h" diff --git a/src/univalue/test/fail45.json b/src/univalue/test/fail45.json new file mode 100644 --- /dev/null +++ b/src/univalue/test/fail45.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] diff --git a/src/univalue/test/object.cpp b/src/univalue/test/object.cpp --- a/src/univalue/test/object.cpp +++ b/src/univalue/test/object.cpp @@ -19,9 +19,10 @@ #define BOOST_CHECK_THROW(stmt, excMatch) { \ try { \ (stmt); \ + assert(0 && "No exception caught"); \ } catch (excMatch & e) { \ } catch (...) { \ - assert(0); \ + assert(0 && "Wrong exception caught"); \ } \ } #define BOOST_CHECK_NO_THROW(stmt) { \ diff --git a/src/univalue/test/pass4.json b/src/univalue/test/pass4.json new file mode 100644 --- /dev/null +++ b/src/univalue/test/pass4.json @@ -0,0 +1 @@ +[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[[]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]] diff --git a/src/univalue/test/unitester.cpp b/src/univalue/test/unitester.cpp --- a/src/univalue/test/unitester.cpp +++ b/src/univalue/test/unitester.cpp @@ -114,6 +114,7 @@ "fail41.json", // invalid unicode: unfinished UTF-8 "fail42.json", // valid json with garbage following a nul byte "fail44.json", // unterminated string + "fail45.json", // nested beyond max depth "fail3.json", "fail4.json", // extra comma "fail5.json", @@ -124,6 +125,7 @@ "pass1.json", "pass2.json", "pass3.json", + "pass4.json", "round1.json", // round-trip test "round2.json", // unicode "round3.json", // bare string