When a scalar value (number, and theoretically string) ends exactly at a chunk boundary, the parser flushes it with done=false in that chunk. The next call with len==0 (EOF) then issues a final done=true flush to signal completion. At EOF, Parser3::parse sets this->dataBegin = this->writeBuf = buf, and because buf is null for an EOF call, both pointers become null. The final flush computes len = buf - dataBegin, i.e. nullptr - nullptr, which is undefined behavior in C++.
Affected code:
src/parser3.hParser3::parse (around line 1030) always resets the write window at the start of every call:
autoc=noopCallbacks();auto*parser=WeaselJsonParser_create(1024,&c,nullptr,0);std::stringchunk="123";WeaselJsonParser_parse(parser,chunk.data(),chunk.size());// flushes "123" with done=false, returns AGAIN
WeaselJsonParser_parse(parser,nullptr,0);// EOF: flushNumber(true, nullptr) computes nullptr - nullptr
WeaselJsonParser_destroy(parser);
The same pointer subtraction is reached for strings if a string's content is flushed at a chunk boundary and the subsequent EOF path somehow reaches flushString, although the most common trigger is the number path shown above.
Expected behavior: the parser should not invoke undefined behavior when finalizing a scalar at EOF. It can either skip the final zero-length flush when dataBegin is null, or explicitly compute len = 0 without pointer subtraction.
When a scalar value (number, and theoretically string) ends exactly at a chunk boundary, the parser flushes it with `done=false` in that chunk. The next call with `len==0` (EOF) then issues a final `done=true` flush to signal completion. At EOF, `Parser3::parse` sets `this->dataBegin = this->writeBuf = buf`, and because `buf` is null for an EOF call, both pointers become null. The final flush computes `len = buf - dataBegin`, i.e. `nullptr - nullptr`, which is undefined behavior in C++.
Affected code:
- `src/parser3.h` `Parser3::parse` (around line 1030) always resets the write window at the start of every call:
```cpp
inline WeaselJsonStatus Parser3::parse(char *buf, int len) {
this->dataBegin = this->writeBuf = buf;
...
```
- `src/parser3.h` `Parser3::flushNumber` and `Parser3::flushString` compute `len` by subtracting `dataBegin` from `buf`:
```cpp
void flushNumber(bool done, char *buf) {
int len = buf - dataBegin;
...
callbacks->on_number_data(userdata, dataBegin, len, done);
}
void flushString(bool done, char *buf) {
int len;
if (!(flags & WeaselJsonRaw)) {
len = writeBuf - dataBegin;
} else {
len = buf - dataBegin;
}
...
callbacks->on_string_data(userdata, dataBegin, len, done);
}
```
Concrete reproduction for numbers:
```cpp
auto c = noopCallbacks();
auto *parser = WeaselJsonParser_create(1024, &c, nullptr, 0);
std::string chunk = "123";
WeaselJsonParser_parse(parser, chunk.data(), chunk.size()); // flushes "123" with done=false, returns AGAIN
WeaselJsonParser_parse(parser, nullptr, 0); // EOF: flushNumber(true, nullptr) computes nullptr - nullptr
WeaselJsonParser_destroy(parser);
```
The same pointer subtraction is reached for strings if a string's content is flushed at a chunk boundary and the subsequent EOF path somehow reaches `flushString`, although the most common trigger is the number path shown above.
Expected behavior: the parser should not invoke undefined behavior when finalizing a scalar at EOF. It can either skip the final zero-length flush when `dataBegin` is null, or explicitly compute `len = 0` without pointer subtraction.
weaselbot
was assigned by andrew2026-06-29 17:09:49 +00:00
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
When a scalar value (number, and theoretically string) ends exactly at a chunk boundary, the parser flushes it with
done=falsein that chunk. The next call withlen==0(EOF) then issues a finaldone=trueflush to signal completion. At EOF,Parser3::parsesetsthis->dataBegin = this->writeBuf = buf, and becausebufis null for an EOF call, both pointers become null. The final flush computeslen = buf - dataBegin, i.e.nullptr - nullptr, which is undefined behavior in C++.Affected code:
src/parser3.hParser3::parse(around line 1030) always resets the write window at the start of every call:src/parser3.hParser3::flushNumberandParser3::flushStringcomputelenby subtractingdataBeginfrombuf:Concrete reproduction for numbers:
The same pointer subtraction is reached for strings if a string's content is flushed at a chunk boundary and the subsequent EOF path somehow reaches
flushString, although the most common trigger is the number path shown above.Expected behavior: the parser should not invoke undefined behavior when finalizing a scalar at EOF. It can either skip the final zero-length flush when
dataBeginis null, or explicitly computelen = 0without pointer subtraction.It's not actually UB