ref: c10c8191f21dd12c1bea2d9b9a68536f7cb0491c
parent: 8c325e35494ba9d2a5578d4a6702691884b85f0f
author: Erik de Castro Lopo <[email protected]>
date: Sat Aug 24 11:13:32 EDT 2019
src/src_sinc.c: Fix a buffer out-of-bounds read error The buffer out-of-bounds read that happens with the 'SRC_SINC_*' converters when the `src_ratio` is dynamically decreased while processing. This is a relatively naive fix for issue that seems to have an up to 3% performance degradation with respect to the unfixed version. It may be possible to come up with a better version of this fix that does not degrade performance. Closes: https://github.com/erikd/libsamplerate/issues/5
--- a/src/src_sinc.c
+++ b/src/src_sinc.c
@@ -295,12 +295,14 @@
left = 0.0 ;
do
- { fraction = fp_to_double (filter_index) ;
- indx = fp_to_int (filter_index) ;
+ { if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
+ { fraction = fp_to_double (filter_index) ;
+ indx = fp_to_int (filter_index) ;
- icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
+ icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
- left += icoeff * filter->buffer [data_index] ;
+ left += icoeff * filter->buffer [data_index] ;
+ } ;
filter_index -= increment ;
data_index = data_index + 1 ;
@@ -440,13 +442,15 @@
left [0] = left [1] = 0.0 ;
do
- { fraction = fp_to_double (filter_index) ;
- indx = fp_to_int (filter_index) ;
+ { if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
+ { fraction = fp_to_double (filter_index) ;
+ indx = fp_to_int (filter_index) ;
- icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
+ icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
- left [0] += icoeff * filter->buffer [data_index] ;
- left [1] += icoeff * filter->buffer [data_index + 1] ;
+ left [0] += icoeff * filter->buffer [data_index] ;
+ left [1] += icoeff * filter->buffer [data_index + 1] ;
+ } ;
filter_index -= increment ;
data_index = data_index + 2 ;
@@ -587,15 +591,17 @@
left [0] = left [1] = left [2] = left [3] = 0.0 ;
do
- { fraction = fp_to_double (filter_index) ;
- indx = fp_to_int (filter_index) ;
+ { if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
+ { fraction = fp_to_double (filter_index) ;
+ indx = fp_to_int (filter_index) ;
- icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
+ icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
- left [0] += icoeff * filter->buffer [data_index] ;
- left [1] += icoeff * filter->buffer [data_index + 1] ;
- left [2] += icoeff * filter->buffer [data_index + 2] ;
- left [3] += icoeff * filter->buffer [data_index + 3] ;
+ left [0] += icoeff * filter->buffer [data_index] ;
+ left [1] += icoeff * filter->buffer [data_index + 1] ;
+ left [2] += icoeff * filter->buffer [data_index + 2] ;
+ left [3] += icoeff * filter->buffer [data_index + 3] ;
+ } ;
filter_index -= increment ;
data_index = data_index + 4 ;
@@ -740,17 +746,19 @@
left [0] = left [1] = left [2] = left [3] = left [4] = left [5] = 0.0 ;
do
- { fraction = fp_to_double (filter_index) ;
- indx = fp_to_int (filter_index) ;
+ { if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
+ { fraction = fp_to_double (filter_index) ;
+ indx = fp_to_int (filter_index) ;
- icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
+ icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
- left [0] += icoeff * filter->buffer [data_index] ;
- left [1] += icoeff * filter->buffer [data_index + 1] ;
- left [2] += icoeff * filter->buffer [data_index + 2] ;
- left [3] += icoeff * filter->buffer [data_index + 3] ;
- left [4] += icoeff * filter->buffer [data_index + 4] ;
- left [5] += icoeff * filter->buffer [data_index + 5] ;
+ left [0] += icoeff * filter->buffer [data_index] ;
+ left [1] += icoeff * filter->buffer [data_index + 1] ;
+ left [2] += icoeff * filter->buffer [data_index + 2] ;
+ left [3] += icoeff * filter->buffer [data_index + 3] ;
+ left [4] += icoeff * filter->buffer [data_index + 4] ;
+ left [5] += icoeff * filter->buffer [data_index + 5] ;
+ } ;
filter_index -= increment ;
data_index = data_index + 6 ;
@@ -910,48 +918,49 @@
icoeff = filter->coeffs [indx] + fraction * (filter->coeffs [indx + 1] - filter->coeffs [indx]) ;
- /*
- ** Duff's Device.
- ** See : http://en.wikipedia.org/wiki/Duff's_device
- */
- ch = channels ;
- do
- {
- switch (ch % 8)
- { default :
- ch -- ;
- left [ch] += icoeff * filter->buffer [data_index + ch] ;
- /* Falls through. */
- case 7 :
- ch -- ;
- left [ch] += icoeff * filter->buffer [data_index + ch] ;
- /* Falls through. */
- case 6 :
- ch -- ;
- left [ch] += icoeff * filter->buffer [data_index + ch] ;
- /* Falls through. */
- case 5 :
- ch -- ;
- left [ch] += icoeff * filter->buffer [data_index + ch] ;
- /* Falls through. */
- case 4 :
- ch -- ;
- left [ch] += icoeff * filter->buffer [data_index + ch] ;
- /* Falls through. */
- case 3 :
- ch -- ;
- left [ch] += icoeff * filter->buffer [data_index + ch] ;
- /* Falls through. */
- case 2 :
- ch -- ;
- left [ch] += icoeff * filter->buffer [data_index + ch] ;
- /* Falls through. */
- case 1 :
- ch -- ;
- left [ch] += icoeff * filter->buffer [data_index + ch] ;
- } ;
- }
- while (ch > 0) ;
+ if (data_index >= 0) /* Avoid underflow access to filter->buffer. */
+ { /*
+ ** Duff's Device.
+ ** See : http://en.wikipedia.org/wiki/Duff's_device
+ */
+ ch = channels ;
+ do
+ { switch (ch % 8)
+ { default :
+ ch -- ;
+ left [ch] += icoeff * filter->buffer [data_index + ch] ;
+ /* Falls through. */
+ case 7 :
+ ch -- ;
+ left [ch] += icoeff * filter->buffer [data_index + ch] ;
+ /* Falls through. */
+ case 6 :
+ ch -- ;
+ left [ch] += icoeff * filter->buffer [data_index + ch] ;
+ /* Falls through. */
+ case 5 :
+ ch -- ;
+ left [ch] += icoeff * filter->buffer [data_index + ch] ;
+ /* Falls through. */
+ case 4 :
+ ch -- ;
+ left [ch] += icoeff * filter->buffer [data_index + ch] ;
+ /* Falls through. */
+ case 3 :
+ ch -- ;
+ left [ch] += icoeff * filter->buffer [data_index + ch] ;
+ /* Falls through. */
+ case 2 :
+ ch -- ;
+ left [ch] += icoeff * filter->buffer [data_index + ch] ;
+ /* Falls through. */
+ case 1 :
+ ch -- ;
+ left [ch] += icoeff * filter->buffer [data_index + ch] ;
+ } ;
+ }
+ while (ch > 0) ;
+ } ;
filter_index -= increment ;
data_index = data_index + channels ;
--- a/tests/varispeed_test.c
+++ b/tests/varispeed_test.c
@@ -23,7 +23,7 @@
#define fftw_cleanup()
#endif
-#define BUFFER_LEN (1 << 15)
+#define BUFFER_LEN (1 << 14)
static void varispeed_test (int converter, double target_snr) ;
static void varispeed_bounds_test (int converter) ;
@@ -221,22 +221,20 @@
src_data.input_frames = chunk_size ;
src_data.output_frames = total_output_frames ;
- /* Process one chunk at initial_ratio. */
- if ((error = src_process (src_state, &src_data)))
- { printf ("\n\nLine %d : %s : %s\n\n", __LINE__, details, src_strerror (error)) ;
- exit (1) ;
- } ;
-
- /* Now hard switch to second_ratio ... */
- src_data.src_ratio = second_ratio ;
- if ((error = src_process (src_state, &src_data)))
- { printf ("\n\nLine %d : %s : %s\n\n", __LINE__, details, src_strerror (error)) ;
- exit (1) ;
- } ;
-
- /* ... and process the remaining. */
+ /* Use a max_loop_count here to enable the detection of infinite loops
+ ** (due to end of input not being detected.
+ */
for (k = 0 ; k < max_loop_count ; k ++)
- { if ((error = src_process (src_state, &src_data)) != 0)
+ { if (k == 1)
+ { /* Hard switch to second_ratio after processing one chunk. */
+ src_data.src_ratio = second_ratio ;
+ if ((error = src_set_ratio (src_state, second_ratio)))
+ { printf ("\n\nLine %d : %s : %s\n\n", __LINE__, details, src_strerror (error)) ;
+ exit (1) ;
+ } ;
+ } ;
+
+ if ((error = src_process (src_state, &src_data)) != 0)
{ printf ("\n\nLine %d : %s : %s\n\n", __LINE__, details, src_strerror (error)) ;
exit (1) ;
} ;