pulseaudio/src/tests/cpu-volume-test.c
Faidon Liambotis 2afecd637c tests: fix use of uninitialized variable cpu_info
On cpu-volume-test, cpu_info is initialized only on i386/amd64 systems,
and otherwise passed on to pa_cpu_init_orc() uninitialized.

If one was unlucky enough, they could end up with cpu_info.cpu_type ==
PA_CPU_X86 on a non-x86 system, and use and test the Orc codepath
without that being functional, and thus with the test failing.

This has been observed in the wild on the ppc64el Debian buildds. See
Debian bug #982740 for more context.

Define cpu_info here in the same way as in other tests.

Signed-off-by: Faidon Liambotis <paravoid@debian.org>
Part-of: <https://gitlab.freedesktop.org/pulseaudio/pulseaudio/-/merge_requests/511>
2021-03-01 15:02:11 +00:00

247 lines
7.4 KiB
C

/***
This file is part of PulseAudio.
PulseAudio is free software; you can redistribute it and/or modify
it under the terms of the GNU Lesser General Public License as published
by the Free Software Foundation; either version 2.1 of the License,
or (at your option) any later version.
PulseAudio is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
General Public License for more details.
You should have received a copy of the GNU Lesser General Public License
along with PulseAudio; if not, see <http://www.gnu.org/licenses/>.
***/
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <check.h>
#include <pulsecore/cpu-arm.h>
#include <pulsecore/cpu-x86.h>
#include <pulsecore/cpu-orc.h>
#include <pulsecore/random.h>
#include <pulsecore/macro.h>
#include <pulsecore/sample-util.h>
#include "runtime-test-util.h"
/* Common defines for svolume tests */
#define SAMPLES 1028
#define TIMES 1000
#define TIMES2 100
#define PADDING 16
static void run_volume_test(
pa_do_volume_func_t func,
pa_do_volume_func_t orig_func,
int align,
int channels,
bool correct,
bool perf) {
PA_DECLARE_ALIGNED(8, int16_t, s[SAMPLES]) = { 0 };
PA_DECLARE_ALIGNED(8, int16_t, s_ref[SAMPLES]) = { 0 };
PA_DECLARE_ALIGNED(8, int16_t, s_orig[SAMPLES]) = { 0 };
int32_t volumes[channels + PADDING];
int16_t *samples, *samples_ref, *samples_orig;
int i, padding, nsamples, size;
/* Force sample alignment as requested */
samples = s + (8 - align);
samples_ref = s_ref + (8 - align);
samples_orig = s_orig + (8 - align);
nsamples = SAMPLES - (8 - align);
if (nsamples % channels)
nsamples -= nsamples % channels;
size = nsamples * sizeof(int16_t);
pa_random(samples, size);
memcpy(samples_ref, samples, size);
memcpy(samples_orig, samples, size);
for (i = 0; i < channels; i++)
volumes[i] = PA_CLAMP_VOLUME((pa_volume_t)(rand() >> 15));
for (padding = 0; padding < PADDING; padding++, i++)
volumes[i] = volumes[padding];
if (correct) {
orig_func(samples_ref, volumes, channels, size);
func(samples, volumes, channels, size);
for (i = 0; i < nsamples; i++) {
if (samples[i] != samples_ref[i]) {
pa_log_debug("Correctness test failed: align=%d, channels=%d", align, channels);
pa_log_debug("%d: %04hx != %04hx (%04hx * %08x)", i, samples[i], samples_ref[i],
samples_orig[i], volumes[i % channels]);
ck_abort();
}
}
}
if (perf) {
pa_log_debug("Testing svolume %dch performance with %d sample alignment", channels, align);
PA_RUNTIME_TEST_RUN_START("func", TIMES, TIMES2) {
memcpy(samples, samples_orig, size);
func(samples, volumes, channels, size);
} PA_RUNTIME_TEST_RUN_STOP
PA_RUNTIME_TEST_RUN_START("orig", TIMES, TIMES2) {
memcpy(samples_ref, samples_orig, size);
orig_func(samples_ref, volumes, channels, size);
} PA_RUNTIME_TEST_RUN_STOP
fail_unless(memcmp(samples_ref, samples, size) == 0);
}
}
#if defined (__i386__) || defined (__amd64__)
START_TEST (svolume_mmx_test) {
pa_do_volume_func_t orig_func, mmx_func;
pa_cpu_x86_flag_t flags = 0;
int i, j;
pa_cpu_get_x86_flags(&flags);
if (!((flags & PA_CPU_X86_MMX) && (flags & PA_CPU_X86_CMOV))) {
pa_log_info("MMX/CMOV not supported. Skipping");
return;
}
orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
pa_volume_func_init_mmx(flags);
mmx_func = pa_get_volume_func(PA_SAMPLE_S16NE);
pa_log_debug("Checking MMX svolume");
for (i = 1; i <= 3; i++) {
for (j = 0; j < 7; j++)
run_volume_test(mmx_func, orig_func, j, i, true, false);
}
run_volume_test(mmx_func, orig_func, 7, 1, true, true);
run_volume_test(mmx_func, orig_func, 7, 2, true, true);
run_volume_test(mmx_func, orig_func, 7, 3, true, true);
}
END_TEST
START_TEST (svolume_sse_test) {
pa_do_volume_func_t orig_func, sse_func;
pa_cpu_x86_flag_t flags = 0;
int i, j;
pa_cpu_get_x86_flags(&flags);
if (!(flags & PA_CPU_X86_SSE2)) {
pa_log_info("SSE2 not supported. Skipping");
return;
}
orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
pa_volume_func_init_sse(flags);
sse_func = pa_get_volume_func(PA_SAMPLE_S16NE);
pa_log_debug("Checking SSE2 svolume");
for (i = 1; i <= 3; i++) {
for (j = 0; j < 7; j++)
run_volume_test(sse_func, orig_func, j, i, true, false);
}
run_volume_test(sse_func, orig_func, 7, 1, true, true);
run_volume_test(sse_func, orig_func, 7, 2, true, true);
run_volume_test(sse_func, orig_func, 7, 3, true, true);
}
END_TEST
#endif /* defined (__i386__) || defined (__amd64__) */
#if defined (__arm__) && defined (__linux__)
START_TEST (svolume_arm_test) {
pa_do_volume_func_t orig_func, arm_func;
pa_cpu_arm_flag_t flags = 0;
int i, j;
pa_cpu_get_arm_flags(&flags);
if (!(flags & PA_CPU_ARM_V6)) {
pa_log_info("ARMv6 instructions not supported. Skipping");
return;
}
orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
pa_volume_func_init_arm(flags);
arm_func = pa_get_volume_func(PA_SAMPLE_S16NE);
pa_log_debug("Checking ARM svolume");
for (i = 1; i <= 3; i++) {
for (j = 0; j < 7; j++)
run_volume_test(arm_func, orig_func, j, i, true, false);
}
run_volume_test(arm_func, orig_func, 7, 1, true, true);
run_volume_test(arm_func, orig_func, 7, 2, true, true);
run_volume_test(arm_func, orig_func, 7, 3, true, true);
}
END_TEST
#endif /* defined (__arm__) && defined (__linux__) */
START_TEST (svolume_orc_test) {
pa_do_volume_func_t orig_func, orc_func;
pa_cpu_info cpu_info = { PA_CPU_UNDEFINED, {}, false };
int i, j;
#if defined (__i386__) || defined (__amd64__)
pa_zero(cpu_info);
cpu_info.cpu_type = PA_CPU_X86;
pa_cpu_get_x86_flags(&cpu_info.flags.x86);
#endif
orig_func = pa_get_volume_func(PA_SAMPLE_S16NE);
if (!pa_cpu_init_orc(cpu_info)) {
pa_log_info("Orc not supported. Skipping");
return;
}
orc_func = pa_get_volume_func(PA_SAMPLE_S16NE);
pa_log_debug("Checking Orc svolume");
for (i = 1; i <= 2; i++) {
for (j = 0; j < 7; j++)
run_volume_test(orc_func, orig_func, j, i, true, false);
}
run_volume_test(orc_func, orig_func, 7, 1, true, true);
run_volume_test(orc_func, orig_func, 7, 2, true, true);
}
END_TEST
int main(int argc, char *argv[]) {
int failed = 0;
Suite *s;
TCase *tc;
SRunner *sr;
if (!getenv("MAKE_CHECK"))
pa_log_set_level(PA_LOG_DEBUG);
s = suite_create("CPU");
tc = tcase_create("svolume");
#if defined (__i386__) || defined (__amd64__)
tcase_add_test(tc, svolume_mmx_test);
tcase_add_test(tc, svolume_sse_test);
#endif
#if defined (__arm__) && defined (__linux__)
tcase_add_test(tc, svolume_arm_test);
#endif
tcase_add_test(tc, svolume_orc_test);
tcase_set_timeout(tc, 120);
suite_add_tcase(s, tc);
sr = srunner_create(s);
srunner_run_all(sr, CK_NORMAL);
failed = srunner_ntests_failed(sr);
srunner_free(sr);
return (failed == 0) ? EXIT_SUCCESS : EXIT_FAILURE;
}