forked from weaselab/weaseljson
Make parser reject state sticky after WeaselJson_REJECT
After the parser returns WeaselJson_REJECT once, subsequent calls to WeaselJsonParser_parse (including the final len==0 EOF call) must keep returning WeaselJson_REJECT instead of potentially reporting OK. - Add a `rejected` flag to Parser3. - Clear the flag in reset(). - Check the flag at the start of parse() and immediately return REJECT. - Set the flag whenever a continuation returns REJECT. Add a test covering the exact reproduction from issue #12.
This commit is contained in:
+15
-2
@@ -139,6 +139,7 @@ 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;
|
||||||
|
rejected = false;
|
||||||
utf8Codepoint = 0;
|
utf8Codepoint = 0;
|
||||||
utf16Surrogate = 0;
|
utf16Surrogate = 0;
|
||||||
minCodepoint = 0;
|
minCodepoint = 0;
|
||||||
@@ -161,6 +162,7 @@ struct Parser3 {
|
|||||||
NumDfa numDfa;
|
NumDfa numDfa;
|
||||||
Utf8Dfa strDfa;
|
Utf8Dfa strDfa;
|
||||||
bool inKey = false;
|
bool inKey = false;
|
||||||
|
bool rejected = false;
|
||||||
|
|
||||||
#ifndef HAS_MUSTTAIL
|
#ifndef HAS_MUSTTAIL
|
||||||
char *stashBufForTrampoline;
|
char *stashBufForTrampoline;
|
||||||
@@ -1062,18 +1064,29 @@ 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->rejected) [[unlikely]] {
|
||||||
|
return WeaselJson_REJECT;
|
||||||
|
}
|
||||||
|
|
||||||
#ifdef HAS_MUSTTAIL
|
#ifdef HAS_MUSTTAIL
|
||||||
// The continuation returns a value in 0..3 here (kBounce is only used by the
|
// The continuation returns a value in 0..3 here (kBounce is only used by the
|
||||||
// no-musttail trampoline below), so the conversion back to the enum is in
|
// no-musttail trampoline below), so the conversion back to the enum is in
|
||||||
// range.
|
// range.
|
||||||
return WeaselJsonStatus(
|
ContinuationStatus status =
|
||||||
symbolTables.continuations[top()](this, buf, buf + len));
|
symbolTables.continuations[top()](this, buf, buf + len);
|
||||||
|
if (status == WeaselJson_REJECT) {
|
||||||
|
this->rejected = true;
|
||||||
|
}
|
||||||
|
return WeaselJsonStatus(status);
|
||||||
#else
|
#else
|
||||||
this->stashBufForTrampoline = buf;
|
this->stashBufForTrampoline = buf;
|
||||||
ContinuationStatus result;
|
ContinuationStatus result;
|
||||||
while ((result = symbolTables.continuations[top()](
|
while ((result = symbolTables.continuations[top()](
|
||||||
this, stashBufForTrampoline, buf + len)) == kBounce)
|
this, stashBufForTrampoline, buf + len)) == kBounce)
|
||||||
;
|
;
|
||||||
|
if (result == WeaselJson_REJECT) {
|
||||||
|
this->rejected = true;
|
||||||
|
}
|
||||||
return WeaselJsonStatus(result);
|
return WeaselJsonStatus(result);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -202,6 +202,31 @@ TEST_CASE("parser3") {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TEST_CASE("rejected state is sticky") {
|
||||||
|
auto c = noopCallbacks();
|
||||||
|
auto *parser = WeaselJsonParser_create(1024, &c, nullptr, 0);
|
||||||
|
REQUIRE(parser != nullptr);
|
||||||
|
|
||||||
|
// Feed a valid prefix, then an invalid byte. The parser must reject.
|
||||||
|
std::string chunk1 = "1";
|
||||||
|
REQUIRE(WeaselJsonParser_parse(parser, chunk1.data(), chunk1.size()) ==
|
||||||
|
WeaselJson_AGAIN);
|
||||||
|
std::string chunk2 = "x";
|
||||||
|
REQUIRE(WeaselJsonParser_parse(parser, chunk2.data(), chunk2.size()) ==
|
||||||
|
WeaselJson_REJECT);
|
||||||
|
|
||||||
|
// After a reject, every later call must also reject, including the EOF
|
||||||
|
// finish call that would otherwise return OK.
|
||||||
|
REQUIRE(WeaselJsonParser_parse(parser, nullptr, 0) == WeaselJson_REJECT);
|
||||||
|
|
||||||
|
// Further data chunks must also stay rejected.
|
||||||
|
std::string chunk3 = " ";
|
||||||
|
REQUIRE(WeaselJsonParser_parse(parser, chunk3.data(), chunk3.size()) ==
|
||||||
|
WeaselJson_REJECT);
|
||||||
|
|
||||||
|
WeaselJsonParser_destroy(parser);
|
||||||
|
}
|
||||||
|
|
||||||
TEST_CASE("create rejects too-small stack") {
|
TEST_CASE("create rejects too-small stack") {
|
||||||
auto c = noopCallbacks();
|
auto c = noopCallbacks();
|
||||||
// The parser needs room for the bootstrap symbols pushed by reset(); a stack
|
// The parser needs room for the bootstrap symbols pushed by reset(); a stack
|
||||||
|
|||||||
Reference in New Issue
Block a user