You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
EncodedS2ShapeIndex: OOB access via unchecked shape_id in cell decode #676
Out-of-bounds access in EncodedS2ShapeIndex::shape() via unchecked shape_id
Related to (but distinct from) #674. A malformed EncodedS2ShapeIndex can encode a
clipped shape whose shape_id >= num_shape_ids(), causing an OOB access on the shapes_ vector during lazy shape decode.
Root cause
S2ShapeIndexCell::Decode() derives shape_id from the untrusted header
(shape_id_count >> 4, header >> 4, shape_delta) and only guards against int
overflow, never against num_shape_ids:
int64_t shape_id = 0;
for (...) {
if (shape_id >= std::numeric_limits<int>::max()) returnfalse; // overflow only
shape_id += <untrusted delta>; // can exceed num_shape_ids
clipped->Init(shape_id, num_edges);
}
shape(shape_id) then does shapes_[shape_id] with the precondition 0 <= id < num_shape_ids(), but shape_id is out of range.
OOB read (shapes_[id].load()) and OOB write (shapes_[id].compare_exchange_strong())
on a std::vector<std::atomic<S2Shape*>>. Under ASan this is a heap-buffer-overflow;
without the bounds assertion it is a silent OOB access.
Fix
In S2ShapeIndexCell::Decode(), reject any clipped shape with shape_id >= num_shape_ids
(return false). num_shape_ids is already a parameter, so the check is local.
Related framing: #686 documents the trusted byte stream assumption on EncodedS2ShapeIndex::Init — that a true return does not mean the encoding is sound, because cells are decoded lazily and a malformed one is not reached until later.
The behaviour reported here is unchanged; the note only states the contract a caller is operating under when it hands the decoder an encoding that does not satisfy it. Filing it as documentation rather than a fix follows jmr's reading on #674.
Activity
Validate shape_id against num_shape_ids in S2ShapeIndexCell::Decode
test: add regression tests for malformed encoded indexes (google#674/g…
sushant-me commentedon Oct 5, 2026
Related framing: #686 documents the trusted byte stream assumption on
EncodedS2ShapeIndex::Init— that atruereturn does not mean the encoding is sound, because cells are decoded lazily and a malformed one is not reached until later.The behaviour reported here is unchanged; the note only states the contract a caller is operating under when it hands the decoder an encoding that does not satisfy it. Filing it as documentation rather than a fix follows jmr's reading on #674.