Skip to content

Commit 8c325e3

Browse files
committed
Extend varispeed test to trigger out-of-bounds buffer read
Dramatic decreases in the SRC ratio can cause the SINC converters to read from a location before the start of the input data buffer. Debugging this was made easier by use of the ASAN sanitizer. Inspired by a PR from Alexander Grund <[email protected]>
1 parent 9fb7f43 commit 8c325e3

File tree

2 files changed

+134
-8
lines changed

2 files changed

+134
-8
lines changed

tests/util.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@ double calculate_snr (float *data, int len, int expected_peaks) ;
2929

3030
const char * get_cpu_name (void) ;
3131

32+
#define ASSERT(condition) \
33+
if (!(condition)) \
34+
{ printf ("Condition failed on Line %d : %s\n\n", __LINE__, #condition) ; \
35+
exit (1) ; \
36+
} ;
37+
3238
#if OS_IS_WIN32
3339
/*
3440
** Extra Win32 hacks.

tests/varispeed_test.c

Lines changed: 128 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -23,22 +23,46 @@
2323
#define fftw_cleanup()
2424
#endif
2525

26-
#define BUFFER_LEN (1 << 16)
26+
#define BUFFER_LEN (1 << 15)
2727

2828
static void varispeed_test (int converter, double target_snr) ;
29+
static void varispeed_bounds_test (int converter) ;
30+
static void set_ratio_test (int converter, int channels, double initial_ratio, double second_ratio) ;
2931

3032
int
3133
main (void)
3234
{
33-
puts ("") ;
34-
printf (" Zero Order Hold interpolator : ") ;
35+
puts ("\n Varispeed SNR test") ;
36+
printf (" Zero Order Hold interpolator : ") ;
37+
fflush (stdout) ;
3538
varispeed_test (SRC_ZERO_ORDER_HOLD, 10.0) ;
39+
puts ("ok") ;
3640

37-
printf (" Linear interpolator : ") ;
41+
printf (" Linear interpolator : ") ;
42+
fflush (stdout) ;
3843
varispeed_test (SRC_LINEAR, 10.0) ;
44+
puts ("ok") ;
3945

40-
printf (" Sinc interpolator : ") ;
46+
printf (" Sinc interpolator : ") ;
47+
fflush (stdout) ;
4148
varispeed_test (SRC_SINC_FASTEST, 115.0) ;
49+
puts ("ok") ;
50+
51+
puts ("\n Varispeed bounds test") ;
52+
printf (" Zero Order Hold interpolator : ") ;
53+
fflush (stdout) ;
54+
varispeed_bounds_test (SRC_ZERO_ORDER_HOLD) ;
55+
puts ("ok") ;
56+
57+
printf (" Linear interpolator : ") ;
58+
fflush (stdout) ;
59+
varispeed_bounds_test (SRC_LINEAR) ;
60+
puts ("ok") ;
61+
62+
printf (" Sinc interpolator : ") ;
63+
fflush (stdout) ;
64+
varispeed_bounds_test (SRC_SINC_FASTEST) ;
65+
puts ("ok") ;
4266

4367
fftw_cleanup () ;
4468
puts ("") ;
@@ -65,7 +89,7 @@ varispeed_test (int converter, double target_snr)
6589

6690
/* Perform sample rate conversion. */
6791
if ((src_state = src_new (converter, 1, &error)) == NULL)
68-
{ printf ("\n\nLine %d : src_new() failed : %s\n\n", __LINE__, src_strerror (error)) ;
92+
{ printf ("\n\nLine %d : src_new () failed : %s\n\n", __LINE__, src_strerror (error)) ;
6993
exit (1) ;
7094
} ;
7195

@@ -144,8 +168,104 @@ varispeed_test (int converter, double target_snr)
144168
exit (1) ;
145169
} ;
146170

147-
puts ("ok") ;
148-
149171
return ;
150172
} /* varispeed_test */
151173

174+
static void
175+
varispeed_bounds_test (int converter)
176+
{ double ratios [] = { 0.1, 0.01, 20 } ;
177+
int chan, r1, r2 ;
178+
179+
for (chan = 1 ; chan <= 9 ; chan ++)
180+
for (r1 = 0 ; r1 < ARRAY_LEN (ratios) ; r1++)
181+
for (r2 = 0 ; r2 < ARRAY_LEN (ratios) ; r2 ++)
182+
if (r1 != r2)
183+
set_ratio_test (converter, chan, ratios [r1], ratios [r2]) ;
184+
} /* varispeed_bounds_test */
185+
186+
static void
187+
set_ratio_test (int converter, int channels, double initial_ratio, double second_ratio)
188+
{ const int total_input_frames = BUFFER_LEN ;
189+
/* Maximum upsample ratio is 20, use a value beigger. */
190+
const int total_output_frames = 25 * BUFFER_LEN ;
191+
192+
/* Interested in array boundary conditions, so all zero data here is fine. */
193+
float *input = calloc (total_input_frames * channels, sizeof (float)) ;
194+
float *output = calloc (total_output_frames * channels, sizeof (float)) ;
195+
196+
char details [128] ;
197+
198+
const int max_loop_count = 100000 ;
199+
const int chunk_size = 128 ;
200+
201+
SRC_STATE *src_state ;
202+
SRC_DATA src_data ;
203+
204+
int error, k, total_frames_used, total_frames_gen ;
205+
206+
snprintf (details, sizeof (details), "%d channels, ratio %g -> %g", channels, initial_ratio, second_ratio) ;
207+
208+
if ((src_state = src_new (converter, channels, &error)) == NULL)
209+
{ printf ("\n\nLine %d : src_new () failed : %s\n\n", __LINE__, src_strerror (error)) ;
210+
exit (1) ;
211+
} ;
212+
213+
total_frames_used = 0 ;
214+
total_frames_gen = 0 ;
215+
216+
memset (&src_data, 0, sizeof (src_data)) ;
217+
src_data.end_of_input = 0 ;
218+
src_data.src_ratio = initial_ratio ;
219+
src_data.data_in = input ;
220+
src_data.data_out = output ;
221+
src_data.input_frames = chunk_size ;
222+
src_data.output_frames = total_output_frames ;
223+
224+
/* Process one chunk at initial_ratio. */
225+
if ((error = src_process (src_state, &src_data)))
226+
{ printf ("\n\nLine %d : %s : %s\n\n", __LINE__, details, src_strerror (error)) ;
227+
exit (1) ;
228+
} ;
229+
230+
/* Now hard switch to second_ratio ... */
231+
src_data.src_ratio = second_ratio ;
232+
if ((error = src_process (src_state, &src_data)))
233+
{ printf ("\n\nLine %d : %s : %s\n\n", __LINE__, details, src_strerror (error)) ;
234+
exit (1) ;
235+
} ;
236+
237+
/* ... and process the remaining. */
238+
for (k = 0 ; k < max_loop_count ; k ++)
239+
{ if ((error = src_process (src_state, &src_data)) != 0)
240+
{ printf ("\n\nLine %d : %s : %s\n\n", __LINE__, details, src_strerror (error)) ;
241+
exit (1) ;
242+
} ;
243+
244+
if (src_data.end_of_input && src_data.output_frames_gen == 0)
245+
break ;
246+
247+
total_frames_used += src_data.input_frames_used ;
248+
total_frames_gen += src_data.output_frames_gen ;
249+
250+
src_data.data_in += src_data.input_frames_used * channels ;
251+
src_data.data_out += src_data.output_frames_gen * channels ;
252+
253+
src_data.input_frames = total_input_frames - total_frames_used ;
254+
src_data.output_frames = total_output_frames - total_frames_gen ;
255+
256+
src_data.end_of_input = total_frames_used >= total_input_frames ? 1 : 0 ;
257+
} ;
258+
259+
ASSERT (k < max_loop_count) ;
260+
ASSERT (total_frames_gen > 0) ;
261+
262+
for (k = 0 ; k < total_frames_gen * channels ; k ++)
263+
ASSERT (! isnan (output [k])) ;
264+
265+
src_state = src_delete (src_state) ;
266+
267+
free (input) ;
268+
free (output) ;
269+
270+
return ;
271+
} /* set_ratio_test */

0 commit comments

Comments
 (0)