Fix File stat-before-open crash risk, JSON string-quoting bug, and MString buffer overflow

- File: stat() only after a successful open() (previously ran first with
  its result ignored, feeding a missing file's garbage st_size into a
  realloc - could crash the whole APIServer on a request for a
  nonexistent static asset)
- JString::setString(): always quote+escape the value instead of going
  through set()'s literal-value guess, which misclassified any string
  starting with digits (e.g. a UUID) as a bare numeric literal and wrote
  it unquoted, corrupting later edits to the same JSON document
- MString::remove() (both overloads): fixed an off-by-one that read one
  byte past the buffer on a completely full string (found via ASan under
  concurrent load)
- CGIFormData: added fields() so callers can iterate every parsed field
  without knowing names in advance (used to merge POST body into
  jet::Global::variables the same way query-string params already are)
This commit is contained in:
Brad Arant committed 2026-09-03 05:14:24 +00:00
1 parent d7057ebb00
commit 78c45d378c
6 files changed
+79 -8

No files matched your search

+13 -2
View File
@@ -266,15 +266,26 @@ namespace coreutils {
}
void MString::remove(int length) {
// Shifts the tail (everything after the removed range) down to close
// the gap. The loop must stop once ix + length reaches the end of the
// valid data - reading cursor[ix + length] past that point is a
// heap-buffer-overflow (confirmed via AddressSanitizer under
// concurrent APIServer load: a completely full MString hit exactly
// this on the final iteration, reading 1 byte past the allocation).
// The old condition `ix < len` let the loop run `length` iterations
// too far.
int len = (data + this->length - cursor);
for (int ix = 0; ix < len; ix++)
for (int ix = 0; ix < len - length; ix++)
cursor[ix] = cursor[ix + length];
setSize(this->length - length);
onChange();
}
void MString::remove(int offset, int length) {
for (int ix = offset; ix < this->length; ix++)
// Same off-by-one as the single-argument overload above - the loop
// must stop once ix + length reaches this->length, not run all the
// way to this->length itself.
for (int ix = offset; ix < this->length - length; ix++)
getData()[ix] = getData()[ix + length];
setSize(this->length - length);
onChange();