Return an empty cell rather than nullptr when an encoded cell fails to decode - #680
sushant-me wants to merge 1 commit into
Conversation
EncodedS2ShapeIndex::GetCell() returned nullptr when S2ShapeIndexCell::Decode()
failed, and Iterator::cell() dereferences the result:
return *index_->GetCell(cell_pos_);
so iterating an index that contains a corrupt cell dereferenced a null pointer.
The bytes reach this path through Init(), so it is a crash on malformed input
rather than an internal invariant violation.
Return a static empty cell instead. The decoded contents of such a cell are
meaningless either way -- what this restores is the guarantee that traversal
does not crash, which is the contract the rest of the decode path already keeps
by returning false.
Both inputs in the regression test segfaulted (signal 11) before this change and
pass after it:
encoded_s2shape_index_test --gtest_filter='*MalformedCellDoesNotDereferenceNull*'
before: Segmentation fault (core dumped) [exit 139]
after: PASSED [exit 0]
Full suite on this branch: encoded_s2shape_index_test 10/10.
Split out of google#675 as requested there, so this can be reviewed on its own
without waiting on the num_edges allocation question, which is separate.
| auto cell = make_unique<S2ShapeIndexCell>(); | ||
| Decoder decoder = encoded_cells_.GetDecoder(i); | ||
| if (!cell->Decode(num_shape_ids(), &decoder)) { | ||
| return nullptr; |
There was a problem hiding this comment.
Like I said in the other PR, we should continue to return nullptr and check that at the call site. The bug is the missing null check, not what's returned here.
|
Closing this, because the test I added here showed the patch does not fix the crash it claims to. Run under ASan at So the crash this PR's own test exercises is an unvalidated That also explains the confusing CI result: the test passes on my machine without ASan and SEGFAULTs The fix for that input is the |
Split out of #675, per the request there to separate the changes so the
independent fixes can land without waiting on the rest.
The bug
EncodedS2ShapeIndex::GetCell()returnednullptrwhenS2ShapeIndexCell::Decode()failed, andIterator::cell()is:Iterating an index that contains a corrupt cell therefore dereferenced a null
pointer. The bytes arrive through
EncodedS2ShapeIndex::Init(), so this is acrash on malformed input.
The change
Return a static empty cell rather than
nullptr. The contents of such a cell aremeaningless either way; what this restores is the guarantee that traversal does
not crash — the same guarantee the rest of the decode path keeps by returning
false.Verification
Both inputs in the new test were run before and after:
The test asserts the crash directly rather than through a sanitizer, because the
failure mode is a segfault in a normal build.
Not included
This does not touch
num_edgesallocation. A separate concern in #675 is that amalformed single-shape cell can make
S2ClippedShape::Initallocatenum_edges * 4bytes from an untrusted count; that needs a sound bound and isbeing settled separately, since a bound derived from
Decoder::avail()is notsound (edges are run-length encoded, so their count is independent of the
remaining byte count).