未发生被零除时如何调试sigfpe

时间:2019-12-25 04:47:17

标签: c ruby assembly gdb sigfpe

我正在尝试在sw64上用O0 -ggdb3编译ruby,这是一个类似alpha的拱,并遇到了一个奇怪的SIGFPE错误:

(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,来自gdb的回溯告诉我,帧1 distance_multiply是sigfpe的根本原因。

下面是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;
}

如您所见,如果m为零,它将直接返回,因此devided-by-zero sigfpe将永远不会发生。我还尝试借助d转储mprintf的值:

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;
  }
}

输出:

#+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

从日志中,我们可以看到最后一个日志始终是:

  

d = 1,m = 1,ONIG_INFINITE_DISTANCE = -1

d < ONIG_INFINITE_DISTANCE / m部分没有被打印,因为它已经陷在sigfpe中。奇怪的是,某些先前的日志也打印了d = 1, m = 1, ONIG_INFINITE_DISTANCE = -1,这意味着当d = 1m = 1时,在这些情况下不会发生sigfpe。

可能会发生什么?我没有想法了拆卸可以帮助吗?

编辑:

很抱歉,缺少宏定义:

#define ONIG_INFINITE_DISTANCE  ~((OnigDistance )0)
typedef size_t         OnigDistance;

0 个答案:

没有答案