I'm trying to compile ruby with O0 -ggdb3
on sw64---- a alpha-like arch and met a weird SIGFPE error:
(gdb) bt
#0 0x000002000544463c in __divlu ()
from /lib/libc.so.6.1
#1 0x0000020001fe6808 in distance_multiply (
d=18446744073709551615, m=1) at regcomp.c:109
#2 0x0000020001ff5a44 in optimize_node_left (
node=0x121f43be0, opt=0x2000db31480,
env=0x2000db31678) at regcomp.c:5247
#3 0x0000020001ff4b6c in optimize_node_left (
node=0x122387f60, opt=0x2000db317c0,
env=0x2000db319b8) at regcomp.c:4982
#4 0x0000020001ff62c4 in set_optimize_info_from_tree (node=0x122387f60, reg=0x12216df60,
scan_env=0x2000db31a20) at regcomp.c:5417
#5 0x0000020001ff6d64 in onig_compile_ruby (
reg=0x12216df60,
pattern=0x121c021e0 "\\A([^:\\s]*)(?:::([^:\\s]*))?\\s*=(.*)\\z", pattern_end=0x121c02205 "",
einfo=0x2000db31bc0,
sourcefile=0x12109eea0 "-", sourceline=90)
at regcomp.c:5854
#6 0x0000020001fd9ef4 in onig_new_with_source (
reg=0x2000db31bd8,
pattern=0x121c021e0 "\\A([^:\\s]*)(?:::([^:\\s]*))?\\s*=(.*)\\z", pattern_end=0x121c02205 "",
option=0, enc=0x12108c840,
syntax=0x2000213fef8 <OnigSyntaxRuby>,
einfo=0x2000db31bc0,
sourcefile=0x12109eea0 "-", sourceline=90)
at re.c:842
#7 0x0000020001fd9fe8 in make_regexp (
s=0x121c021e0 "\\A([^:\\s]*)(?:::([^:\\s]*))?\\s*=(.*)\\z", len=37, enc=0x12108c840, flags=0,
err=0x2000db31d20 "",
<tinue, or q <return> to quit---
IIUC, the backtrace from gdb tells me that the frame 1 distance_multiply
is the root cause of sigfpe.
Below is the definition of distance_multiply
static OnigDistance
distance_multiply(OnigDistance d, int m)
{
if (m == 0) return 0;
if (d < ONIG_INFINITE_DISTANCE / m)
return d * m;
else
return ONIG_INFINITE_DISTANCE;
}
As you can see, if m is zero, it will return directly, so devided-by-zero
sigfpe will never occur. I have also tried to dump the value of d
and m
with the help of printf
:
static OnigDistance
distance_multiply(OnigDistance d, int m)
{
fprintf(stderr, "\n\nd = %zu, m = %d, ONIG_INFINITE_DISTANCE = %d ", d, m, ONIG_INFINITE_DISTA\
NCE );
if (m == 0)
{
fprintf(stderr, "m == 0, should return\n");
return 0;
}
if (d < ONIG_INFINITE_DISTANCE / m)
{
fprintf(stderr, "d < ONIG_INFINITE_DISTANCE / m\n");
return d * m;
}
else
{
fprintf(stderr, "else\n");
return ONIG_INFINITE_DISTANCE;
}
}
output:
#+BEGIN_SRC
d = 1, m = 0, ONIG_INFINITE_DISTANCE = -1 m == 0, should return
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1 d < ONIG_INFINITE_DISTANCE / m
22% [198/871] ext/psych/lib/psych.rb
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1
Thread 1 "ruby2.5" received signal SIGFPE, Arithmetic exception.
0x000002000209263c in __divlu () from /lib/libc.so.6.1
#+END_SRC
#+BEGIN_SRC
d = 1, m = 0, ONIG_INFINITE_DISTANCE = -1 m == 0, should return
d = 1, m = 2, ONIG_INFINITE_DISTANCE = -1 d < ONIG_INFINITE_DISTANCE / m
43% [378/871] lib/net/http.rb
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1
Thread 1 "ruby2.5" received signal SIGFPE, Arithmetic exception.
0x0000020004bbc63c in __divlu () from /lib/libc.so.6.1
#+END_SRC
#+BEGIN_SRC
d = 1, m = 0, ONIG_INFINITE_DISTANCE = -1 m == 0, should return
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1 d < ONIG_INFINITE_DISTANCE / m
22% [198/871] ext/psych/lib/psych.rb
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1
Thread 1 "ruby2.5" received signal SIGFPE, Arithmetic exception.
0x000002000d9f063c in __divlu () from /lib/libc.so.6.1
#+END_SRC
#+BEGIN_SRC
d = 1, m = 0, ONIG_INFINITE_DISTANCE = -1 m == 0, should return
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1 d < ONIG_INFINITE_DISTANCE / m
22% [198/871] ext/psych/lib/psych.rb
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1
Thread 1 "ruby2.5" received signal SIGFPE, Arithmetic exception.
0x0000020001abc63c in __divlu () from /lib/libc.so.6.1
#+END_SRC
#+BEGIN_SRC
d = 1, m = 0, ONIG_INFINITE_DISTANCE = -1 m == 0, should return
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1 d < ONIG_INFINITE_DISTANCE / m
22% [198/871] ext/psych/lib/psych.rb
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1
Thread 1 "ruby2.5" received signal SIGFPE, Arithmetic exception.
0x0000020005ce263c in __divlu () from /lib/libc.so.6.1
#+END_SRC
#+BEGIN_SRC
d = 23, m = 1, ONIG_INFINITE_DISTANCE = -1 d < ONIG_INFINITE_DISTANCE / m
d = 24, m = 1, ONIG_INFINITE_DISTANCE = -1 d < ONIG_INFINITE_DISTANCE / m
d = 1, m = 0, ONIG_INFINITE_DISTANCE = -1 m == 0, should return
37% [329/871] lib/getoptlong.rb
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1
Thread 1 "ruby2.5" received signal SIGFPE, Arithmetic exception.
0x0000020000ba863c in __divlu () from /lib/libc.so.6.1
(gdb)
#+END_SRC
From the log, we can see that the last log is always:
d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1
and d < ONIG_INFINITE_DISTANCE / m
part is not printed because it has trapped into sigfpe already. What's strange is that some previous logs also printed d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1
, which means when d = 1
and m = 1
, sigfpe doesn't occur in those cases.
What may happend? I have no ideas any more. Can disassembly help here?
EDIT:
Sorry for the lack of macro definitions:
#define ONIG_INFINITE_DISTANCE ~((OnigDistance )0)
typedef size_t OnigDistance;