Skip to content

Fix heap overrun in texture readback for the model transparency scan#7616

Merged
BMagnu merged 3 commits into
scp-fs2open:masterfrom
Goober5000:fix/texture_check
Jul 18, 2026
Merged

Fix heap overrun in texture readback for the model transparency scan#7616
BMagnu merged 3 commits into
scp-fs2open:masterfrom
Goober5000:fix/texture_check

Conversation

@Goober5000

Copy link
Copy Markdown
Contributor

gr_opengl_get_bitmap_from_texture() sized its readback buffer from the texture cache slot dimensions and the bmpman frame count, but glGetTexImage() returns whatever the bound GL texture actually contains. When texture detail below maximum culls textures on upload, the two can disagree, and the readback overruns the buffer (observed as heap corruption when loading Zeus.pof with Texture Detail: Minimum). Size the readback from the dimensions and layer count OpenGL itself reports for the texture, and pad the staging buffer to 4x4 block granularity in case a driver writes tiny compressed mips back in whole blocks.

The readback now also allocates the returned buffer and reports the dimensions of the data it returns, because the second half of the bug was on the consumer side: bitmap_lookup indexed the readback data by the bitmap's own dimensions, so with any culling in effect the transparency scan read mostly uninitialized memory. bitmap_lookup (and its cache) now carries the actual readback dimensions, and it skips the texture cleanly if the readback fails.

Also pairs the cache's vm_malloc allocations with vm_free instead of free, and no longer ignores a failed tcache_set before reading back.

gr_opengl_get_bitmap_from_texture() sized its readback buffer from the
texture cache slot dimensions and the bmpman frame count, but
glGetTexImage() returns whatever the bound GL texture actually contains.
When texture detail below maximum culls textures on upload, the two can
disagree, and the readback overruns the buffer (observed as heap
corruption when loading Zeus.pof with Texture Detail: Minimum).  Size
the readback from the dimensions and layer count OpenGL itself reports
for the texture, and pad the staging buffer to 4x4 block granularity in
case a driver writes tiny compressed mips back in whole blocks.

The readback now also allocates the returned buffer and reports the
dimensions of the data it returns, because the second half of the bug
was on the consumer side: bitmap_lookup indexed the readback data by
the bitmap's own dimensions, so with any culling in effect the
transparency scan read mostly uninitialized memory.  bitmap_lookup (and
its cache) now carries the actual readback dimensions, and it skips the
texture cleanly if the readback fails.

Also pairs the cache's vm_malloc allocations with vm_free instead of
free, and no longer ignores a failed tcache_set before reading back.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@Goober5000 Goober5000 added fix A fix for bugs, not-a-bugs, and/or regressions. graphics A feature or issue related to graphics (2d and 3d) labels Jul 18, 2026
Return fully opaque from bitmap_lookup::get_channel_alpha() when the
bitmap has no alpha channel, since indexing channel 3 of a 3-channel
buffer reads out of bounds (currently unreachable because the only
caller checks bm_has_alpha_channel() first, but no longer a trap).

Per review, also assert at maximum texture detail, where no culling
occurs on upload, that the readback dimensions OpenGL reports match the
texture cache slot, so any future slot mismatch is caught immediately
in debug builds instead of surfacing as corruption.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The validation rejected the export only if both the width and the
height mismatched the texture cache slot, so a texture wrong in one
dimension passed through into opengl_get_texture, which trusts the
caller-supplied dimensions for its mipmap loop.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@BMagnu
BMagnu merged commit 6f4825c into scp-fs2open:master Jul 18, 2026
18 checks passed
@Goober5000
Goober5000 deleted the fix/texture_check branch July 18, 2026 19:53
@Goober5000 Goober5000 added the Point Release Candidate An already merged bugfix that may be merged into a previous stable version label Jul 18, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

fix A fix for bugs, not-a-bugs, and/or regressions. graphics A feature or issue related to graphics (2d and 3d) Point Release Candidate An already merged bugfix that may be merged into a previous stable version

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants