Client: lua
The binary, compact and JSON protocols refused only a negative list, set or
map size, and the generated code reads one element per declared element.
Lua has no MaxMessageSize that would bound the count otherwise, so the new
limit gets a finite default instead of the "no limit of its own" default
THRIFT-6291 gives MaxContainerSize.
- TProtocol.lua: DEFAULT_MAX_CONTAINER_SIZE = 16384000, the value of the
string and frame size limits, and TProtocolBase:checkContainerSize().
maxContainerSize on a protocol instance overrides the default; zero or
less switches the limit off.
- readListBegin, readSetBegin and readMapBegin of TBinaryProtocol,
TCompactProtocol and TJSONProtocol call it before any element is read.
- doc/specs/thrift-tconfiguration.md records the finite Lua default and the
reason.
- test/test_container_limits.lua covers the three protocols for list, set
and map, at the limit and one over it, the default, the off values and
skip. Its pure-Lua stand-in for libluabpack gains the int8_t wrap of 'c'
and toVarint32, which the compact protocol needs.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
Client: lua
__readFrame passed the four-byte frame length to readAll unchecked, readString
and readBinary did the same with a field length, and THttpTransport did the
same with Content-Length. All three now refuse a negative or over-maximum
length before reading anything on account of it, against a default of 16 MB
that other bindings use and that each transport or protocol can override.
readAll accumulated with buf = buf .. chunk, which builds a new string and
copies everything read so far on every pass. A peer that drips bytes therefore
made the cost quadratic in what it sent -- measured here at 29x the time for 4x
the input, against 3.9x once the chunks are collected and joined once.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Client: py,go,php,java,netstd,delphi,haxe,lua,swift,rb,dart,erl,rs
C++ and Node.js already enforce a 10-byte ceiling on varint reads.
This change brings all remaining runtimes into parity by raising a
protocol exception (INVALID_DATA) when more than 10 bytes are consumed
without finding a terminating byte.
Java: both fast-path and slow-path varint readers are covered.
Erlang: read_varint/3 gains a when Count < 10 guard clause; call sites
updated to propagate the error tuple rather than crashing on badmatch.
Rust: VarIntReader trait replaced with local bounded loops; zigzag
decode moved to free functions independent of the integer_encoding crate.
Ruby: both the pure-Ruby implementation and the C extension are fixed;
read_varint32 gains a separate 5-byte limit instead of delegating to
read_varint64.
Named constants replace bare integer literals in all runtimes, with a
comment explaining the derivation (ceil(64/7) = 10, ceil(32/7) = 5).
Java and Rust enforce both the 5-byte (32-bit) and 10-byte (64-bit)
limits; other runtimes enforce the 10-byte ceiling uniformly.
Tests added for py, go, php, java (all four original runtimes), plus
rb, swift, dart, and rs which have existing unit-test infrastructure.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>