Sun JVM(JRE jre1.6.0_24)segfault NET_Read

16

我们的JVM在生产环境中不时出现分段错误,感觉像是某种竞态条件。

可重现的设置: - JRE jre1.6.0_24 在 Linux Ubuntu 9.10 和 Debian 4.x 64位多核 AMD 上 - Apache tomcat 6.0.24 ... 6.0.32

使用fastdebug重新编译java可以重现问题(该gcc -g1)。 但是,它并没有提供比我们拥有的更有用的信息。

使用debug重新编译java无法重现问题(这是gcc -g加上可能的一些-DSOMETHING代码调试标志)。

希望能有任何帮助来尝试找出问题的方法。

使用Oracle的1.6.0_24 jdk生成的核心文件。 gdb的结果如下:

    Program terminated with signal 11, Segmentation fault.
    #0  0x00002aaab7b10666 in NET_Read () from
    /usr/local/jdk1.6.0_24/jre/lib/amd64/libnet.so

好的,我的汇编语言非常非常陈旧。请记住这一点:

    (gdb) info frame
    Stack level 0, frame at 0x4b3e0040:
     rip = 0x2aaab7b10666 in NET_Read; saved rip 0x2aaab7b0d53b
     called by frame at 0x4b3f0090
             Arglist at 0x4b3dffc8, args:
     Locals at 0x4b3dffc8, Previous frame's sp is 0x4b3e0040
     Saved registers:
     rbx at 0x4b3e0008, rbp at 0x4b3e0010, r12 at 0x4b3e0018, r13 at
    0x4b3e0020, r14 at 0x4b3e0028, r15 at 0x4b3e0030, rip at 0x4b3e0038

因此,gdb告诉我们参数列表在:

    0x4b3dffc8

看着那里的数据:

    (gdb) x/8x 0x4b3dffc8
    0x4b3dffc8:     0x00000000      0x00000000      0x00000000      0x00000000
    0x4b3dffd8:     0x00000000      0x00000000      0x00000000      0x00000000

所以那里没有骰子。再次说明,我的汇编语言可以追溯到第二波斯卡,所以我只能认为栈有点出了问题,或者gcc优化标志生成的代码使用寄存器作为参数而不是栈?

关于寄存器:

    (gdb) info registers
    rax            0xf2     242
                                                    rbx            0x4      4
    rcx            0x2b73aa8bfed3   47775782534867
    rdx            0x4      4
    rsi            0x4b3e0050       1262354512
            rdi            0xf2     242
    rbp            0x0      0x0
    rsp            0x4b3dffd0       0x4b3dffd0
    r8             0xffc    4092
    r9             0x2b73aa8c61b0   47775782560176
    r10            0x2b73aa8c9f78   47775782575992
    r11            0x2b73aa8b20d0   47775782478032
    r12            0xf2     242
    r13            0xf2     242
    r14            0x2aaabad4b9c8   46912767310280
    r15            0x4      4
    rip            0x2aaab7b10666   0x2aaab7b10666 <NET_Read+22>
    eflags         0x10202  [ IF RF ]
    cs             0x33     51
    ss             0x2b     43
    ds             0x0      0
    es             0x0      0
    fs             0x63     99
    gs             0x0      0

反汇编代码(在我看来似乎是在Read+22处出现了故障):

    0x00002aaab7b10650 <NET_Read+0>:        push   %r15
            0x00002aaab7b10652 <NET_Read+2>:        mov    %rdx,%r15
    0x00002aaab7b10655 <NET_Read+5>:        push   %r14
                            0x00002aaab7b10657 <NET_Read+7>:        push   %r13
    0x00002aaab7b10659 <NET_Read+9>:        mov    %edi,%r13d
    0x00002aaab7b1065c <NET_Read+12>:       push   %r12
    0x00002aaab7b1065e <NET_Read+14>:       push   %rbp
    0x00002aaab7b1065f <NET_Read+15>:       push   %rbx
    0x00002aaab7b10660 <NET_Read+16>:       sub    $0x38,%rsp
    0x00002aaab7b10664 <NET_Read+20>:       test   %edi,%edi
    0x00002aaab7b10666 <NET_Read+22>:       mov    %rsi,0x8(%rsp)
    0x00002aaab7b1066b <NET_Read+27>:       js     0x2aaab7b1067c <NET_Read+44>
    0x00002aaab7b1066d <NET_Read+29>:       lea    1073812(%rip),%rax
     # 0x2aaab7c16908 <fdCount>
    0x00002aaab7b10674 <NET_Read+36>:       cmp    (%rax),%edi
    0x00002aaab7b10676 <NET_Read+38>:       jle    0x2aaab7b1070b <NET_Read+187>
    0x00002aaab7b1067c <NET_Read+44>:       xor    %ebp,%ebp
    0x00002aaab7b1067e <NET_Read+46>:       test   %rbp,%rbp
    0x00002aaab7b10681 <NET_Read+49>:       je     0x2aaab7b106f9 <NET_Read+169>
    0x00002aaab7b10683 <NET_Read+51>:       lea    0x10(%rsp),%r14
    0x00002aaab7b10688 <NET_Read+56>:       callq  0x2aaab7b03dd0 <pthread_self@plt>
    0x00002aaab7b1068d <NET_Read+61>:       mov    %rbp,%rdi
    0x00002aaab7b10690 <NET_Read+64>:       movl   $0x0,0x20(%rsp)
    0x00002aaab7b10698 <NET_Read+72>:       mov    %rax,0x10(%rsp)
    0x00002aaab7b1069d <NET_Read+77>:       callq  0x2aaab7b03f80
    <pthread_mutex_lock@plt>
    0x00002aaab7b106a2 <NET_Read+82>:       mov    %rbp,%rdi
    0x00002aaab7b106a5 <NET_Read+85>:       mov    0x28(%rbp),%rax
    0x00002aaab7b106a9 <NET_Read+89>:       mov    %rax,0x18(%rsp)
    0x00002aaab7b106ae <NET_Read+94>:       mov    %r14,0x28(%rbp)
    0x00002aaab7b106b2 <NET_Read+98>:       callq  0x2aaab7b043b0
    <pthread_mutex_unlock@plt>
    0x00002aaab7b106b7 <NET_Read+103>:      mov    %r13d,%edi
    0x00002aaab7b106ba <NET_Read+106>:      mov    0x8(%rsp),%rsi
    0x00002aaab7b106bf <NET_Read+111>:      xor    %ecx,%ecx
    0x00002aaab7b106c1 <NET_Read+113>:      mov    %r15,%rdx
    0x00002aaab7b106c4 <NET_Read+116>:      callq  0x2aaab7b04160 <recv@plt>
    0x00002aaab7b106c9 <NET_Read+121>:      mov    %rbp,%rdi
    0x00002aaab7b106cc <NET_Read+124>:      mov    %r14,%rsi
    0x00002aaab7b106cf <NET_Read+127>:      mov    %eax,%ebx
    0x00002aaab7b106d1 <NET_Read+129>:      mov    %rax,%r12
    0x00002aaab7b106d4 <NET_Read+132>:      callq  0x2aaab7b11000 <endOp>
    0x00002aaab7b106d9 <NET_Read+137>:      inc    %ebx
    0x00002aaab7b106db <NET_Read+139>:      jne    0x2aaab7b106e7 <NET_Read+151>
    0x00002aaab7b106dd <NET_Read+141>:      callq  0x2aaab7b04380
    <__errno_location@plt>
    0x00002aaab7b106e2 <NET_Read+146>:      cmpl   $0x4,(%rax)
    0x00002aaab7b106e5 <NET_Read+149>:      je     0x2aaab7b10688 <NET_Read+56>
    0x00002aaab7b106e7 <NET_Read+151>:      mov    %r12d,%eax
    0x00002aaab7b106ea <NET_Read+154>:      add    $0x38,%rsp
    0x00002aaab7b106ee <NET_Read+158>:      pop    %rbx
    0x00002aaab7b106ef <NET_Read+159>:      pop    %rbp
    0x00002aaab7b106f0 <NET_Read+160>:      pop    %r12
    0x00002aaab7b106f2 <NET_Read+162>:      pop    %r13
            0x00002aaab7b106f4 <NET_Read+164>:      pop    %r14
            0x00002aaab7b106f6 <NET_Read+166>:      pop    %r15
            0x00002aaab7b106f8 <NET_Read+168>:      retq
            0x00002aaab7b106f9 <NET_Read+169>:      callq  0x2aaab7b04380
    <__errno_location@plt>
    0x00002aaab7b106fe <NET_Read+174>:      movl   $0x9,(%rax)
    0x00002aaab7b10704 <NET_Read+180>:      mov    $0xffffffff,%eax
    0x00002aaab7b10709 <NET_Read+185>:      jmp    0x2aaab7b106ea <NET_Read+154>
    0x00002aaab7b1070b <NET_Read+187>:      movslq %edi,%rax
    0x00002aaab7b1070e <NET_Read+190>:      lea    (%rax,%rax,2),%rbp
    0x00002aaab7b10712 <NET_Read+194>:      lea    1073639(%rip),%rax
     # 0x2aaab7c16900 <fdTable>
    0x00002aaab7b10719 <NET_Read+201>:      shl    $0x4,%rbp
    0x00002aaab7b1071d <NET_Read+205>:      add    (%rax),%rbp
    ---Type <return> to continue, or q <return> to quit---
    0x00002aaab7b10720 <NET_Read+208>:      jmpq   0x2aaab7b1067e <NET_Read+46>
    0x00002aaab7b10725 <NET_Read+213>:      data16
    0x00002aaab7b10726 <NET_Read+214>:      data16
    0x00002aaab7b10727 <NET_Read+215>:      data16
    0x00002aaab7b10728 <NET_Read+216>:      nop
    0x00002aaab7b10729 <NET_Read+217>:      data16
    0x00002aaab7b1072a <NET_Read+218>:      data16
    0x00002aaab7b1072b <NET_Read+219>:      data16
    0x00002aaab7b1072c <NET_Read+220>:      nop
    0x00002aaab7b1072d <NET_Read+221>:      data16
    0x00002aaab7b1072e <NET_Read+222>:      data16
    0x00002aaab7b1072f <NET_Read+223>:      nop

查看 NETRead 的源代码:

    jdk/src/solaris/native/java/net/linux_close.c

    *snip*
    /*
             * Macro to perform a blocking IO operation. Restarts
     * automatically if interrupted by signal (other than
             * our wakeup signal)
     */
    #define BLOCKING_IO_RETURN_INT(FD, FUNC) {      \
       int ret;                                    \
       threadEntry_t self;                         \
               fdEntry_t *fdEntry = getFdEntry(FD);        \
               if (fdEntry == NULL) {                      \
           errno = EBADF;                          \
           return -1;                              \
       }                                           \
       do {                                        \
           startOp(fdEntry, &self);                \
           ret = FUNC;                             \
           endOp(fdEntry, &self);                  \
       } while (ret == -1 && errno == EINTR);      \
       return ret;                                 \
    }

    int NET_Read(int s, void* buf, size_t len) {
       BLOCKING_IO_RETURN_INT( s, recv(s, buf, len, 0) );
    }

谢谢。


可重现的JVM崩溃很有趣:这是我的一个例子... https://dev59.com/hnE95IYBdhLWcg3wd9tK 人们会告诉你,如果你的发行版没有官方支持,那么你就完了(在我看来有点傻,但无论如何;) - SyntaxT3rr0r
2
我很好奇你从哪里获取了Sun Java源代码进行重新编译。但是,是的 - 1)您肯定拥有64位JVM(“rax”,“rcx”等),2)您说它是来自Oracle的Sun JVM,3)您说您可以通过使用“fastdebug”编译重现问题,并且使用“-g”后问题消失....所以4)我只能说这是Java此版本上GCC优化器的问题。问:您尝试过不同版本吗? - paulsm4
你的 "assembly" 确实生锈了:它叫做 "汇编器" ;) - jjmontes
1
"非常感谢任何帮助解决这个问题的支持。在JVM中出现SEGV错误表明JVM或JNI代码存在漏洞。程序中是否有您自己编写的JNI?如果没有,您只能向Oracle提交错误报告。他们应该感谢您,因为您已经超越了典型的错误报告。" - Raedwald
2个回答

1

0

getFdEntry是一个宏还是内联函数?我会在那里查找。根据汇编代码转储,段错误发生在第一次分支之前,就在初始堆栈操作之后,这使得它看起来像是在getFdEntry的某个地方。此外,考虑到对读取的调用被包装在类似于锁定/解锁操作的东西中,我认为你对竞争条件的怀疑可能是正确的。没有看到源代码的其余部分很难说,但我最好的猜测是getFdEntry是一个内联函数,它不够线程安全。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接