From 43e3c9904f589c16dea835dcb9272770be84486f Mon Sep 17 00:00:00 2001 From: Weaselbot Date: Mon, 22 Jun 2026 02:26:30 -0400 Subject: [PATCH] Reject negative lengths in WeaselJsonParser_parse `Parser3::parse` previously formed `buf + len` immediately, so passing a negative `len` from the C API caused undefined pointer arithmetic. Add an explicit `len < 0` check that returns `WeaselJson_REJECT` (and makes the rejected state sticky) before any `buf + len` computation. Also document the non-negative length precondition in the public header and add a regression test. Closes #24 --- include/weaseljson.h | 3 ++- src/parser3.h | 5 +++++ src/test.cpp | 14 ++++++++++++++ 3 files changed, 21 insertions(+), 1 deletion(-) diff --git a/include/weaseljson.h b/include/weaseljson.h index c2e0c8b..4a42681 100644 --- a/include/weaseljson.h +++ b/include/weaseljson.h @@ -64,7 +64,8 @@ void WeaselJsonParser_destroy(WeaselJsonParser *parser); /** Incrementally parse `len` more bytes starting at `buf`. `buf` may be * modified. Call with `len` 0 to indicate end of data. `buf` may be null if - * `len` is 0 */ + * `len` is 0. `len` must not be negative; a negative length is treated as a + * rejected input. */ WeaselJsonStatus WeaselJsonParser_parse(WeaselJsonParser *parser, char *buf, int len); diff --git a/src/parser3.h b/src/parser3.h index 348f69b..e1c9a42 100644 --- a/src/parser3.h +++ b/src/parser3.h @@ -1068,6 +1068,11 @@ inline WeaselJsonStatus Parser3::parse(char *buf, int len) { return WeaselJson_REJECT; } + if (len < 0) [[unlikely]] { + this->rejected = true; + return WeaselJson_REJECT; + } + #ifdef HAS_MUSTTAIL // 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 diff --git a/src/test.cpp b/src/test.cpp index 4723341..eec6669 100644 --- a/src/test.cpp +++ b/src/test.cpp @@ -246,6 +246,20 @@ TEST_CASE("create rejects too-small stack") { WeaselJsonParser_destroy(parser); } +TEST_CASE("parse rejects negative length") { + auto c = noopCallbacks(); + auto *parser = WeaselJsonParser_create(1024, &c, nullptr, 0); + REQUIRE(parser != nullptr); + + // A negative length must not cause pointer arithmetic UB. It should be + // rejected, and the rejected state should remain sticky. + char buf[10] = "hello"; + REQUIRE(WeaselJsonParser_parse(parser, buf, -1) == WeaselJson_REJECT); + REQUIRE(WeaselJsonParser_parse(parser, nullptr, 0) == WeaselJson_REJECT); + + WeaselJsonParser_destroy(parser); +} + TEST_CASE("streaming") { testStreaming(json); } TEST_CASE("reset clears inKey and transient state") {