Was an unchecked std::vector index (return list[index];). Any
malformed/short line - a port scanner, a bot probing the port, or any
client sending fewer colon-delimited fields than a given handler
indexes via request[N] - reached this with no length check anywhere
upstream, across every server built on this class. Depending on build
flags that was either undefined behavior or, confirmed live (a real
crash log from Zephora's game server), a hard process abort via
libstdc++'s own vector bounds assertion:
Assertion '__n < this->size()' failed.
Throwing instead lets this be caught: every caller that dispatches a
parsed request already wraps that dispatch in a try/catch (see
CommandList::processRequest()), so a single malformed line is now
cleanly rejected instead of taking down the entire server process for
every connected player.
operator< computed end2 as valuex.getData() + valuex.getLength() - mixing
an absolute pointer (getData(), the buffer start) with a cursor-relative
length (getLength(), remaining-from-cursor). For any ZString with a
non-zero cursor offset this produces an end pointer short of the true
buffer end by exactly the amount already consumed, truncating the
comparison early. Fixed to use valuex.data + valuex.length (the true
end), matching how end1 was already computed for *this. operator<=,
>=, and > were separately broken (flagged by the codes own TODO
comment) - they compared via strncmp from data (ignoring cursor
entirely), inconsistent with operator< and with each other. Replaced
all three with derivations from the now-correct operator< (a <= b is
!(b < a), etc.) - guarantees trichotomy by construction instead of
three independently-written comparison loops.
substring(start, len): when the requested length overran the buffer,
computed newlen as endChar - end (the overrun amount) instead of
end - startChar (the actual remaining valid length) - backwards, and
stored into a char (max 127), silently wrapping for longer strings.
Fixed the formula and widened to size_t.
trimCRLF(): read *(data + length - 1) unconditionally, including when
length is already 0 - one byte before the buffer on an empty string.
Guarded both checks on length > 0.
Verified: full local compile (identical result to before - 13/20 clean,
same pre-existing StreamReader.h-blocked failures, nothing new broken);
a dedicated runtime test exercising all three fixes plus a trichotomy
check across multiple cursor offsets - all 13 assertions pass. Test
file not included in this commit.