Fix truncated size and stale capacity in tile array allocation - #258
Merged
kpchoi merged 1 commit intoAug 7, 2026
Merged
Conversation
The tile array is sized with a size_t expression but the instance allocator takes a 32-bit size, so the value is silently truncated on the way in. In the decoder the oapv_mset() on the following line uses the full, untruncated size, so a request above 4 GiB under-allocates and is then written past its end. The decoder path is reachable from the bitstream. sizeof(oapvd_tile_t) is 88, so the product exceeds 2^32 once num_tiles reaches 48,806,447, which an UNCONST profile at the minimum tile size reaches with a frame of about 16.7M x 745 pixels -- both within the u(24) frame dimensions, and accepted by oapv_validate_tile_topology() since the count stays below INT_MAX. tile_size_present_in_fh_flag may be 0, so no per-tile payload is needed either: a frame header of a few dozen bytes is enough to trigger it. Both sites also left tile_cap holding the previous capacity when the allocation failed, after the old array had already been freed. A later call whose tile count fitted that stale capacity skipped the allocation and dereferenced the NULL pointer, turning a recoverable OAPV_ERR_OUT_OF_MEMORY into a crash. Range-check the byte size before allocating, and clear the pointer and the capacity together so they cannot disagree. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two defects in the tile array allocation added in #236, one of them a memory-safety issue reachable from the bitstream. Both occur at the encoder site in
enc_frm_prepare()and the decoder site indec_frm_prepare().1. Truncated allocation size
The array is sized with a
size_texpression, butoapv_ops_mem.malloctakes a 32-bit size:so the value is silently truncated on the way in:
The
oapv_mset()on the following line uses the untruncated size, so a request above 4 GiB under-allocates and is then immediately written past its end.Reachability of the decoder path.
sizeof(oapvd_tile_t)is 88, so the product exceeds 2^32 oncenum_tilesreaches 48,806,447. Under an UNCONST profile at the minimum tile size that needs a frame of roughly 16.7M x 745 pixels — both inside theu(24)frame dimensions, and accepted byoapv_validate_tile_topology()because the count stays belowINT_MAX. Sincetile_size_present_in_fh_flagmay be 0, no per-tile payload is required: a frame header of a few dozen bytes is enough.2. Stale capacity after a failed allocation
Both sites freed the old array, then returned early on allocation failure with
tile_capstill holding the previous capacity:A later call whose tile count fits that stale capacity skips the whole block and dereferences
ctx->tilewhile NULL, turning a recoverableOAPV_ERR_OUT_OF_MEMORYinto a crash.The change
Range-check the byte size before allocating, and clear the pointer and the capacity together so they cannot disagree. The decoder reports
OAPV_ERR_MALFORMED_BITSTREAM(the count comes from the bitstream); the encoder reportsOAPV_ERR_INVALID_ARGUMENT(it comes from the caller's parameters).One file, +25/-4.
ctest18/18 pass.