Fix integer overflow in Writer::WriteString for long strings This fix is attributed to @afonsojanu Fixes #2348, and the same root cause reported separately in #2336. WriteString computes the stack reservation as 2 + length * 6 (or * 12 for the non-Unicode-target case), where length is a SizeType. With the default SizeType (unsigned, 32-bit), that multiplication overflows for strings around 716 million characters and up, so PutReserve ends up reserving far less space than the writer actually needs. Once writing continues past the undersized buffer, that's either a hard assertion failure in Stack::PushUnsafe in debug builds (exactly the crash reported in #2348), or plain memory corruption in release builds. Widening length to size_t before the multiplication fixes it: on 64-bit platforms the multiplication now happens at 64 bits and can't wrap around for any length that actually fits in a SizeType to begin with. Verified with a small standalone program writing an 800,000,000-character string through Writer<StringBuffer>: reliably hits the reported assertion on unmodified master, and completes correctly with the fix (produces a StringBuffer of the exact expected size). I didn't add this as an automated unit test in this PR, since a real repro needs close to a gigabyte of memory and I wasn't sure that's a good tradeoff for the test suite to run on every CI job — happy to add one if you'd rather have it. Ran the existing writer, prettywriter, stringbuffer, and document unit tests (63 cases) against the fix, all pass unchanged.
diff --git a/include/rapidjson/writer.h b/include/rapidjson/writer.h index 632e02c..89001bd 100644 --- a/include/rapidjson/writer.h +++ b/include/rapidjson/writer.h
@@ -395,9 +395,9 @@ }; if (TargetEncoding::supportUnicode) - PutReserve(*os_, 2 + length * 6); // "\uxxxx..." + PutReserve(*os_, 2 + static_cast<size_t>(length) * 6); // "\uxxxx..." else - PutReserve(*os_, 2 + length * 12); // "\uxxxx\uyyyy..." + PutReserve(*os_, 2 + static_cast<size_t>(length) * 12); // "\uxxxx\uyyyy..." PutUnsafe(*os_, '\"'); GenericStringStream<SourceEncoding> is(str);