Commit f5c7df5
committed
gfx/common/vulkan: plug partial-init leak in emulated mailbox + CI
Found during the v2 audit of gfx/common/vulkan_common.c, deferred
from the v3 patch (da5e650) which addressed the three high-severity
heap-corruption findings. Adds an AddressSanitizer + LSan
regression test under samples/gfx/vulkan_mailbox_init_leak/ wired
into the existing Linux-samples-gfx CI workflow as a fifth step.
vulkan_emulated_mailbox_init has three sequential allocations
(scond_new, slock_new, sthread_create) and on any of the latter
two failures returns `false` directly, leaking the already-
allocated cond and/or lock. Both production call sites in
vulkan_create_swapchain ignore the return value -- so an init
failure also leaves vk->mailbox.lock == NULL and vk->mailbox.cond
== NULL while VK_DATA_FLAG_EMULATING_MAILBOX is still set,
setting up a NULL-deref the next time vulkan_acquire_next_image()
routes into the emulated path (slock_lock(NULL) inside
vulkan_emulated_mailbox_acquire_next_image()).
The leak itself is small (the libretro-common slock_t / scond_t
each hold a pthread mutex / cond worth of data); the trigger
requires scond_new or slock_new to fail, which means OOM or
pthread resource exhaustion. Realistic mainly on memory-
constrained devices (older Android, Vita, 3DS, Wii U) where
filter-chain teardown / re-init under thrashing memory pressure
can put the system in this state.
* gfx/common/vulkan_common.c
Route every early-failure path in vulkan_emulated_mailbox_init
through `goto error` to a single cleanup that calls
vulkan_emulated_mailbox_deinit(). The deinit function is
null-safe (each free is guarded by an `if (mailbox->X)` check)
and ends with a memset, so the deinit-on-failure shape matches
the deinit-on-shutdown shape exactly -- the two production
callers that ignore the return value get a self-healing
failure mode.
The post-deinit memset also clears mailbox->swapchain, which
trips the existing guard at vulkan_acquire_next_image:
if (vk->mailbox.swapchain == VK_NULL_HANDLE)
err = VK_ERROR_OUT_OF_DATE_KHR;
closing the NULL-deref crash that the bare `return false` left
open. No caller-side changes needed.
* samples/gfx/vulkan_mailbox_init_leak/,
.github/workflows/Linux-samples-gfx.yml
Regression test following the convention of the v3 vulkan/
tests, the v4 slang test, and the security regression tests
under samples/tasks/. Keeps verbatim copies of both
vulkan_emulated_mailbox_init() and vulkan_emulated_mailbox_
deinit() demarcated by `=== verbatim copy ===` markers, with
an `IMPORTANT: ... must follow` comment. Plain C, asserts
manually, exits nonzero on failure.
Five probes: scond fails first (was already correct, baseline
case); slock fails second (pre-fix: scond leak); sthread fails
third (pre-fix: scond + slock leak); full success (sanity check
on alloc/free pairing post-deinit); and an explicit
__lsan_do_recoverable_leak_check() call after running all
three failure stages. Mocks scond_new / slock_new /
sthread_create with controllable failure injection so each
stage can be exercised deterministically.
Verified pre/post-patch discrimination: under the pre-fix
`return false` shape, ASan's LeakSanitizer reports 384 bytes
leaked across 6 allocations (1 scond from slock-fails + 2
alloc/leak pairs from sthread-fails + 3 from the lsan-check
probe), each with a full backtrace pointing into
vulkan_emulated_mailbox_init. Under the post-fix shape all
five probes pass clean. The CI step runs with
ASAN_OPTIONS=detect_leaks=1 so leaks fail the run with a
non-zero exit.1 parent de7ae03 commit f5c7df5
4 files changed
Lines changed: 628 additions & 3 deletions
File tree
- .github/workflows
- gfx/common
- samples/gfx/vulkan_mailbox_init_leak
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
139 | 139 | | |
140 | 140 | | |
141 | 141 | | |
| 142 | + | |
| 143 | + | |
| 144 | + | |
| 145 | + | |
| 146 | + | |
| 147 | + | |
| 148 | + | |
| 149 | + | |
| 150 | + | |
| 151 | + | |
| 152 | + | |
| 153 | + | |
| 154 | + | |
| 155 | + | |
| 156 | + | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
| 162 | + | |
| 163 | + | |
| 164 | + | |
| 165 | + | |
| 166 | + | |
| 167 | + | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
| 173 | + | |
| 174 | + | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
265 | 265 | | |
266 | 266 | | |
267 | 267 | | |
268 | | - | |
| 268 | + | |
269 | 269 | | |
270 | | - | |
| 270 | + | |
271 | 271 | | |
272 | 272 | | |
273 | | - | |
| 273 | + | |
274 | 274 | | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
275 | 288 | | |
276 | 289 | | |
277 | 290 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
| 1 | + | |
| 2 | + | |
| 3 | + | |
| 4 | + | |
| 5 | + | |
| 6 | + | |
| 7 | + | |
| 8 | + | |
| 9 | + | |
| 10 | + | |
| 11 | + | |
| 12 | + | |
| 13 | + | |
| 14 | + | |
| 15 | + | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
| 19 | + | |
| 20 | + | |
| 21 | + | |
| 22 | + | |
| 23 | + | |
| 24 | + | |
| 25 | + | |
0 commit comments