GNOME Bugzilla – Bug 794115
make check (test-quad) fails on 32bit x86 with musl libc
Last modified: 2018-03-14 23:06:09 UTC
test suite fails in test-quad on 32 bit x86 Alpine Linux. ... sin(-6.875) = -0.557868 [-0.557868] cos(-6.875) = 0.82993 [0.82993] sinpi(-6.875) = -0.382684 [-0.382684] cospi(-6.875) = -0.92388 [-0.92388] sin(7) = 0.656986 [0.656986] cos(7) = 0.753902 [0.753902] sinpi(7) = 0 [0] cospi(7) = -1 [-1] sin(-7) = -0.656986 [-0.656986] cos(-7) = 0.753902 [0.753902] sinpi(-7) = 0 [-0] cospi(-7) = -1 [-1] sin(7.125) = 0.745854 [4.51896] ** ERROR:test-quad.c:315:trig_tests: assertion failed: (fabs (go_quad_value (&qc) - p) / p < 1e-14) FAIL test-quad (exit status: 134) What is interesting is that libc sin(7.125) unexpectedly returns 4.51896. This does not happen unless the test suite is run. This does not happen on any other architecture either (armhf, aarch64, x86_64, ppc64le, s390x) I suspect that something messes up with the FPU state on i386 or similar.
diff --git a/tests/test-quad.c b/tests/test-quad.c index c33d416..76c955a 100644 --- a/tests/test-quad.c +++ b/tests/test-quad.c @@ -37,6 +37,13 @@ do { \ /* ------------------------------------------------------------------------- */ +static int testfpu(void) { + double x; + for (x=0; x<10; x+=0.125) + if (sin(x) > 1.0) return 0; + return 1; +} + static void pow_tests (void) { @@ -349,6 +356,7 @@ main (int argc, char **argv) GOQuad a, b, c; state = go_quad_start (); + g_assert(testfpu()); go_quad_init (&a, 42.125); g_assert (go_quad_value (&a) == 42.125); The above testfpu fails after go_quad_start() is called, but not before.
The problem is that the tests don't honor the documented (in comments, at https://github.com/GNOME/goffice/blob/b25fec70148ba52f9a2d886833733f75be67fa36/goffice/math/go-quad.c#L57) limitations for use of go_quad_start/end, that you can't make libm calls between them. test-quad.c simply wraps the whole main inside go_quad_start/end, calling a number of functions that are unsafe in this context, including floor, fabs, sin, cos, *printf (indirectly), etc.: https://github.com/GNOME/goffice/blob/7f65bb4bfbfa6792bd04099c27d14cf44fe03c50/tests/test-quad.c#L351 Shrinkwrapping the start/end around each go_quad operation inside the test macros should fix the issue. Further, as written the comment in go-quad.c is not actually strong enough. The i386 ABI has the fpu in extended precision mode, so calling any external function (anything in libc and potentially other libraries) that hasn't been written to support nonstandard fpu modes. In particular, the call to g_memdup is not safe, and should be moved before the mode setting. However, the whole alloc/dealloc per start/end is gratuitously slow; it would make a lot more sense to just replace the void* API for go_quad_start/end with one that takes a pointer to a moderately large char array into/out-of which it's safe to memcpy the fpu state (or better yet, just an object of type fenv_t).
I moved the g_memdup in go_quad_start. Don't diss the speed of that g_memdup/g_free pair until you measure it. glib keeps per-thread allocation pools and there's no indication that we have any performance problems at all.
Fixed the rest too. I hope. This problem has been fixed in our software repository. The fix will go into the next software release. Once that release is available, you may want to check for a software upgrade provided by your Linux distribution.