test-resample: add test for floating point rounding producing bad in_len

If phase is float, calculations in impl_native_in_len/out_len don't
necessarily match with do_resample, because e.g.

    float phase0 = 7999.99;
    float phase = phase0;
    int frac = 8000, out_rate = 8000, n = 64, count = 0;
    for (int j = 0; j < n; ++j) {
        phase += frac;
        if (phase >= out_rate) {
                phase -= out_rate;
                count++;
        }
    }
    printf("count = %d\n", count);      /* count = 64 */

    count = (int)(phase0 + n*frac) / out_rate;
    printf("count = %d\n", count);      /* count = 65 */

don't give the same result.

Also add test where floating point multiplication rounding up to nearest
in

    float ph = phase * pm;
    uint32_t offset = (uint32_t)floorf(ph);

computation results to offset+1 > data->n_phases, accessing filter array
beyond bounds.  (The accessed value is still inside allocated memory
block, but contains unrelated values; the test passes silently.)
This commit is contained in:
Pauli Virtanen 2025-07-27 13:18:08 +03:00 committed by Wim Taymans
parent 84e8d59782
commit 3cade43cf3

View file

@ -15,6 +15,7 @@
SPA_LOG_IMPL(logger);
#include "resample.h"
#include "resample-native-impl.h"
#define N_SAMPLES 253
#define N_CHANNELS 11
@ -125,14 +126,20 @@ static void pull_blocks_out(struct resample *r, uint32_t first, uint32_t size, u
}
}
static void check_inout_len(struct resample *r, uint32_t first, uint32_t size, double rate)
static void check_inout_len(struct resample *r, uint32_t first, uint32_t size, double rate, double phase)
{
struct native_data *data = r->data;
resample_reset(r);
resample_update_rate(r, rate);
if (phase != 0.0)
data->phase = (float)phase;
pull_blocks(r, first, size, 500);
resample_reset(r);
resample_update_rate(r, rate);
if (phase != 0.0)
data->phase = (float)phase;
pull_blocks_out(r, first, size, 500);
}
@ -148,7 +155,7 @@ static void test_inout_len(void)
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
check_inout_len(&r, 1024, 1024, 1.0);
check_inout_len(&r, 1024, 1024, 1.0, 0);
resample_free(&r);
spa_zero(r);
@ -159,7 +166,7 @@ static void test_inout_len(void)
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
check_inout_len(&r, 1024, 1024, 1.0);
check_inout_len(&r, 1024, 1024, 1.0, 0);
resample_free(&r);
spa_zero(r);
@ -170,7 +177,7 @@ static void test_inout_len(void)
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
check_inout_len(&r, 1024, 1024, 1.0);
check_inout_len(&r, 1024, 1024, 1.0, 0);
resample_free(&r);
spa_zero(r);
@ -181,7 +188,7 @@ static void test_inout_len(void)
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
check_inout_len(&r, 513, 64, 1.0);
check_inout_len(&r, 513, 64, 1.0, 0);
resample_free(&r);
spa_zero(r);
@ -192,7 +199,7 @@ static void test_inout_len(void)
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
check_inout_len(&r, 513, 64, 1.02);
check_inout_len(&r, 513, 64, 1.02, 0);
resample_free(&r);
spa_zero(r);
@ -203,7 +210,7 @@ static void test_inout_len(void)
r.quality = RESAMPLE_DEFAULT_QUALITY;
resample_native_init(&r);
check_inout_len(&r, 513, 64, 1.0002);
check_inout_len(&r, 513, 64, 1.0002, 0);
resample_free(&r);
spa_zero(r);
@ -215,7 +222,37 @@ static void test_inout_len(void)
r.options = RESAMPLE_OPTION_PREFILL;
resample_native_init(&r);
check_inout_len(&r, 513, 64, 1.0002);
check_inout_len(&r, 513, 64, 1.0002, 0);
resample_free(&r);
/* Test value of phase that in floating-point arithmetic produces
* inconsistent in_len
*/
spa_zero(r);
r.log = &logger.log;
r.channels = 1;
r.i_rate = 8000;
r.o_rate = 8000;
r.quality = RESAMPLE_DEFAULT_QUALITY;
r.options = RESAMPLE_OPTION_PREFILL;
resample_native_init(&r);
check_inout_len(&r, 64, 64, 1.0 + 1e-10, 7999.99);
resample_free(&r);
/* Test value of phase that overflows filter buffer due to floating point rounding
* up to nearest
*/
spa_zero(r);
r.log = &logger.log;
r.channels = 1;
r.i_rate = 8000;
r.o_rate = 8000;
r.quality = RESAMPLE_DEFAULT_QUALITY;
r.options = RESAMPLE_OPTION_PREFILL;
resample_native_init(&r);
check_inout_len(&r, 64, 64, 1.0 + 1e-10, nextafterf(8000, 0));
resample_free(&r);
}