vercel-labs / vercel-labs/native
macOS: OOB panic in NativeSdkSpectrumComputeBands when sample rate < 32 kHz (index past Nyquist)
Nobody has claimed this yet.
- Dominant language
- Zig
- Stars
- 7.7k
- Forks
- 314
- Avg merge
- 5h
- Merged PRs (30d)
- 13
Description
Summary
NativeSdkSpectrumComputeBands in src/platform/macos/appkit_host.m crashes with an index-out-of-bounds panic when the audio sample rate is low enough that the fixed 50 Hz–16 kHz band range extends past the Nyquist frequency (e.g. 16 kHz sample rate, common for VoIP/telephony audio).
thread 9178883 panic: index 1036 out of bounds for type 'float[1024]'
src/platform/macos/appkit_host.m:8595:17 in NativeSdkSpectrumComputeBands
if (power[bin] > peak) peak = power[bin];
src/platform/macos/appkit_host.m:8743:10 in -[NativeSdkAppKitHost audioSpectrumTimerFired:]
if (!NativeSdkSpectrumComputeBands(state, self.audioSpectrumFft, window, event.audio_bands)) return;
Environment
@native-sdk/cli0.4.0 (@native-sdk/cli-darwin-arm64)- macOS (Darwin 25.5.0), Apple Silicon
- Crash observed while running an app via
native devwith audio playing at a 16 kHz sample rate (SIP/VoIP call audio)
Root cause
In the band-bucketing loop (appkit_host.m around line 8586):
int low_bin = (int)(low_hz / hz_per_bin);
int high_bin = (int)ceil(high_hz / hz_per_bin);
if (low_bin < 1) low_bin = 1;
if (high_bin > NATIVE_SDK_SPECTRUM_FFT_SIZE / 2 - 1) high_bin = NATIVE_SDK_SPECTRUM_FFT_SIZE / 2 - 1;
if (high_bin < low_bin) high_bin = low_bin; // <-- undoes the clamp above
float peak = 0.0f;
for (int bin = low_bin; bin <= high_bin; bin += 1) {
if (power[bin] > peak) peak = power[bin]; // <-- OOB read
}
Two problems combine:
low_binis clamped only at the bottom (< 1), never against the top of thepower[FFT_SIZE / 2]array.if (high_bin < low_bin) high_bin = low_bin;re-raiseshigh_binabove the top clamp applied on the previous line.
With sample_rate = 16000 and FFT_SIZE = 2048, hz_per_bin ≈ 7.8125. Bands whose low_hz exceeds the 8 kHz Nyquist produce low_bin ≥ 1024 (first offender lands at 1036, matching the panic), high_bin is clamped to 1023, then re-raised to low_bin, and the peak loop reads power[1036] out of bounds.
Any sample rate below 32 kHz can trigger this, since the top band edge is fixed at NATIVE_SDK_SPECTRUM_HIGH_HZ = 16 kHz.
Reproduction
- Build any app that enables the audio spectrum feed.
- Play audio whose engine sample rate is 16 kHz (e.g. wideband VoIP audio).
- Wait for
audioSpectrumTimerFired:to run once enough samples are buffered — the app panics.
Suggested fix
Clamp low_bin against the top of the array as well, and skip bands entirely above Nyquist rather than folding them onto the last bin, e.g.:
const int max_bin = NATIVE_SDK_SPECTRUM_FFT_SIZE / 2 - 1;
int low_bin = (int)(low_hz / hz_per_bin);
int high_bin = (int)ceil(high_hz / hz_per_bin);
if (low_bin < 1) low_bin = 1;
if (low_bin > max_bin) { // band entirely above Nyquist
bands[band] = 0; // silence, matches the floor-dB mapping
continue;
}
if (high_bin > max_bin) high_bin = max_bin;
if (high_bin < low_bin) high_bin = low_bin;
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start in src/platform/macos/appkit_host.m at NativeSdkSpectrumComputeBands and follow its call from audioSpectrumTimerFired:. Verify the band-bucketing bounds for sample rates below 32 kHz, including bands above Nyquist. Done means low-rate audio spectrum processing no longer reads past the power array and above-Nyquist bands produce silence.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- macos, objective-c
- Domain
- audio-video-rtc, desktop
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 75/100