@@ -5,9 +5,10 @@ The source snapshot is pinned to ggml-org/whisper.cpp commit
55The tree is otherwise an exact — if trimmed — upstream snapshot; see
66[ ` AETHER_VENDORING.md ` ] ( AETHER_VENDORING.md ) for what was removed.
77
8- AetherSDR carries three local changes: two in the ggml Metal backend, from the
9- same fix (#4535 , PR #4553 ), and one in the ggml CPU backend, a MinGW build fix
10- (#4406 ) landed separately.
8+ AetherSDR carries four local changes: two in the ggml Metal backend, from the
9+ same fix (#4535 , PR #4553 ), one in the ggml CPU backend, a MinGW build fix
10+ (#4406 ) landed separately, and one in ` src/whisper.cpp ` , a model-load crash fix
11+ (#4972 ).
1112
12131 . ` ggml/src/ggml-metal/CMakeLists.txt ` : adds ` GGML_METAL_EMBED_LIBRARY_COMPILED ` .
1314 Upstream's ` GGML_METAL_EMBED_LIBRARY ` embeds the merged kernel ** source** and
@@ -72,6 +73,52 @@ completion in 75 minutes on a Radeon Pro 560X.
7273 ` ggml-org/ggml ` and ` ggml-org/whisper.cpp ` , with no existing issue or PR —
7374 so a ` COMMIT ` bump alone would not have picked up a fix.
7475
76+ 4 . ` src/whisper.cpp ` : fails the model load when the weight buffer cannot be
77+ allocated, at both sites that share the pattern — ` whisper_model_load() ` and
78+ the VAD loader in ` whisper_vad_init_with_params() ` (the latter is not called
79+ by AetherSDR; it is patched so the two copies cannot drift).
80+
81+ Upstream writes
82+
83+ ``` cpp
84+ ggml_backend_buffer_t buf = ggml_backend_alloc_ctx_tensors_from_buft(ctx, buft);
85+ if (buf) { model.buffers.emplace_back(buf); ... }
86+ ```
87+
88+ with no `else`, then uploads the weights with `ggml_backend_tensor_set()`.
89+ When the allocation fails — a GPU short of memory is the ordinary case —
90+ every tensor in that context still has no buffer, and the first upload
91+ dereferences it. Measured on Linux with ggml-vulkan (RTX 5060 Laptop, ~1.1 GB
92+ of device memory free, `ggml-large-v3-turbo.bin`): ggml logs
93+ `alloc_tensor_range: failed to allocate Vulkan1 buffer of size 551900160`,
94+ then the process takes SIGSEGV at address 0x10 in
95+ `ggml_vk_buffer_write_2d()` on the ASR worker thread. A signal is not an
96+ exception, so the guards in `WhisperAsrBackend` cannot intercept it (#4972).
97+
98+ The patch adds `whisper_ctx_has_unallocated_tensor()` and an `else if` on it
99+ at both sites that logs and returns failure. A bare `else` would be wrong:
100+ the allocator also returns NULL when every tensor in the context was already
101+ allocated, so the helper repeats the allocator's own "needs allocation" test
102+ (`data == NULL && view_src == NULL`, non-zero size) rather than treating NULL
103+ as the error. The patch also changes the failed-load cleanup in
104+ `whisper_init_with_params_no_state()` from `delete ctx` to
105+ `whisper_free(ctx)`: the model stores raw ggml context and buffer pointers,
106+ so deleting the C++ context alone leaks them, including any weight buffers
107+ allocated before a later group failed. The VAD allocation-failure path
108+ similarly calls `whisper_vad_free(vctx)` before returning NULL. The returned
109+ NULL lets `WhisperAsrBackend::load()` latch the device and retry on CPU
110+ after the failed attempt's resources have been released.
111+
112+ Checked upstream at the time of this patch (2026-09-16): both sites read the
113+ same on `ggml-org/whisper.cpp` `master`, so a `COMMIT` bump alone would not
114+ pick up a fix.
115+
116+ **The Windows release does not compile this file.** It links the prebuilt
117+ `whisper.lib` from the `whisper-gpu-<ver>` release asset
118+ (`ASR_USE_PREBUILT_WHISPER_GPU`, top-level `CMakeLists.txt`), so this patch
119+ reaches Windows release binaries only when that pack is rebuilt from a tree
120+ that contains it and its pinned SHA-256 is updated.
121+
75122## Refreshing
76123
77124When refreshing whisper.cpp, first check whether upstream has adopted an
@@ -95,8 +142,18 @@ configure + build (`cmake --build` from a MinGW-w64 Ninja toolchain); a
95142regression here only shows up as a MinGW compile failure, not a test failure,
96143since MSVC and non-Windows builds never exercise this branch.
97144
145+ For the ` src/whisper.cpp ` allocation check, look at both
146+ ` ggml_backend_alloc_ctx_tensors_from_buft() ` call sites: if upstream now fails
147+ the load when the returned buffer is NULL, drop the local patch. Otherwise
148+ reapply it at both, including the full context cleanup on the failure paths.
149+ There is no unit seam for it — forcing the failure needs a
150+ GPU backend that is short of memory — so confirm on a GPU host by occupying
151+ device memory until the large tier cannot fit and enabling Copy Assist: the log
152+ must show ` GPU model load failed ... retrying on CPU ` and the process must
153+ survive.
154+
98155The authoritative diff for any of these files is its git history
99156(` git log -p -- third_party/whisper.cpp/ggml/src/ggml-metal/<file> ` or
100- ` .../ggml-cpu/ggml-cpu.c ` ). No checked-in ` .patch ` copy is kept for any of
157+ ` .../ggml-cpu/ggml-cpu.c ` , or ` .../src/whisper.cpp ` ). No checked-in ` .patch ` copy is kept for any of
101158them: it would need hand-syncing on every edit, and its context would not
102159apply cleanly across an upstream bump anyway.
0 commit comments