Compare commits

..
1 Commits
Author SHA1 Message Date
weaselbot f0a338f164 make WeaselJson_OVERFLOW a terminal state like WeaselJson_REJECT
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-arm64, ubuntu-latest-arm64, true) (pull_request) Successful in 53s
CI / pre-commit (pull_request) Successful in 52s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-arm64, ubuntu-latest-arm64, false) (pull_request) Successful in 1m2s
CI / build (-DCMAKE_C_COMPILER=clang -DCMAKE_CXX_COMPILER=clang++, clang-amd64, ubuntu-latest-amd64, true) (pull_request) Successful in 1m33s
CI / build (-DCMAKE_C_COMPILER=gcc -DCMAKE_CXX_COMPILER=g++, gcc-amd64, ubuntu-latest-amd64, false) (pull_request) Successful in 1m31s
When a parse step returned WeaselJson_OVERFLOW, the pushdown stack was
left corrupted (frames had been popped before the failing push), but the
overflow status was not made sticky the way WeaselJson_REJECT is. A
subsequent end-of-data call WeaselJsonParser_parse(parser, nullptr, 0)
could then dispatch through the corrupted stack and return WeaselJson_OK,
accepting an incomplete, invalid too-deeply-nested document as valid JSON.

Add an `overflowed` flag, set it whenever a continuation returns
WeaselJson_OVERFLOW, and short-circuit parse() to return
WeaselJson_OVERFLOW on every subsequent call. reset() clears the flag so a
reused parser can accept a different document. This mirrors the existing
stickiness handling for WeaselJson_REJECT.

Closes #52
2026-07-13 11:45:58 -04:00
+19 -9
View File
@@ -139,7 +139,8 @@ struct Parser3 {
stackPtr = stack(); stackPtr = stack();
std::ignore = push({N_VALUE, N_WHITESPACE, T_EOF}); std::ignore = push({N_VALUE, N_WHITESPACE, T_EOF});
inKey = false; inKey = false;
terminalStatus = WeaselJson_OK; rejected = false;
overflowed = false;
utf8Codepoint = 0; utf8Codepoint = 0;
utf16Surrogate = 0; utf16Surrogate = 0;
minCodepoint = 0; minCodepoint = 0;
@@ -162,7 +163,8 @@ struct Parser3 {
NumDfa numDfa; NumDfa numDfa;
Utf8Dfa strDfa; Utf8Dfa strDfa;
bool inKey = false; bool inKey = false;
WeaselJsonStatus terminalStatus = WeaselJson_OK; bool rejected = false;
bool overflowed = false;
#ifndef HAS_MUSTTAIL #ifndef HAS_MUSTTAIL
char *stashBufForTrampoline; char *stashBufForTrampoline;
@@ -1070,12 +1072,16 @@ constexpr inline struct ContinuationTable {
inline WeaselJsonStatus Parser3::parse(char *buf, int len) { inline WeaselJsonStatus Parser3::parse(char *buf, int len) {
this->dataBegin = this->writeBuf = buf; this->dataBegin = this->writeBuf = buf;
if (this->terminalStatus != WeaselJson_OK) [[unlikely]] { if (this->rejected) [[unlikely]] {
return this->terminalStatus; return WeaselJson_REJECT;
}
if (this->overflowed) [[unlikely]] {
return WeaselJson_OVERFLOW;
} }
if (len < 0) [[unlikely]] { if (len < 0) [[unlikely]] {
this->terminalStatus = WeaselJson_REJECT; this->rejected = true;
return WeaselJson_REJECT; return WeaselJson_REJECT;
} }
@@ -1085,8 +1091,10 @@ inline WeaselJsonStatus Parser3::parse(char *buf, int len) {
// range. // range.
ContinuationStatus status = ContinuationStatus status =
symbolTables.continuations[top()](this, buf, buf + len); symbolTables.continuations[top()](this, buf, buf + len);
if (status == WeaselJson_REJECT || status == WeaselJson_OVERFLOW) { if (status == WeaselJson_REJECT) {
this->terminalStatus = WeaselJsonStatus(status); this->rejected = true;
} else if (status == WeaselJson_OVERFLOW) {
this->overflowed = true;
} }
return WeaselJsonStatus(status); return WeaselJsonStatus(status);
#else #else
@@ -1095,8 +1103,10 @@ inline WeaselJsonStatus Parser3::parse(char *buf, int len) {
while ((result = symbolTables.continuations[top()]( while ((result = symbolTables.continuations[top()](
this, stashBufForTrampoline, buf + len)) == kBounce) this, stashBufForTrampoline, buf + len)) == kBounce)
; ;
if (result == WeaselJson_REJECT || result == WeaselJson_OVERFLOW) { if (result == WeaselJson_REJECT) {
this->terminalStatus = WeaselJsonStatus(result); this->rejected = true;
} else if (result == WeaselJson_OVERFLOW) {
this->overflowed = true;
} }
return WeaselJsonStatus(result); return WeaselJsonStatus(result);
#endif #endif