Monorepo for Aesthetic.Computer aesthetic.computer
4
fork

Configure Feed

Select the types of activity you want to include in your feed.

audio: fix sample playback crash on recording stop

Race condition: playback thread reads sample_buf[] while mic_stop
writes to it (ring buffer copy + memmove trim). Fix:
- Kill all sample voices before modifying sample_buf in mic_stop
- Add bounds clamping in playback: clamp indices to sample_max_len
- Final bounds check before buffer access prevents segfault even
if sample_len changes between read and index calculation

This was causing kernel panic (via PID 1 segfault) when releasing
Home key during notepat sample recording.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+14 -1
+14 -1
fedac/native/src/audio.c
··· 317 317 318 318 // Interpolated read for L channel 319 319 int slen = audio->sample_len; 320 - if (slen <= 0) { sv->active = 0; continue; } 320 + int smax = audio->sample_max_len; 321 + if (slen <= 0 || smax <= 0) { sv->active = 0; continue; } 322 + // Clamp slen to buffer bounds (sample_len may change mid-read) 323 + if (slen > smax) slen = smax; 321 324 int p0l = (int)pos_l; 322 325 if (sv->loop) { 323 326 p0l = ((p0l % slen) + slen) % slen; ··· 325 328 sv->active = 0; continue; 326 329 } 327 330 int p1l = p0l + 1; if (p1l >= slen) p1l = sv->loop ? 0 : p0l; 331 + // Final bounds check against actual buffer size 332 + if (p0l >= smax || p1l >= smax) { sv->active = 0; continue; } 328 333 double fl = pos_l - p0l; 329 334 double samp_l = audio->sample_buf[p0l] * (1.0 - fl) 330 335 + audio->sample_buf[p1l] * fl; ··· 336 341 } else if (p0r >= slen) { 337 342 p0r = slen - 1; 338 343 } 344 + if (p0r < 0) p0r = 0; 339 345 int p1r = p0r + 1; if (p1r >= slen) p1r = sv->loop ? 0 : p0r; 346 + if (p0r >= smax || p1r >= smax) { sv->active = 0; continue; } 340 347 double fr = pos_r - p0r; 341 348 double samp_r = audio->sample_buf[p0r] * (1.0 - fr) 342 349 + audio->sample_buf[p1r] * fr; ··· 1229 1236 int audio_mic_stop(ACAudio *audio) { 1230 1237 if (!audio) return 0; 1231 1238 audio->recording = 0; 1239 + __sync_synchronize(); 1240 + 1241 + // Kill all sample voices BEFORE touching sample_buf — 1242 + // playback thread reads sample_buf[]/sample_len without locks 1243 + for (int i = 0; i < AUDIO_MAX_SAMPLE_VOICES; i++) 1244 + audio->sample_voices[i].active = 0; 1232 1245 __sync_synchronize(); 1233 1246 1234 1247 int direct_len = audio->sample_write_pos;