Das Projekt
Ich schreibe eine Java-Befehlszeilenschnittstelle zu einer C-Bibliothek mit internen Netzwerk- und Netzwerktesttools unter Verwendung der Java Native Interface. Der C-Code (den ich nicht geschrieben habe) ist komplex und auf niedriger Ebene, manipuliert häufig den Speicher auf Bitebene und verwendet ausschließlich Raw-Sockets. Die Anwendung ist sowohl auf der C-Seite (pthreads, die im Hintergrund ausgeführt werden) als auch auf der Java-Seite (ScheduledThreadPoolExecutors, die Threads ausführen, die nativen Code aufrufen) multithreaded. Allerdings sollte die C-Bibliothek größtenteils stabil sein. Der Java- und JNI-Schnittstellencode verursacht, wie sich herausstellt, Probleme.
Die Probleme)
Die Anwendung stürzt beim Eintritt in eine native C-Funktion mit einem Segmentierungsfehler ab. Dies geschieht nur, wenn sich das Programm in einem bestimmten Zustand befindet (dh das erfolgreiche Ausführen einer bestimmten nativen Funktion bewirkt, dass der nächste Aufruf einer anderen spezifischen nativen Funktion einen Segfault auslöst). Darüber hinaus stürzt die Anwendung mit einem ähnlich aussehenden Segfault ab, wenn die quit
Befehl ausgegeben, aber auch hier erst nach erfolgreicher Ausführung derselben spezifischen nativen Funktion.
Ich bin ein unerfahrener C-Entwickler und ein erfahrener Java-Entwickler – ich bin es gewohnt, dass Abstürze einen bestimmten Grund und eine bestimmte Zeilennummer angeben. Alles, woran ich in diesem Fall arbeiten muss, ist die hs_err_pid*.log
Ausgabe und den Core-Dump. Ich habe eingeschlossen, was ich am Ende dieser Frage konnte.
Meine bisherige Arbeit
- Natürlich wollte ich die spezifische Codezeile finden, in der der Absturz passiert ist. Ich habe a platziert
System.out.println()
direkt vor dem nativen Aufruf auf der Java-Seite und aprintf()
B. die erste Zeile der nativen Funktion, wo das Programm abstürzt, sicher zu verwendenfflush(stdout)
direkt danach. DasSystem.out
Anruf lief und dieprintf
Anruf nicht. Dies sagt mir, dass der Segfault beim Eintritt in die Funktion aufgetreten ist – etwas, das ich noch nie zuvor gesehen habe. - Ich habe die Parameter der Funktion dreifach überprüft, um sicherzustellen, dass sie nicht funktionieren. Allerdings übergebe ich nur einen Parameter (vom Typ
jint
). Die anderen zwei (JNIEnv *env, jobject j_object
) sind JNI-Konstrukte und außerhalb meiner Kontrolle. - Ich habe jede einzelne Zeile in der Funktion auskommentiert und nur ein übrig gelassen
return 0;
Am Ende. Der Segfault ist immer noch aufgetreten. Dies lässt mich glauben, dass das Problem nicht in dieser Funktion liegt. - Ich habe den Befehl in verschiedenen Reihenfolgen ausgeführt (wobei die nativen Funktionen effektiv in verschiedenen Reihenfolgen ausgeführt wurden). Die Segfaults treten nur auf, wenn eine bestimmte native Funktion vor dem abstürzenden Funktionsaufruf ausgeführt wird. Diese spezielle Funktion scheint sich ordnungsgemäß zu verhalten, wenn sie ausgeführt wird.
- Ich habe den Wert der ausgedruckt
env
Zeiger und der Wert von&j_object
am Ende dieser anderen Funktion, um sicherzustellen, dass ich sie nicht irgendwie beschädigt habe. Ich weiß nicht, ob ich sie beschädigt habe, aber beide haben beim Beenden der Funktion Werte ungleich Null. - Bearbeiten 1: Normalerweise wird dieselbe Funktion in vielen Threads ausgeführt (normalerweise nicht gleichzeitig, aber sie sollte Thread-sicher sein). Ich habe die Funktion vom Hauptthread aus ausgeführt, ohne dass andere Threads aktiv waren, um sicherzustellen, dass Multithreading auf der Java-Seite das Problem nicht verursacht. Es war nicht, und ich bekam den gleichen Segfault.
All das verwirrt mich. Warum ist es immer noch segfault, wenn ich die gesamte Funktion außer der return-Anweisung auskommentiere? Wenn das Problem in dieser anderen Funktion liegt, warum schlägt es dort nicht fehl? Wenn es ein Problem ist, bei dem die erste Funktion den Speicher durcheinander bringt und die zweite Funktion illegal auf den beschädigten Speicher zugreift, warum schlägt dies dann nicht in der Zeile mit dem illegalen Zugriff fehl und nicht beim Eintritt in die Funktion?
Wenn Sie einen Internetartikel sehen, in dem jemand ein ähnliches Problem wie ich erklärt, kommentieren Sie ihn bitte. Es gibt so viele Segfault-Artikel, und keiner scheint dieses spezifische Problem zu enthalten. Dito für SO-Fragen. Das Problem kann auch sein, dass ich nicht erfahren genug bin, um eine abstrakte Lösung für dieses Problem anzuwenden.
Meine Frage
Was kann dazu führen, dass eine native Java-Funktion (in C) bei einem solchen Eintrag segfault? Nach welchen spezifischen Dingen kann ich suchen, die mir helfen, diesen Fehler zu beseitigen? Wie kann ich in Zukunft Code schreiben, der mir hilft, dieses Problem zu vermeiden?
Hilfreiche Informationen
Für das Protokoll, ich kann den Code nicht wirklich posten. Wenn Sie der Meinung sind, dass eine Beschreibung des Codes hilfreich wäre, kommentieren Sie ihn und ich werde ihn bearbeiten.
Fehlermeldung
#
# A fatal error has been detected by the Java Runtime Environment:
#
# SIGSEGV (0xb) at pc=0x00002aaaaaf6d9c3, pid=2185, tid=1086892352
#
# JRE version: 6.0_21-b06
# Java VM: Java HotSpot(TM) 64-Bit Server VM (17.0-b16 mixed mode linux-amd64 )
# Problematic frame:
# j path.to.my.Object.native_function_name(I)I+0
#
# An error report file with more information is saved as:
# /path/to/hs_err_pid2185.log
#
# If you would like to submit a bug report, please visit:
# http://java.sun.com/webapps/bugreport/crash.jsp
# The crash happened outside the Java Virtual Machine in native code.
# See problematic frame for where to report the bug.
#
Die wichtigen Bits der hs_err_pid*.log
Datei
--------------- T H R E A D ---------------
Current thread (0x000000004fd13800): JavaThread "pool-1-thread-1" [_thread_in_native, id=2198, stack(0x0000000040b8a000,0x0000000040c8b000)]
siginfo:si_signo=SIGSEGV: si_errno=0, si_code=128 (), si_addr=0x0000000000000000
Registers:
RAX=0x34372e302e3095e1, RBX=0x00002aaaae39dcd0, RCX=0x0000000000000000, RDX=0x0000000000000000
RSP=0x0000000040c89870, RBP=0x0000000040c898c0, RSI=0x0000000040c898e8, RDI=0x000000004fd139c8
R8 =0x000000004fb631f0, R9 =0x000000004faf5d30, R10=0x00002aaaaaf6d999, R11=0x00002b1243b39580
R12=0x00002aaaae3706d0, R13=0x00002aaaae39dcd0, R14=0x0000000040c898e8, R15=0x000000004fd13800
RIP=0x00002aaaaaf6d9c3, EFL=0x0000000000010202, CSGSFS=0x0000000000000033, ERR=0x0000000000000000
TRAPNO=0x000000000000000d
Stack: [0x0000000040b8a000,0x0000000040c8b000], sp=0x0000000040c89870, free space=3fe0000000000000018k
Native frames: (J=compiled Java code, j=interpreted, Vv=VM code, C=native code)
j path.to.my.Object.native_function_name(I)I+0
j path.to.my.Object$CustomThread.fire()V+18
j path.to.my.CustomThreadSuperClass.run()V+1
j java.util.concurrent.Executors$RunnableAdapter.call()Ljava/lang/Object;+4
j java.util.concurrent.FutureTask$Sync.innerRun()V+30
j java.util.concurrent.FutureTask.run()V+4
j java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Ljava/util/concurrent/ScheduledThreadPoolExecutor$ScheduledFutureTask;)V+1
j java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run()V+15
j java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Ljava/lang/Runnable;)V+59
j java.util.concurrent.ThreadPoolExecutor$Worker.run()V+28
j java.lang.Thread.run()V+11
v ~StubRoutines::call_stub
V [libjvm.so+0x3e756d]
V [libjvm.so+0x5f6f59]
V [libjvm.so+0x3e6e39]
V [libjvm.so+0x3e6eeb]
V [libjvm.so+0x476387]
V [libjvm.so+0x6ee452]
V [libjvm.so+0x5f80df]
Java frames: (J=compiled Java code, j=interpreted, Vv=VM code)
j path.to.my.Object.native_function_name(I)I+0
j path.to.my.Object$CustomThread.fire()V+18
j path.to.my.CustomThreadSuperClass.run()V+1
j java.util.concurrent.Executors$RunnableAdapter.call()Ljava/lang/Object;+4
j java.util.concurrent.FutureTask$Sync.innerRun()V+30
j java.util.concurrent.FutureTask.run()V+4
j java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.access$301(Ljava/util/concurrent/ScheduledThreadPoolExecutor$ScheduledFutureTask;)V+1
j java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run()V+15
j java.util.concurrent.ThreadPoolExecutor$Worker.runTask(Ljava/lang/Runnable;)V+59
j java.util.concurrent.ThreadPoolExecutor$Worker.run()V+28
j java.lang.Thread.run()V+11
v ~StubRoutines::call_stub
--------------- P R O C E S S ---------------
Java Threads: ( => current thread )
0x000000004fabc800 JavaThread "pool-1-thread-6" [_thread_new, id=2203, stack(0x0000000000000000,0x0000000000000000)]
0x000000004fbcb000 JavaThread "pool-1-thread-5" [_thread_blocked, id=2202, stack(0x0000000042c13000,0x0000000042d14000)]
0x000000004fbc9800 JavaThread "pool-1-thread-4" [_thread_blocked, id=2201, stack(0x0000000042b12000,0x0000000042c13000)]
0x000000004fbc7800 JavaThread "pool-1-thread-3" [_thread_blocked, id=2200, stack(0x0000000042a11000,0x0000000042b12000)]
0x000000004fc54800 JavaThread "pool-1-thread-2" [_thread_blocked, id=2199, stack(0x0000000042910000,0x0000000042a11000)]
=>0x000000004fd13800 JavaThread "pool-1-thread-1" [_thread_in_native, id=2198, stack(0x0000000040b8a000,0x0000000040c8b000)]
0x000000004fb04800 JavaThread "Low Memory Detector" daemon [_thread_blocked, id=2194, stack(0x0000000041d0d000,0x0000000041e0e000)]
0x000000004fb02000 JavaThread "CompilerThread1" daemon [_thread_blocked, id=2193, stack(0x0000000041c0c000,0x0000000041d0d000)]
0x000000004fafc800 JavaThread "CompilerThread0" daemon [_thread_blocked, id=2192, stack(0x0000000040572000,0x0000000040673000)]
0x000000004fafa800 JavaThread "Signal Dispatcher" daemon [_thread_blocked, id=2191, stack(0x0000000040471000,0x0000000040572000)]
0x000000004fad6000 JavaThread "Finalizer" daemon [_thread_blocked, id=2190, stack(0x0000000041119000,0x000000004121a000)]
0x000000004fad4000 JavaThread "Reference Handler" daemon [_thread_blocked, id=2189, stack(0x0000000041018000,0x0000000041119000)]
0x000000004fa51000 JavaThread "main" [_thread_in_vm, id=2186, stack(0x00000000418cc000,0x00000000419cd000)]
Other Threads:
0x000000004facf800 VMThread [stack: 0x0000000040f17000,0x0000000041018000] [id=2188]
0x000000004fb0f000 WatcherThread [stack: 0x0000000041e0e000,0x0000000041f0f000] [id=2195]
VM state:not at safepoint (normal execution)
VM Mutex/Monitor currently owned by a thread: None
Heap
PSYoungGen total 305856K, used 31465K [0x00002aaadded0000, 0x00002aaaf3420000, 0x00002aaaf3420000)
eden space 262208K, 12% used [0x00002aaadded0000,0x00002aaadfd8a6a8,0x00002aaaedee0000)
from space 43648K, 0% used [0x00002aaaf0980000,0x00002aaaf0980000,0x00002aaaf3420000)
to space 43648K, 0% used [0x00002aaaedee0000,0x00002aaaedee0000,0x00002aaaf0980000)
PSOldGen total 699072K, used 0K [0x00002aaab3420000, 0x00002aaadded0000, 0x00002aaadded0000)
object space 699072K, 0% used [0x00002aaab3420000,0x00002aaab3420000,0x00002aaadded0000)
PSPermGen total 21248K, used 3741K [0x00002aaaae020000, 0x00002aaaaf4e0000, 0x00002aaab3420000)
object space 21248K, 17% used [0x00002aaaae020000,0x00002aaaae3c77c0,0x00002aaaaf4e0000)
VM Arguments:
jvm_args: -Xms1024m -Xmx1024m -XX:+UseParallelGC
--------------- S Y S T E M ---------------
OS:Red Hat Enterprise Linux Client release 5.5 (Tikanga)
uname:Linux 2.6.18-194.8.1.el5 #1 SMP Wed Jun 23 10:52:51 EDT 2010 x86_64
libc:glibc 2.5 NPTL 2.5
rlimit: STACK 10240k, CORE 102400k, NPROC 10000, NOFILE 1024, AS infinity
load average:0.21 0.08 0.05
CPU:total 1 (1 cores per cpu, 1 threads per core) family 6 model 26 stepping 4, cmov, cx8, fxsr, mmx, sse, sse2, sse3, ssse3, sse4.1, sse4.2, popcnt
Memory: 4k page, physical 3913532k(1537020k free), swap 1494004k(1494004k free)
vm_info: Java HotSpot(TM) 64-Bit Server VM (17.0-b16) for linux-amd64 JRE (1.6.0_21-b06), built on Jun 22 2010 01:10:00 by "java_re" with gcc 3.2.2 (SuSE Linux)
time: Tue Oct 15 15:08:13 2013
elapsed time: 13 seconds
Valgrind-Ausgabe
Ich weiß nicht wirklich, wie man Valgrind richtig benutzt. Das kam beim Laufen raus valgrind app arg1
==2184==
==2184== HEAP SUMMARY:
==2184== in use at exit: 16,914 bytes in 444 blocks
==2184== total heap usage: 673 allocs, 229 frees, 32,931 bytes allocated
==2184==
==2184== LEAK SUMMARY:
==2184== definitely lost: 0 bytes in 0 blocks
==2184== indirectly lost: 0 bytes in 0 blocks
==2184== possibly lost: 0 bytes in 0 blocks
==2184== still reachable: 16,914 bytes in 444 blocks
==2184== suppressed: 0 bytes in 0 blocks
==2184== Rerun with --leak-check=full to see details of leaked memory
==2184==
==2184== For counts of detected and suppressed errors, rerun with: -v
==2184== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 7 from 7)
Bearbeiten 2:
GDB-Ausgabe und Backtrace
Ich habe es mit GDB durchgespielt. Ich habe dafür gesorgt, dass die C-Bibliothek mit kompiliert wurde -g
Flagge.
$ gdb `which java`
GNU gdb (GDB) Red Hat Enterprise Linux (7.0.1-23.el5)
Copyright (C) 2009 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/>...
Reading symbols from /usr/bin/java...(no debugging symbols found)...done.
(gdb) run -jar /opt/scts/scts.jar test.config
Starting program: /usr/bin/java -jar /opt/scts/scts.jar test.config
[Thread debugging using libthread_db enabled]
Executing new program: /usr/lib/jvm/java-1.6.0-sun-1.6.0.21.x86_64/jre/bin/java
[Thread debugging using libthread_db enabled]
[New Thread 0x4022c940 (LWP 3241)]
[New Thread 0x4032d940 (LWP 3242)]
[New Thread 0x4042e940 (LWP 3243)]
[New Thread 0x4052f940 (LWP 3244)]
[New Thread 0x40630940 (LWP 3245)]
[New Thread 0x40731940 (LWP 3246)]
[New Thread 0x40832940 (LWP 3247)]
[New Thread 0x40933940 (LWP 3248)]
[New Thread 0x40a34940 (LWP 3249)]
… mein Programm erledigt etwas Arbeit und startet einen Hintergrundthread …
[New Thread 0x41435940 (LWP 3250)]
… Ich gebe den Befehl ein, der beim nächsten Befehl den Segfault zu verursachen scheint; die neuen Threads werden erwartet …
[New Thread 0x41536940 (LWP 3252)]
[New Thread 0x41637940 (LWP 3253)]
[New Thread 0x41738940 (LWP 3254)]
[New Thread 0x41839940 (LWP 3255)]
[New Thread 0x4193a940 (LWP 3256)]
… Ich gebe den Befehl ein, der den Segfault tatsächlich auslöst. Der neue Thread wird erwartet, da die Funktion in einem eigenen Thread ausgeführt wird. Wenn es keinen Segfault gegeben hätte, hätte es die gleiche Anzahl von Threads wie der vorherige Befehl erstellt …
[New Thread 0x41a3b940 (LWP 3257)]
Program received signal SIGSEGV, Segmentation fault.
[Switching to Thread 0x41839940 (LWP 3255)]
0x00002aaaabcaec45 in ?? ()
… Ich lese wie wild die gdb-Hilfe durch und führe dann den Backtrace aus …
(gdb) bt
#0 0x00002aaaabcaec45 in ?? ()
#1 0x00002aaaf3ad7800 in ?? ()
#2 0x00002aaaf3ad81e8 in ?? ()
#3 0x0000000041838600 in ?? ()
#4 0x00002aaaeacddcd0 in ?? ()
#5 0x0000000041838668 in ?? ()
#6 0x00002aaaeace23f0 in ?? ()
#7 0x0000000000000000 in ?? ()
… Sollte das nicht Symbole haben, wenn ich mit kompiliert habe -g
? Ich habe nach den Zeilen aus der Ausgabe von make
:
gcc -g -Wall -fPIC -c -I ...
gcc -g -shared -W1,soname, ...
Eine der besser formatierten Fragen, die ich seit langem gesehen habe
– Knirscher
15. Oktober 2013 um 20:23 Uhr
Mit dem, was Sie bisher gezeigt haben, habe ich den starken Verdacht, dass Nr. 3 (das Problem liegt woanders) richtig ist. War zum Zeitpunkt des Segfaults eine Garbage Collection im Gange? Eventuell ein anderer Thread?
– ldav1s
15. Oktober 2013 um 20:48 Uhr
Ich habe keine Ahnung, wie ich feststellen kann, ob eine Garbage Collection stattgefunden hat. Wenn es hilft, habe ich sichergestellt, dass die Threads, die die Segfaulting-Funktion ausführen, die einzigen Threads (zusätzlich zum Haupt-Thread) waren, die zu diesem Zeitpunkt in Betrieb waren. Einer der Debugging-Schritte, die ich vergessen habe, war der, bei dem ich die Funktion im Haupt-Thread ausgeführt habe, anstatt im eigenen Thread (mit demselben Segfault-Ergebnis). Ich werde das jetzt bearbeiten.
– Griff George
15. Oktober 2013 um 21:05 Uhr
Auch, wenn jemand eine gute Referenz hat, wo ich nachlesen kann, was alles darin eingetragen ist
hs_err_pid
Datei bedeutet, ich würde es gerne sehen.– Griff George
15. Oktober 2013 um 21:46 Uhr