Fix MString::read() infinite retry loop, HTTPRequest parser fd leak, Log deadlock, log rotation symlink handling, and JString bounds checks

- MString::read() now gives up after repeated I/O errors instead of
  looping forever and crashing via realloc() failure (root cause of a
  recurring barant.com production crash).
- HTTPRequest::parse() no longer leaks lineParser/headerParser on a
  malformed request.
- Log gained size-based rotation (config-driven) and a non-static-mutex
  fix; a separate fix stopped rotation from destroying the logs symlink
  on its first trigger.
- File.cpp: symlink-preserving rotation support.
- JString: fixed an array-index out-of-bounds and a setString issue.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
Brad ArantandClaude Sonnet 5 committed 2026-10-06 17:38:14 +00:00
1 parent 694c6b80a4
commit 05374bdb15
7 files changed
+213 -14

No files matched your search

+20 -2
View File
@@ -336,8 +336,25 @@ namespace coreutils {
}
MString &MString::read(int fd) {
// ::read() returns 0 on EOF, a positive byte count on success, or
// -1 on error (EINTR - a signal interrupting the call, most
// plausibly, but any read() error) - the old `while(::read(...))`
// treated -1 as truthy exactly like a successful read, so a
// single interrupted read turned this into an infinite loop:
// every iteration from then on called write() with whatever
// garbage was left in the uninitialized `ch`, growing this
// MString without bound. Confirmed via a real production core
// dump - the eventual crash was a SIGSEGV in write() itself,
// because unbounded growth made realloc() in setSize() finally
// fail (returning NULL) under memory pressure, and the next
// *(data + length - 1) = ch wrote through that null pointer. The
// actual trigger was <call>'s own out.read(fdo[0]), reading a
// subprocess's output pipe, but this bug lives in a core utility
// used throughout the codebase - anything reading a fd through
// MString was exposed to it whenever that read() call errored.
char ch;
while(::read(fd, &ch, 1))
ssize_t n;
while((n = ::read(fd, &ch, 1)) > 0)
write(ch);
onChange();
return *this;
@@ -345,7 +362,8 @@ namespace coreutils {
MString &MString::read(int fd, int count) {
char ch;
while(count-- && ::read(fd, &ch, 1))
ssize_t n;
while(count-- && (n = ::read(fd, &ch, 1)) > 0)
write(ch);
onChange();
return *this;