Was kann dazu führen, dass eine native Java-Funktion (in C) beim Eintritt einen Segfault auslöst?

Lesezeit: 18 Minuten

Benutzer-Avatar
Griff George

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

  1. 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 a printf() B. die erste Zeile der nativen Funktion, wo das Programm abstürzt, sicher zu verwenden fflush(stdout) direkt danach. Das System.out Anruf lief und die printf Anruf nicht. Dies sagt mir, dass der Segfault beim Eintritt in die Funktion aufgetreten ist – etwas, das ich noch nie zuvor gesehen habe.
  2. 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.
  3. 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.
  4. 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.
  5. 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.
  6. 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

Sieht so aus, als hätte ich das Problem gelöst, das ich hier zum Nutzen anderer skizzieren werde.

Was ist passiert

Die Ursache für den Segmentierungsfehler war, dass ich verwendet habe sprintf() a einen Wert zuweisen char * Zeiger, dem kein Wert zugewiesen wurde. Hier ist der schlechte Code:

char* ip_to_string(uint32_t ip)
{
    unsigned char bytes[4];
    bytes[0] = ip & 0xFF;
    bytes[1] = (ip >> 8) & 0xFF;
    bytes[2] = (ip >> 16) & 0xFF;
    bytes[3] = (ip >> 24) & 0xFF;

    char *ip_string;
    sprintf(ip_string, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
    return ip_string;
}

Der Zeiger ip_string hat hier keinen Wert, zeigt also auf nichts. Außer, dass das nicht ganz stimmt. Worauf es hinweist ist nicht definiert. Es könnte überall hin zeigen. Also indem man ihm einen Wert zuweist sprintf(), habe ich versehentlich ein zufälliges Stück Speicher überschrieben. Ich glaube, dass der Grund für das seltsame Verhalten (obwohl ich das nie bestätigt habe) darin bestand, dass der undefinierte Zeiger auf irgendwo auf dem Stapel zeigte. Dies führte dazu, dass der Computer verwirrt wurde, wenn bestimmte Funktionen aufgerufen wurden.

Eine Möglichkeit, dies zu beheben, besteht darin, Speicher zuzuweisen und dann den Zeiger auf diesen Speicher zu zeigen, was damit erreicht werden kann malloc(). Diese Lösung würde ungefähr so ​​​​aussehen:

char* ip_to_string(uint32_t ip)
{
    unsigned char bytes[4];
    bytes[0] = ip & 0xFF;
    bytes[1] = (ip >> 8) & 0xFF;
    bytes[2] = (ip >> 16) & 0xFF;
    bytes[3] = (ip >> 24) & 0xFF;

    char *ip_string = malloc(16);
    sprintf(ip_string, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
    return ip_string;
}

Das Problem dabei ist, dass jeder malloc() muss durch einen Aufruf an abgeglichen werden free(), oder Sie haben ein Speicherleck. Wenn ich anrufe free(ip_string) Innerhalb dieser Funktion ist der zurückgegebene Zeiger nutzlos, und wenn ich das nicht tue, muss ich mich auf den Code verlassen, der diese Funktion aufruft, um den Speicher freizugeben, was ziemlich gefährlich ist.

Soweit ich das beurteilen kann, besteht die “richtige” Lösung darin, einen bereits zugewiesenen Zeiger an die Funktion zu übergeben, sodass es in der Verantwortung der Funktion liegt, auf den Speicher zu füllen. Auf diese Weise Anrufe an malloc() und free() kann im Codeblock vorgenommen werden. Viel sicherer. Hier die neue Funktion:

char* ip_to_string(uint32_t ip, char *ip_string)
{
    unsigned char bytes[4];
    bytes[0] = ip & 0xFF;
    bytes[1] = (ip >> 8) & 0xFF;
    bytes[2] = (ip >> 16) & 0xFF;
    bytes[3] = (ip >> 24) & 0xFF;

    sprintf(ip_string, "%d.%d.%d.%d", bytes[0], bytes[1], bytes[2], bytes[3]);
    return ip_string;
}

Antworten auf die Fragen

Was kann dazu führen, dass eine native Java-Funktion (in C) bei einem solchen Eintrag segfault?

Wenn Sie einem Zeiger, dem noch kein Speicher zugewiesen wurde, einen Wert zuweisen, können Sie versehentlich Speicher auf dem Stack überschreiben. Dies führt möglicherweise nicht zu einem sofortigen Fehler, verursacht jedoch wahrscheinlich Probleme, wenn Sie später andere Funktionen aufrufen.

Nach welchen spezifischen Dingen kann ich suchen, die mir helfen, diesen Fehler zu beseitigen?

Suchen Sie nach einem Segmentierungsfehler wie jedem anderen. Dinge wie das Zuweisen eines Werts zu nicht zugeordnetem Speicher oder das Dereferenzieren eines Nullzeigers. Ich bin kein Experte auf diesem Gebiet, aber ich wette, dass es welche gibt viele Webressourcen dafür.

Wie kann ich in Zukunft Code schreiben, der mir hilft, dieses Problem zu vermeiden?

Seien Sie vorsichtig mit Zeigern, insbesondere wenn Sie für deren Erstellung verantwortlich sind. Wenn Sie eine Codezeile sehen, die so aussieht:

type *variable;

… suchen Sie dann nach einer Zeile, die aussieht wie …

variable = ...;

… und stellen Sie sicher, dass diese Zeile vor dem Schreiben in den Speicher kommt, auf den gezeigt wird.

  • Ja, C verzeiht viel weniger, wenn es um nicht initialisierte Variablen geht und den Speicherbesitz zwischen Stack-Frames verwaltet. Ich bin eigentlich ziemlich überrascht, dass Valgrind das nicht bemerkt hat – vielleicht haben Sie es nicht lange genug ausgeführt, um die Fehlerbedingung zu erreichen? Das Ausführen eines Programms unter Valgrind macht eine Größenordnung langsamer, da es so ziemlich so ist, als würde der Code in einem Emulator ausgeführt.

    – Adam Rosenfield

    17. Oktober 2013 um 1:41 Uhr

  • @Adam Ich würde gerne mehr darüber erfahren, wie man Valgrind bedient. Was ich in der ursprünglichen Frage gepostet habe, war das, was unmittelbar nach dem Auftreten des Segfaults auftauchte (dh die Segfault-Fehlermeldung erschien zuerst und dann die Valgrind-Ausgabe). Ich vermute, dass ich es nicht mit den richtigen Argumenten oder mit den richtigen aktivierten Valgrind-Tools ausgeführt habe.

    – Griff George

    17. Oktober 2013 um 14:00 Uhr

  • Sowohl GCC als auch Clang warnen in hohen Warnstufen davor.

    – Demi

    11. November 2015 um 10:14 Uhr

Haben Sie versucht, GDB an die JVM anzuschließen?

Um dies zu tun:

  1. Führen Sie GDB gegen die Binärdatei der JVM aus. (/usr/bin/java, oder welche JVM Sie auch verwenden)
  2. Legen Sie die Argumente in GDB als die Argumente fest, die Sie an Ihre JVM übergeben
  3. Erstellen Sie den Segfault neu. Das klingt so, als wäre dies wiederholbar.

Sie sollten in der Lage sein, die Anwendung auszuführen und sie im defekten Zustand zu erhalten. Sobald es dort ist, sollte GDB an der Stelle brechen, an der es einen Seg-Fehler hatte, und Sie können möglicherweise einen Stack-Trace erhalten. Stellen Sie sicher, dass die Bibliothek mit Debug-Symbolen kompiliert ist, damit Sie die Methodenaufrufe und Zeilennummern sehen können.

  • Ich werde versuchen, herauszufinden, wie das geht. Ich habe GDB noch nie benutzt. Welchen Vorteil hat in der Zwischenzeit ein GDB-Stack-Trace, den der Stack-Trace am Ende meiner Frage nicht hat?

    – Griff George

    15. Oktober 2013 um 21:12 Uhr

  • Um ehrlich zu sein, vielleicht nicht. Ich denke, es wäre ein guter Gesundheitstest, um zu sehen, ob Sie auf den richtigen Code zugreifen. Es kann Ihnen auch mehr über den Seg-Fehler sagen.

    – lordoku

    15. Oktober 2013 um 21:35 Uhr

  • @iordoku Ich habe das Ende der Frage mit der gdb-Ausgabe und dem Backtrace bearbeitet. Ich bin mir nicht sicher, ob Sie dort mehr gesucht haben, aber es scheint mir nicht, dass es viel zu bieten hat. Gibt es noch etwas, das ich in GDB hätte tun sollen, damit ich nicht alle bekomme ??‘s?

    – Griff George

    15. Oktober 2013 um 21:40 Uhr

  • Entschuldigung, dass die Ausgabe nicht geholfen hat. Ich bin verwirrt darüber, warum die Debug-Symbole nicht angezeigt wurden, aber ich bin froh, dass Sie etwas finden konnten. Es ist auch eine gute Arbeit, diese Seite mit Ihren Ergebnissen auf dem neuesten Stand zu halten.

    – lordoku

    22. Oktober 2013 um 20:49 Uhr

  • Könnte es sein, dass ich den Speicher im Stack überschrieben habe und dadurch die Rückverfolgung beschädigt habe?

    – Griff George

    24. Oktober 2013 um 2:36 Uhr

Benutzer-Avatar
Benutzer2654836

Wie kann ich in Zukunft Code schreiben, der mir hilft, dieses Problem zu vermeiden?

Sie können gegen NULL initialisieren/validieren, das ist eine bewährte Methode in C.

Übrigens, endet die IP, die Sie sprinten, mit: 47.0.0 ? Das enthält einen Teil des RAX-Registers in Hex:

RAX=0x34372e302e3095e1

Obwohl sprintf nach der letzten Zahl ein NULL-Zeichen hätte hinzufügen sollen.

1362810cookie-checkWas kann dazu führen, dass eine native Java-Funktion (in C) beim Eintritt einen Segfault auslöst?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy