2014-01-30 50 views
5

下面是一段代碼,我一直在試圖編譯:超級奇怪段錯誤與海灣合作委員會4.7 - 錯誤?

#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; 
} 

是的,這看起來很奇怪,在所有的時刻沒有做什麼有用的,但它是最簡潔的版本我最初遇到問題的一個更大的程序。

它編譯和運行只需用GCC(G ++)4.4和4.6罰款,但如果我使用GCC 4.7,並啓用第三級優化:

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

我運行時,它得到一個分段錯誤。 GDB並沒有真正給出了什麼差錯多的信息:

(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 

我試着調整方式不同的代碼,看看錯誤消失。似乎有必要在foo中擁有所有四個循環級別,並且我無法通過調用一個函數級別來重現它。哦,是的,最外層的循環必須使用無符號循環索引。

我開始懷疑這是編譯器或運行時的錯誤,因爲它特定於版本4.7,我無法看到哪些內存訪問無效。

任何深入瞭解正在發生的事情將非常感激。

通過對代碼進行輕微修改,可以獲得與G-C版本相同的情況。

我的系統是:

Debian的喘息 的Linux 3.2.0-4,AMD64 GCC 4.7.2-5


好了,所以我看着由GDB提供的拆卸,但我對我來說恐怕不多說:

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 

我看到這個時應該看到什麼?


編輯2015-08-13:這似乎是固定在g ++ 4.8和更高版本。

+1

是的,它的一個錯誤。看看它在段落所在位置生成的組件。 – PlasmaHH

+0

我知道你可以省略函數原型中的參數名稱,但我從來沒有見過任何人在實際函數定義中省略過名稱。 – user2357112

+1

看起來像4.6失敗一樣:http://coliru.stacked-crooked.com/a/1d50e7c5360796e6 – marcinj

回答

2

確實不幸的是它是gcc中的一個錯誤。我沒有絲毫的想法,它在那裏做什麼,但爲apply函數生成的程序集是(我編譯它沒有主要的btw。,並且它具有在FOO它內聯):

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

和正好在movl (%rdi,%r8), %ebp它會崩潰,因爲它增加了一個無意義0x400000000$rdi(第一個參數,從而指針Data)和解引用它。

6

您從未初始化d。它的價值是不確定的,試圖用它的內容做數學是未定義的行爲。 (甚至試圖讀取它的值而不做任何事情都是未定義的行爲。)初始化d,看看會發生什麼。


現在你已經初始化d,它仍然失敗,看起來像一個真正的編譯器錯誤。嘗試更新至4.7.3或4.8.2;如果問題仍然存在,請提交錯誤報告。 (已知錯誤列表目前似乎爲空,或者至少鏈接正在某處僅列出非錯誤。)

+1

不會導致段錯誤,或者換句話說,初始化也會導致段錯誤 – PlasmaHH

+4

@PlasmaHH:編譯器可以自由地觀察到'd'永遠不會被初始化,假設它永遠不會被使用,而且也懶得實際分配它程序允許讀取的地方。如果程序在初始化'd'時仍然存在段錯誤,那麼*這是一個編譯器錯誤。 – user2357112

+0

請問downvoter請賜教嗎? – Bathsheba

相關問題