fix(security): prevent infinite loop in split_audio with NaN audio sa… (#46463)
This commit is contained in:
@@ -760,6 +760,42 @@ class TestAudioChunking:
|
||||
assert chunks[0][0] == audio[0]
|
||||
assert chunks[-1][-1] == audio[-1]
|
||||
|
||||
def test_find_split_point_nan_input(self):
|
||||
"""find_split_point must not return 0 for all-NaN input."""
|
||||
from vllm.multimodal.audio import find_split_point
|
||||
|
||||
nan_audio = np.full(32000, float("nan"), dtype=np.float32)
|
||||
start_idx = 16000
|
||||
end_idx = 32000
|
||||
|
||||
split_idx = find_split_point(
|
||||
wav=nan_audio,
|
||||
start_idx=start_idx,
|
||||
end_idx=end_idx,
|
||||
min_energy_window=1600,
|
||||
)
|
||||
|
||||
# Must return start_idx (the safe fallback), not 0
|
||||
assert split_idx == start_idx
|
||||
|
||||
def test_split_audio_nan_input_terminates(self):
|
||||
"""split_audio must terminate on all-NaN audio (no infinite loop)."""
|
||||
# 31 seconds of NaN at 16kHz — longer than max_clip_duration_s
|
||||
nan_audio = np.full(16000 * 31, float("nan"), dtype=np.float32)
|
||||
|
||||
chunks = split_audio(
|
||||
audio_data=nan_audio,
|
||||
sample_rate=16000,
|
||||
max_clip_duration_s=30.0,
|
||||
overlap_duration_s=1.0,
|
||||
min_energy_window_size=1600,
|
||||
)
|
||||
|
||||
# Must produce at least 2 chunks and cover all samples
|
||||
assert len(chunks) >= 2
|
||||
total_samples = sum(c.shape[-1] for c in chunks)
|
||||
assert total_samples == nan_audio.shape[-1]
|
||||
|
||||
def test_split_audio_with_different_sample_rates(self):
|
||||
"""Test chunking works with different sample rates."""
|
||||
|
||||
|
||||
@@ -378,6 +378,11 @@ def split_audio(
|
||||
audio_data, search_start, search_end, min_energy_window_size
|
||||
)
|
||||
|
||||
# Guarantee forward progress: if split_point didn't advance,
|
||||
# fall back to the hard chunk boundary.
|
||||
if split_point <= i:
|
||||
split_point = min(i + chunk_size, audio_data.shape[-1])
|
||||
|
||||
# Extract chunk up to the split point
|
||||
chunks.append(audio_data[..., i:split_point])
|
||||
i = split_point
|
||||
@@ -423,12 +428,12 @@ def find_split_point(
|
||||
|
||||
# Calculate RMS energy in small windows
|
||||
min_energy = math.inf
|
||||
quietest_idx = 0
|
||||
quietest_idx = start_idx
|
||||
|
||||
for i in range(0, len(segment) - min_energy_window, min_energy_window):
|
||||
window = segment[i : i + min_energy_window]
|
||||
energy = (window**2).mean() ** 0.5
|
||||
if energy < min_energy:
|
||||
if not math.isnan(energy) and energy < min_energy:
|
||||
quietest_idx = i + start_idx
|
||||
min_energy = energy
|
||||
|
||||
|
||||
Reference in New Issue
Block a user