From e938122b7ba8723c8cab6de78e8a9b39ad188589 Mon Sep 17 00:00:00 2001 From: Daniel Kraft Date: Thu, 20 Aug 2015 12:48:43 +0200 Subject: [PATCH] Stop parsing JSON after first finished construct. Fix https://github.com/bitcoin/bitcoin/issues/6558. In particular, stop parsing JSON after the first object or array is finished. Check that no other garbage follows, and fail the parser if it does. --- src/test/univalue_tests.cpp | 15 +++++++++++++++ src/univalue/univalue_read.cpp | 14 ++++++++------ 2 files changed, 23 insertions(+), 6 deletions(-) diff --git a/src/test/univalue_tests.cpp b/src/test/univalue_tests.cpp index 67cb9b962..ee31c0955 100644 --- a/src/test/univalue_tests.cpp +++ b/src/test/univalue_tests.cpp @@ -314,6 +314,21 @@ BOOST_AUTO_TEST_CASE(univalue_readwrite) BOOST_CHECK(obj["key3"].isObject()); BOOST_CHECK_EQUAL(strJson1, v.write()); + + /* Check for (correctly reporting) a parsing error if the initial + JSON construct is followed by more stuff. Note that whitespace + is, of course, exempt. */ + + BOOST_CHECK(v.read(" {}\n ")); + BOOST_CHECK(v.isObject()); + BOOST_CHECK(v.read(" []\n ")); + BOOST_CHECK(v.isArray()); + + BOOST_CHECK(!v.read("@{}")); + BOOST_CHECK(!v.read("{} garbage")); + BOOST_CHECK(!v.read("[]{}")); + BOOST_CHECK(!v.read("{}[]")); + BOOST_CHECK(!v.read("{} 42")); } BOOST_AUTO_TEST_SUITE_END() diff --git a/src/univalue/univalue_read.cpp b/src/univalue/univalue_read.cpp index 261771811..64591234c 100644 --- a/src/univalue/univalue_read.cpp +++ b/src/univalue/univalue_read.cpp @@ -244,16 +244,16 @@ bool UniValue::read(const char *raw) bool expectColon = false; vector stack; + string tokenVal; + unsigned int consumed; enum jtokentype tok = JTOK_NONE; enum jtokentype last_tok = JTOK_NONE; - while (1) { + do { last_tok = tok; - string tokenVal; - unsigned int consumed; tok = getJsonToken(tokenVal, consumed, raw); if (tok == JTOK_NONE || tok == JTOK_ERR) - break; + return false; raw += consumed; switch (tok) { @@ -377,9 +377,11 @@ bool UniValue::read(const char *raw) default: return false; } - } + } while (!stack.empty ()); - if (stack.size() != 0) + /* Check that nothing follows the initial construct (parsed above). */ + tok = getJsonToken(tokenVal, consumed, raw); + if (tok != JTOK_NONE) return false; return true;