NULL pointer dereference when probing Java methods

Tetsuo Handa penguin-kernel@I-love.SAKURA.ne.jp
Fri Dec 23 15:08:00 GMT 2016


Problem description:

  SystemTap allows probing Java methods with the aid of byteman
  ( https://developers.redhat.com/blog/2014/01/10/probing-java-w-systemtap/ ).
  But probing Java methods which have arguments of Java objects other than
  java.lang.String using java().class().method() syntax crashes java process.

  Is this a limitation (i.e. Java methods which have arguments of Java objects
  other than java.lang.String cannot be probed using java().class().method() syntax)
  rather than a bug?

Versions:

  CentOS 7:
    java-1.7.0-openjdk-devel-1.7.0.121-2.6.8.0.el7_3.x86_64
    systemtap-3.0-7.el7.x86_64
    systemtap-runtime-java-3.0-7.el7.x86_64
    byteman-2.0.4-5.el7.noarch (and 3.0.6 / 4.0.0-BETA1 from upstream)
    kernel-3.10.0-514.2.2.el7.x86_64

  Fedora 25:
    java-1.8.0-openjdk-devel-1.8.0.111-4.b16.fc25.x86_64
    systemtap-3.1-0.20160725git91bfb36.fc25.x86_64
    systemtap-runtime-java-3.1-0.20160725git91bfb36.fc25.x86_64
    byteman-3.0.6-2.fc25.noarch
    kernel-4.8.14-300.fc25.x86_64

Steps to reproduce:

Test1.java shown below is a reproducer

---------- Test1.java start ----------
public class Test1 {
        public boolean method1(int arg) { System.out.println(arg); return true; }
        public boolean method2(String arg) { System.out.println(arg); return true; }
        public boolean method3(Test1 arg) { System.out.println(arg); return true; }
        public static void main(String args[]) throws Exception {
                Test1 me = new Test1();
                while (true) {
                        me.method1(100);
                        me.method2("Hello");
                        me.method3(me);
                        Thread.sleep(1000);
                }
        }
}
---------- Test1.java end ----------

which can be compiled like shown below.

---------- command line 1 start ----------
$ javac Test1.java
---------- command line 1 end ----------

If I probe Test1 using hotspot.method_entry syntax, it is
probed correctly (but instead can't access arguments).

---------- command line 2 start ----------
# java -XX:+DTraceMethodProbes Test1
100
Hello
Test1@378a4aef
100
Hello
Test1@378a4aef
100
Hello
Test1@378a4aef
---------- command line 2 end ----------

---------- command line 3 start ----------
# stap -e 'probe hotspot.method_entry {
  if (class == "Test1" && method == "method1") { printf("Hooked %s %s@%s\n", class, method, sig); }
  if (class == "Test1" && method == "method2") { printf("Hooked %s %s@%s\n", class, method, sig); }
  if (class == "Test1" && method == "method3") { printf("Hooked %s %s@%s\n", class, method, sig); }
}'
Hooked Test1 method1@(I)Z
Hooked Test1 method2@(Ljava/lang/String;)Z
Hooked Test1 method3@(LTest1;)Z
Hooked Test1 method1@(I)Z
Hooked Test1 method2@(Ljava/lang/String;)Z
Hooked Test1 method3@(LTest1;)Z
Hooked Test1 method1@(I)Z
Hooked Test1 method2@(Ljava/lang/String;)Z
Hooked Test1 method3@(LTest1;)Z
---------- command line 3 end ----------

If I probe Test1 using java().class().method() syntax in order to access
arguments, the java process crashes due to NULL pointer dereference at
strlen() in get_java_string() in /usr/src/debug/systemtap-3.0/java/HelperSDT.c .

---------- command line 4 start ----------
# java Test1
100
Hello
Test1@73549af8
(...snipped...)
100
Hello
Test1@73549af8
(...started command line 5 at this timing...)
Setting org.jboss.byteman.transform.all=true
100
Hello
#
# A fatal error has been detected by the Java Runtime Environment:
#
#  SIGSEGV (0xb) at pc=0x00007fd44604be71, pid=3634, tid=140549695592192
#
# JRE version: OpenJDK Runtime Environment (7.0_121) (build 1.7.0_121-mockbuild_2016_11_21_19_08-b00)
# Java VM: OpenJDK 64-Bit Server VM (24.121-b00 mixed mode linux-amd64 compressed oops)
# Derivative: IcedTea 2.6.8
# Distribution: CentOS Linux release 7.2.1511 (Core) , package rhel-2.6.8.0.el7_3-x86_64 u121-b00
# Problematic frame:
# C  [libc.so.6+0x163e71]  __strlen_sse2_pminub+0x11
#
# Core dump written. Default location: /tmp/core or core.3634
#
# An error report file with more information is saved as:
# /tmp/jvm-3634/hs_error.log
#
# If you would like to submit a bug report, please include
# instructions on how to reproduce the bug and visit:
#   http://icedtea.classpath.org/bugzilla
#
Aborted (core dumped)
---------- command line 4 end ----------

---------- command line 5 start ----------
# stap -e 'probe java("Test1").class("Test1").method("method1(int)") { printf("Hooked method1() with arg = %d\n", $arg1); }
probe java("Test1").class("Test1").method("method2(String)") { printf("Hooked method2() with arg = %s\n", user_string($arg1)); }
probe java("Test1").class("Test1").method("method3(Test1)") { printf("Hooked method3() with arg\n"); }'
Hooked method1() with arg = 100
Hooked method2() with arg = Hello
---------- command line 5 end ----------

---------- command line 6 start ----------
# gdb core.3634
GNU gdb (GDB) Red Hat Enterprise Linux 7.6.1-94.el7
Copyright (C) 2013 Free Software Foundation, Inc.
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
This is free software: you are free to change and redistribute it.
There is NO WARRANTY, to the extent permitted by law.  Type "show copying"
and "show warranty" for details.
This GDB was configured as "x86_64-redhat-linux-gnu".
For bug reporting instructions, please see:
<http://www.gnu.org/software/gdb/bugs/>...
[New LWP 3635]
[New LWP 3641]
[New LWP 3638]
[New LWP 3636]
[New LWP 3642]
[New LWP 3762]
[New LWP 3639]
[New LWP 3637]
[New LWP 3634]
[New LWP 3763]
[New LWP 3643]
[New LWP 3640]
Reading symbols from /usr/lib/jvm/java-1.7.0-openjdk-1.7.0.121-2.6.8.0.el7_3.x86_64/jre-abrt/bin/java...Reading symbols from /usr/lib/debug/usr/lib/jvm/java-1.7.0-openjdk-1.7.0.121-2.6.8.0.el7_3.x86_64/jre-abrt/bin/java.debug...done.
done.
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
Core was generated by `java Test1'.
Program terminated with signal 6, Aborted.
#0  0x00007fd445f1d1d7 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
56        return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig);
(gdb) bt
#0  0x00007fd445f1d1d7 in __GI_raise (sig=sig@entry=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:56
#1  0x00007fd445f1e8c8 in __GI_abort () at abort.c:90
#2  0x00007fd445685ae9 in os::abort(bool) (dump_core=<optimized out>) at /usr/src/debug/java-1.7.0-openjdk-1.7.0.121-2.6.8.0.el7_3.x86_64/openjdk/hotspot/src/os/linux/vm/os_linux.cpp:1640
#3  0x00007fd44581476f in VMError::report_and_die() (this=this@entry=0x7fd446ada9a0)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.121-2.6.8.0.el7_3.x86_64/openjdk/hotspot/src/share/vm/utilities/vmError.cpp:1074
#4  0x00007fd445814ed7 in crash_handler(int, siginfo_t*, void*) (sig=11, info=0x7fd446adabf0, ucVoid=0x7fd446adaac0)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.121-2.6.8.0.el7_3.x86_64/openjdk/hotspot/src/os/linux/vm/vmError_linux.cpp:106
#5  0x00007fd4466ca370 in <signal handler called> () at /usr/lib64/libpthread-2.17.so
#6  0x00007fd4456813c6 in os::is_first_C_frame(frame*) (fr=fr@entry=0x7fd446adb0c0)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.121-2.6.8.0.el7_3.x86_64/openjdk/hotspot/src/share/vm/runtime/os.cpp:1025
#7  0x00007fd4458136c9 in VMError::report(outputStream*) (this=0x7fd446adb810, st=st@entry=0x7fd446adb750)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.121-2.6.8.0.el7_3.x86_64/openjdk/hotspot/src/share/vm/utilities/vmError.cpp:616
#8  0x00007fd4458142e4 in VMError::report_and_die() (this=this@entry=0x7fd446adb810)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.121-2.6.8.0.el7_3.x86_64/openjdk/hotspot/src/share/vm/utilities/vmError.cpp:1008
#9  0x00007fd44568eba7 in JVM_handle_linux_signal(int, siginfo_t*, void*, int) (sig=11, info=0x7fd446adba70, ucVoid=0x7fd446adb940, abort_if_unrecognized=<optimized out>)
    at /usr/src/debug/java-1.7.0-openjdk-1.7.0.121-2.6.8.0.el7_3.x86_64/openjdk/hotspot/src/os_cpu/linux_x86/vm/os_linux_x86.cpp:531
#10 0x00007fd4466ca370 in <signal handler called> () at /usr/lib64/libpthread-2.17.so
#11 0x00007fd44604be71 in __strlen_sse2_pminub () at ../sysdeps/x86_64/multiarch/strlen-sse2-pminub.S:38
#12 0x00007fd413552dc5 in get_java_string (env=0x7fd4400091d8, _string=0x7fd446adbfb8) at HelperSDT.c:13
#13 0x00007fd413553144 in Java_org_systemtap_byteman_helper_HelperSDT_METHOD_1STAP_1PROBE1 (env=0x7fd4400091d8, obj=<optimized out>, _rulename=<optimized out>, _arg1=0x7fd446adbfb8)
    at HelperSDT.c:125
#14 0x00007fd43cbf8e98 in  ()
#15 0x00007fd43c8b50d0 in  ()
#16 0x0000000000000000 in  ()
(gdb) frame 12
#12 0x00007fd413552dc5 in get_java_string (env=0x7fd4400091d8, _string=0x7fd446adbfb8) at HelperSDT.c:13
13        char* string = malloc(strlen( __string)+1);
(gdb) p __string
$1 = 0x0
(gdb)
---------- command line 6 end ----------

I also tested using byteman's jar files from 3.0.6 and 4.0.0-BETA1
using command line 7 shown below. But it did not help.

---------- command line 7 start ----------
# wget https://downloads.jboss.org/byteman/3.0.6/byteman-download-3.0.6-bin.zip
# unzip byteman-download-3.0.6-bin.zip
# find byteman-download-3.0.6 -type f -name '*.jar' -print0 | xargs -0 mv -t /usr/share/java/byteman/ --
---------- command line 7 end ----------

I also tested using Fedora 25. But it did not help.



More information about the Systemtap mailing list