My application gets a SIGFPE during a zooming operation on an image that was previously drawn successfully at lower zooming levels. Program received signal SIGFPE, Arithmetic exception. 0x00c5830e in _cairo_fixed_from_double (d=-33750.7673118194) at cairo_fixed.c:47 47 { (gdb) list 42 return i << 16; 43 } 44 45 cairo_fixed_t 46 _cairo_fixed_from_double (double d) 47 { 48 return (cairo_fixed_t) (d * 65536); 49 } 50 51 cairo_fixed_t (gdb) where #0 0x00c5830e in _cairo_fixed_from_double (d=-33750.7673118194) at cairo_fixed.c:47 #1 0x00c619ae in _cairo_traps_tessellate_polygon (traps=0xbfe64320, poly=0x8220c78, fill_rule=CAIRO_FILL_RULE_WINDING) at cairo_traps.c:529 #2 0x00c5fe2e in _cairo_pen_stroke_spline (pen=0xbfe64188, spline=0xbfe640cc, tolerance=warning: Unhandled dwarf expresion opcode DW_OP_piece 0.10000000000000001, traps=0xbfe64320) at cairo_pen.c:583 #3 0x00c5f392 in _cairo_stroker_curve_to (closure=0xbfe64254, b=0xbfe641f4, c=0xbfe641fc, d=0xbfe64204) at cairo_path_stroke.c:754 #4 0x00c5de15 in _cairo_path_interpret (path=0x81b0d40, dir=CAIRO_DIRECTION_FORWARD, move_to=0xc5eba4 <_cairo_stroker_move_to>, line_to=0xc5ebe0 <_cairo_stroker_line_to>, curve_to=0xc5f164 <_cairo_stroker_curve_to>, close_path=0xc5f39c <_cairo_stroker_close_path>, closure=0xbfe64254) at cairo_path.c:481 #5 0x00c5f4f7 in _cairo_path_stroke_to_traps (path=0x81b0d40, gstate=0x81b0c40, traps=0xbfe64320) at cairo_path_stroke.c:813 #6 0x00c5ae2f in _cairo_gstate_stroke (gstate=0x81b0c40) at cairo_gstate.c:1338 #7 0x00c5645b in cairo_stroke (cr=0x818bce8) at cairo.c:889 #8 0x0804dd5c in cairogen_bezier (job=0x8220c78, A=0x8226fb0, n=4, arrow_at_start=0, arrow_at_end=0) at gvrender_cairo.c:865 #9 0x00adb94e in gvrender_beziercurve (gvc=0x8139d58, AF=0x8226498, n=4, arrow_at_start=0, arrow_at_end=0) at gvrender.c:865 #10 0x00377750 in emit_edge (gvc=0x8139d58, e=0x8147930) at emit.c:881 #11 0x00378bf9 in emit_graph (gvc=0x8139d58, g=0x813f470) at emit.c:1226 #12 0x00adc0a5 in gvevent_refresh (job=0x8220c78) at gvevent.c:37 #13 0x0804d121 in cairogen_finalize (gvc=0x8139d58) at gvrender_cairo.c:175 #14 0x00ada6cc in gvrender_finalize (gvc=0x8139d58) at gvrender.c:138 #15 0x0037a02d in emit_jobs (gvc=0x8139d58, g=0x813f470) at emit.c:1630 #16 0x0804cb12 in main (argc=3, argv=0xbfe64a44) at dot.c:172 (gdb)
I can only get that to generate an FPE if I explicitly enable FE_INVALID. Is your code is enabling this exception? #include <stdio.h> #include <stdint.h> #define _GNU_SOURCE #include <fenv.h> int main() { double d = -33750.7673118194; feenableexcept(FE_INVALID); fprintf (stderr, "foo: %d\n", (int32_t) (d * 65536)); return 0; }
Ah yes, so that probably explains why I was unable to create a small test case. In dot.c (from graphviz-2.4) I set: feenableexcept( FE_DIVBYZERO | FE_OVERFLOW | FE_INVALID )
Thanks to Billy Biggs, I been able to create a small test case illustrating this bug. Please find attached.
Created attachment 3233 [details] [review] xcursor-4244-reset-theme-name.diff
Created attachment 3234 [details] [review] Mighty Mouse Horizontal Scrolling with inverting z axis.
Unfortunately, we've lost many of the attachments to freedesktop.org bugzilla. Would you happen to have the attachments still around?
I'll attach the recent "simple" test case (close, if not exactly the same as the previous attachment). Cairo seems to rely on some sort of automatic corrective behavior for FP errors (Is this behavior documented anywhere? Can it be counted on cross-platform?). If you enable all the possible FP errors there are a flood of problems. In graphviz we are FP error clean and normally keep the error reporting enabled. I finally worked out how to disable the FP error reporting just around the calls to cairo.
Created attachment 2923 [details] Source code illustrating one case of FPE in cairo.
No, Cairo isn't intentionally generating FP errors ... though it's certainly possible there are some places that it's generating FP errors in places that don't matter - the moral equivalent of: c = a / b; if (b > 0) return c; else return 0; Can you check if compiling Cairo with -ffloat-store fixes the problem - your test case seems to trigger a problem with if (m1 == m2) return 0; y_intersect = _cairo_fixed_from_double ((b2 - b1) / (m1 - m2)); Which looks like a typical 80-bit float register problem.
( I don't think your example is mathmatically correct .. but no matter. ) I've been using the cairo-0.9.2-2 shipped with Fedora, which produces FE_INVALID. Something must have changed since then because cairo from CVS produces FE_INEXACT. (I wish I knew how to detect which FP error has occurred. fetestexcept(FE_ALL_EXCEPT) always returns zero. I've been checking for any error with FP_ALL_EXCEPT, then narrowing it down by trying the specific exceptions one at a time.) Rebulding cairo with -ffloat-store made no difference.
Investigated a little bit and I think it's basically a stroker problem - _cairo_pen_stroke_spline() calls _cairo_traps_tessellate_polygon() with a polygon that has two nearly parallel edges, and intersecting them causes a division by zero, or a catastrophic lack of accuracy. Looking at the polygon that gets passed in, it has, for example: (gdb) p polygon->edges[1] $5 = {edge = {p1 = {x = 818734, y = 1992760}, p2 = {x = 926867, y = 2089629}}, clockWise = 0, current_x = 818734} (gdb) p polygon->edges[2] $6 = {edge = {p1 = {x = 818734, y = 1992760}, p2 = {x = 926867, y = 2089629}}, clockWise = 0, current_x = 823407} I don't really understand the polygon structure, but that looks fishy. Anyways, would require some detailed digging to figure it out.
Move bugs against "cvs" version to "0.9.3" so we can remove the "cvs" version.
Seems to still happen, though in a different code path than in comment 11. Since the exception is FE_INEXACT, it sounds like the accuracy of the FP is not enough to compute the result exactly. I wonder if this has real-life consequences or not (extreme scaling could of course bring the error visible). Other than detecting the accuracy of the FP unit (can that be done?) and rounding the values to acceptable values, I'm guessing there isn't much to do here. This is a problem that needs to be specifically requested for by setting the handler anyway. Current backtrace looks like: Program received signal SIGFPE, Arithmetic exception. *INT_cairo_matrix_transform_distance (matrix=0x8053ec8, dx=0xbfeb11d8, dy=0xbfeb11d0) at cairo-matrix.c:331 331 new_x = (matrix->xx * *dx + matrix->xy * *dy); (gdb) bt #0 *INT_cairo_matrix_transform_distance (matrix=0x8053ec8, dx=0xbfeb11d8, dy=0xbfeb11d0) at cairo-matrix.c:331 #1 0xb7f3b815 in *INT_cairo_matrix_transform_point (matrix=0x8053ec8, x=0xbfeb11d8, y=0xbfeb11d0) at cairo-matrix.c:350 #2 0xb7f375ba in _cairo_gstate_user_to_backend (gstate=0x8053e10, x=0xbfeb11d8, y=0xbfeb11d0) at cairo-gstate.c:731 #3 0xb7f3134a in *INT_cairo_move_to (cr=0x8053df0, x=19.800000000000001, y=35.200000000000003) at cairo.c:1381 #4 0x080487e9 in main ()
We routinely now test with FPE enabled in the test-suite [since 1.6], although only for the fatal traps DivideByZero, Overflow and Invalid. Underflow and Inexac,t I consider to be mere warnings that the floating point arithmetic can no longer represent the result without loss of accuracy. If you consider the application of such values within cairo (e.g. conversion to 24.8 fixed point during rasteristation, or printing using %.18f to vector targets) then those two exceptions are of no significant consequence (one hopes). Wrt the original bug, cairo_polygon_t now discards degenerate edges and so the division-by-zero is prevented at source. So given the specific bug has been fixed and the general bug has been incorporated into routine testing, I feel confident in closing this bug. Many thanks for the original report.
Use of freedesktop.org services, including Bugzilla, is subject to our Code of Conduct. How we collect and use information is described in our Privacy Policy.