From 062b93de6599265fe4785494666988516561ab6a Mon Sep 17 00:00:00 2001 From: Max Kellermann Date: Mon, 21 Nov 2022 14:53:00 +0100 Subject: [PATCH] basic_parser: make sentinel() return a unique pointer Right now, sentinel() casts the `basic_parser` pointer (`this`) to `const char *`, but that pointer is not unique if the input buffer happens to be placed right before the `basic_parser_impl` instance - the end of that buffer then has the same address as `basic_parser`. Example code: ``` struct { char buffer[8]{"{\"12345\""}; boost::json::stream_parser p; } s; s.p.write(s.buffer, sizeof(s.buffer)); s.p.write(":0}", 3); ``` This stops parsing at the end of the buffer, and then the `incomplete()` check in `parse_string()` will return true; the second `write()` call will crash with assertion failure: > boost/json/basic_parser_impl.hpp:1016: const char* boost::json::basic_parser::parse_unescaped(const char*, std::integral_constant, std::integral_constant, bool) [with bool StackEmpty_ = true; bool IsKey_ = true; Handler = boost::json::detail::handler]: Assertion `*cs == '\x22'' failed. This changes `sentinel()` by adding 1 to guaranteed that the sentinel pointer is unique even if the input buffers borders on this object. --- include/boost/json/basic_parser_impl.hpp | 4 +++- test/stream_parser.cpp | 15 +++++++++++++++ 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/include/boost/json/basic_parser_impl.hpp b/include/boost/json/basic_parser_impl.hpp index 7ab6f1355..fd415e09f 100644 --- a/include/boost/json/basic_parser_impl.hpp +++ b/include/boost/json/basic_parser_impl.hpp @@ -217,8 +217,10 @@ const char* basic_parser:: sentinel() { + // the "+1" ensures that the returned pointer is unique even if + // the given input buffer borders on this object return reinterpret_cast< - const char*>(this); + const char*>(this) + 1; } template diff --git a/test/stream_parser.cpp b/test/stream_parser.cpp index 7c92960d9..095f06683 100644 --- a/test/stream_parser.cpp +++ b/test/stream_parser.cpp @@ -17,6 +17,7 @@ #include #include +#include #include "parse-vectors.hpp" #include "test.hpp" @@ -1253,6 +1254,19 @@ R"xx({ BOOST_TEST(serialize(t.jv) == "[]"); } + // https://github.com/boostorg/json/pull/814 + void + testSentinelOverlap() + { + struct { + char buffer[8]; + boost::json::stream_parser p; + } s; + memcpy(s.buffer, "{\"12345\"", 8); + s.p.write(s.buffer, sizeof(s.buffer)); + s.p.write(":0}", 3); + } + //------------------------------------------------------ void @@ -1276,6 +1290,7 @@ R"xx({ testDupeKeys(); testIssue15(); testIssue45(); + testSentinelOverlap(); } };