Summary
FunTpassInferBuffer in runtime/onnxruntime/src/funasrruntime.cpp allocates buff and len via new[] on every iteration of the timestamp loop but never calls delete[]. Confirmed by AddressSanitizer.
Location
runtime/onnxruntime/src/funasrruntime.cpp (current main), the second while(audio->FetchTpass(frame) > 0) loop, around lines 565-568:
while(audio->FetchTpass(frame) > 0){
...
float** buff;
int* len;
buff = new float*[1]; // ← leaked every iteration
len = new int[1]; // ← leaked every iteration
buff[0] = frame->data;
len[0] = frame->len;
...
if(frame != nullptr){
delete frame;
frame = nullptr;
}
} // ← buff and len NEVER deleted
For comparison, FunOfflineInferBuffer in the same file (around line 277-285) correctly does delete[] buff/len/flag/start_time at the loop tail. Only the 2pass / TpassStream path is missing the cleanup.
ASAN evidence
Rebuilt the runtime with -fsanitize=address and ran 100 inference calls end-to-end, then SIGTERM. LSan reports exactly:
Direct leak of 800 byte(s) in 100 object(s) allocated from:
#0 0x... in operator new[]
#1 0x... in FunTpassInferBuffer ... /onnxruntime/src/funasrruntime.cpp:567
#2 0x... in funasr_tpass_offline_infer ... /onnxruntime/src/funasr_capi.cpp:287
Direct leak of 400 byte(s) in 100 object(s) allocated from:
#0 0x... in operator new[]
#1 0x... in FunTpassInferBuffer ... /onnxruntime/src/funasrruntime.cpp:568
100 inferences × (1 × new float*[1] + 1 × new int[1]) = 100 × 8B + 100 × 4B = 1200B. The leak rate scales with the number of timestamp segments per inference (the FetchTpass loop iteration count), so for streams with multi-segment audio the absolute number is higher.
Proposed fix
Add delete[] buff; delete[] len; before the existing delete frame cleanup at the loop tail:
if (!(p_result->stamp).empty()){
p_result->stamp_sents = funasr::TimestampSentence(p_result->tpass_msg, p_result->stamp);
}
+ delete[] buff;
+ delete[] len;
if(frame != nullptr){
delete frame;
frame = nullptr;
}
}
After applying, the same ASAN run shows zero leak from FunTpassInferBuffer.
Why this is worth fixing
Per-request 12-byte leak feels small but the runtime is typically deployed as a long-lived service. At 100 QPS sustained, this alone amounts to ~100MB/day of allocator-managed memory not counting glibc/jemalloc per-allocation header overhead, which the reported Direct leak of N byte(s) numbers do not include. Multiple historical issues (#943, #1694, #1708) report production memory growth in funasr-runtime-sdk-cpu that are likely the same root cause.
Summary
FunTpassInferBufferinruntime/onnxruntime/src/funasrruntime.cppallocatesbuffandlenvianew[]on every iteration of the timestamp loop but never callsdelete[]. Confirmed by AddressSanitizer.Location
runtime/onnxruntime/src/funasrruntime.cpp(currentmain), the secondwhile(audio->FetchTpass(frame) > 0)loop, around lines 565-568:For comparison,
FunOfflineInferBufferin the same file (around line 277-285) correctly doesdelete[] buff/len/flag/start_timeat the loop tail. Only the 2pass / TpassStream path is missing the cleanup.ASAN evidence
Rebuilt the runtime with
-fsanitize=addressand ran 100 inference calls end-to-end, then SIGTERM. LSan reports exactly:100 inferences × (1 ×
new float*[1]+ 1 ×new int[1]) = 100 × 8B + 100 × 4B = 1200B. The leak rate scales with the number of timestamp segments per inference (the FetchTpass loop iteration count), so for streams with multi-segment audio the absolute number is higher.Proposed fix
Add
delete[] buff; delete[] len;before the existingdelete framecleanup at the loop tail:if (!(p_result->stamp).empty()){ p_result->stamp_sents = funasr::TimestampSentence(p_result->tpass_msg, p_result->stamp); } + delete[] buff; + delete[] len; if(frame != nullptr){ delete frame; frame = nullptr; } }After applying, the same ASAN run shows zero leak from
FunTpassInferBuffer.Why this is worth fixing
Per-request 12-byte leak feels small but the runtime is typically deployed as a long-lived service. At 100 QPS sustained, this alone amounts to ~100MB/day of allocator-managed memory not counting glibc/jemalloc per-allocation header overhead, which the reported
Direct leak of N byte(s)numbers do not include. Multiple historical issues (#943, #1694, #1708) report production memory growth infunasr-runtime-sdk-cputhat are likely the same root cause.