2014-01-30 9 views
5

Hier ist ein Stück Code, das ich habe zu kompilieren versucht:Super seltsame segfault mit gcc 4.7 - Bug?

#include <cstdio> 

#define N 3 

struct Data { 
    int A[N][N]; 
    int B[N]; 
}; 

int foo(int uloc, const int A[N][N], const int B[N]) 
{ 
    for(unsigned int j = 0; j < N; j++) { 
     for(int i = 0; i < N; i++) { 
      for(int r = 0; r < N ; r++) { 
       for(int q = 0; q < N ; q++) { 
        uloc += B[i]*A[r][j] + B[j]; 
       } 
      } 
     } 
    } 
    return uloc; 
} 

int apply(const Data *d) 
{ 
    return foo(4,d->A,d->B); 
} 

int main(int, char **) 
{ 
    Data d; 
    for(int i = 0; i < N; ++i) { 
     for(int j = 0; j < N; ++j) { 
      d.A[i][j] = 0.0; 
     } 
     d.B[i] = 0.0; 
    } 

    int res = 11 + apply(&d); 

    printf("%d\n",res); 
    return 0; 
} 

Ja, es ziemlich seltsam aussieht, und im Moment etwas Sinnvolles überhaupt nicht tut, aber es ist die knappste Version von einem viel größeren Programm, mit dem ich anfangs das Problem hatte.

Es kompiliert und läuft nur mit GCC (G ++) fein 4.4 und 4.6, aber wenn ich GCC verwenden 4.7 und dritte Ebene Optimierungen ermöglichen:

g++-4.7 -g -O3 prog.cpp -o prog 

ich einen Segmentation Fault erhalten, wenn es ausgeführt wird. GDB nicht wirklich viele Informationen geben, was schief gelaufen ist:

(gdb) run 
Starting program: /home/kalle/work/code/advect_diff/c++/strunt 

Program received signal SIGSEGV, Segmentation fault. 
apply ([email protected]=0x7fffffffe1a0) at src/strunt.cpp:25 
25  int apply(const Data *d) 
(gdb) bt 
#0 apply ([email protected]=0x7fffffffe1a0) at src/strunt.cpp:25 
#1 0x00000000004004cc in main() at src/strunt.cpp:34 

Ich habe versucht, den Code auf unterschiedliche Weise zwicken, um zu sehen, ob der Fehler verschwindet. Es scheint notwendig zu sein, alle vier Schleifenebenen in foo zu haben, und ich war nicht in der Lage, sie durch eine einzige Ebene von Funktionsaufrufen zu reproduzieren. Oh ja, die äußerste Schleife muss einen vorzeichenlosen Schleifenindex verwenden.

Ich fange an zu vermuten, dass dies ein Fehler im Compiler oder in der Laufzeit ist, da es für Version 4.7 spezifisch ist und ich nicht sehen kann, welche Speicherzugriffe ungültig sind.

Jeder Einblick in das, was vor sich geht, würde sehr geschätzt werden.

Es ist möglich, die gleiche Situation mit der C-Version von GCC mit einer leichten Änderung des Codes zu erhalten.

Mein System ist:

Debian sid Linux 3.2.0-4-amd64 GCC 4.7.2-5


Okay, so habe ich mir die Demontage von GDB angeboten, aber ich hab angst das es mir nicht viel sagt:

Dump of assembler code for function apply(Data const*): 
    0x0000000000400760 <+0>: push %r13 
    0x0000000000400762 <+2>: movabs $0x400000000,%r8 
    0x000000000040076c <+12>: push %r12 
    0x000000000040076e <+14>: push %rbp 
    0x000000000040076f <+15>: push %rbx 
    0x0000000000400770 <+16>: mov 0x24(%rdi),%ecx 
=> 0x0000000000400773 <+19>: mov (%rdi,%r8,1),%ebp 
    0x0000000000400777 <+23>: mov 0x18(%rdi),%r10d 
    0x000000000040077b <+27>: mov $0x4,%r8b 
    0x000000000040077e <+30>: mov 0x28(%rdi),%edx 
    0x0000000000400781 <+33>: mov 0x2c(%rdi),%eax 
    0x0000000000400784 <+36>: mov %ecx,%ebx 
    0x0000000000400786 <+38>: mov (%rdi,%r8,1),%r11d 
    0x000000000040078a <+42>: mov 0x1c(%rdi),%r9d 
    0x000000000040078e <+46>: imul %ebp,%ebx 
    0x0000000000400791 <+49>: mov $0x8,%r8b 
    0x0000000000400794 <+52>: mov 0x20(%rdi),%esi 

Was soll ich sehen wenn ich mir das anschaue?


Bearbeiten 2015-08-13: Dies scheint in g ++ 4.8 und später behoben werden.

+1

Ja, es ist ein Fehler. Sehen Sie sich die generierte Assembly von dort an, wo sie segmentiert. – PlasmaHH

+0

Ich wusste, dass Sie Argumentnamen in einem Funktionsprototyp auslassen können, aber ich habe nie gesehen, dass jemand die Namen in einer tatsächlichen Funktionsdefinition ausgelassen hat. – user2357112

+1

sieht aus wie es mit 4,6 entweder: http://coliru.stacked-crooked.com/a/1d50e7c5360796e6 – marcinj

Antwort

2

Es ist tatsächlich und leider ein Fehler in gcc. Ich habe nicht die geringste Ahnung, was es dort macht, aber die generierte Assembly für die Apply-Funktion ist (ich kompilierte es ohne Haupt-BTW.Und es foo inlined in sich hat):

_Z5applyPK4Data: 
     pushq %r13 
     movabsq $17179869184, %r8 
     pushq %r12 
     pushq %rbp 
     pushq %rbx 
     movl 36(%rdi), %ecx 
     movl (%rdi,%r8), %ebp 
     movl 24(%rdi), %r10d 

und genau an der movl (%rdi,%r8), %ebp es wird abstürzt, da es eine unsinnige 0x400000000 zu $rdi (der ersten Parameter addiert, damit der Zeiger auf Data) und dereferenziert es.

6

Sie haben nie d initialisiert. Sein Wert ist unbestimmt und der Versuch, mit seinen Inhalten Mathe zu machen, ist undefiniertes Verhalten. (Auch wenn Sie versuchen, seine Werte zu lesen, ohne etwas damit zu tun, ist ein undefiniertes Verhalten.) Initialisieren Sie d und sehen Sie, was passiert.


Nun, da Sie d initialisiert haben und es immer noch nicht, sieht das wie ein echter Compiler-Fehler. Versuchen Sie, auf 4.7.3 oder 4.8.2 zu aktualisieren; Wenn das Problem weiterhin besteht, reichen Sie einen Fehlerbericht ein. (Die Liste der bekannten Fehler scheint derzeit leer zu sein, oder zumindest der Link führt irgendwo nur Nicht-Fehler auf.)

+1

würde keinen segfault verursachen, oder mit anderen Worten, die Initialisierung wird auch den segfault verursachen – PlasmaHH

+4

@PlasmaHH: Der Compiler kann frei beobachten, dass 'd' niemals initialisiert wird, angenommen, dass es nie benutzt wird, und nicht die Mühe, es zuzuweisen irgendwo darf das Programm lesen. Wenn das Programm immer noch segregiert, wenn "d" initialisiert ist, dann ist es ein Compilerfehler. – user2357112

+0

Könnte der Downvoter uns bitte aufklären? – Bathsheba