Fix use-after-free in Reader::parse(std::istream&) (#1665)
The istream overload stored the document in a local String then
passed raw pointers into it to parse(const char*, const char*),
which kept those pointers in begin_/end_. After parse() returned
the local String was destroyed, leaving begin_/end_ dangling.
Any subsequent call to getFormattedErrorMessages() would then
read freed memory.
Fix by reading the stream into the member document_ instead, matching
the behavior of parse(const std::string&).
Also document the lifetime requirement on parse(const char*, const
char*): the caller's buffer must outlive the Reader if error-reporting
methods are used after parsing.
Fixes #1623
diff --git a/include/json/reader.h b/include/json/reader.h
index d745378..7aa2271 100644
--- a/include/json/reader.h
+++ b/include/json/reader.h
@@ -81,7 +81,10 @@
* document.
*
* \param beginDoc Pointer on the beginning of the UTF-8 encoded
- * string of the document to read.
+ * string of the document to read. The pointed-to
+ * buffer must outlive this Reader if error
+ * methods (e.g. getFormattedErrorMessages()) are
+ * called after parse() returns.
* \param endDoc Pointer on the end of the UTF-8 encoded string
* of the document to read. Must be >= beginDoc.
* \param[out] root Contains the root value of the document if it
diff --git a/src/lib_json/json_reader.cpp b/src/lib_json/json_reader.cpp
index 3faa202..83743f7 100644
--- a/src/lib_json/json_reader.cpp
+++ b/src/lib_json/json_reader.cpp
@@ -88,15 +88,10 @@
}
bool Reader::parse(std::istream& is, Value& root, bool collectComments) {
- // std::istream_iterator<char> begin(is);
- // std::istream_iterator<char> end;
- // Those would allow streamed input from a file, if parse() were a
- // template function.
-
- // Since String is reference-counted, this at least does not
- // create an extra copy.
- String doc(std::istreambuf_iterator<char>(is), {});
- return parse(doc.data(), doc.data() + doc.size(), root, collectComments);
+ document_.assign(std::istreambuf_iterator<char>(is),
+ std::istreambuf_iterator<char>());
+ return parse(document_.data(), document_.data() + document_.size(), root,
+ collectComments);
}
bool Reader::parse(const char* beginDoc, const char* endDoc, Value& root,