2015-07-13 13 views
5

Ho problemi a determinare la causa di un segfault quando un programma è compilato con -O3 con GCC 4.8/4.9/5.1. Per GCC 4.9.x, l'ho visto su Cygwin, Debian 8 (x64) e Fedora 21 (x64). Altri lo hanno sperimentato su GCC 4.8 and 5.1.Determinare la causa del segfault quando si utilizza -O3?

Il programma va bene con -O2, va bene con altre versioni di GCC e va bene con altri compilatori (come MSVC, ICC e Clang).

Di seguito è riportato l'arresto anomalo sotto GDB, ma nulla mi sta saltando addosso. Il codice sorgente da misc.cpp:26 è al di sotto, ma è un semplice XOR:

((word64*)buf)[i] ^= ((word64*)mask)[i]; 

Il codice in questione i controlli per l'allineamento di parola a 64 bit prima al cast. Dal disassemblaggio sotto -O3, so che ha qualcosa a che fare con l'istruzione vmovdqa:

(gdb) disass 0x0000000000539fc3 
... 

    0x0000000000539fbc <+220>: vxorps 0x0(%r13,%r10,1),%ymm0,%ymm0 
=> 0x0000000000539fc3 <+227>: vmovdqa %ymm0,0x0(%r13,%r10,1) 
    0x0000000000539fca <+234>: add $0x20,%r10 

Sembra GCC sta usando vettori vento -O3, e non li utilizzano a -O2. (Grazie ad Alejandro per il suggerimento).

Ho intenzione di chiedere ingenuamente: il vmovdqa ha requisiti di allineamento superiori alla parola a 64 bit? È così, perché GCC lo seleziona quando le parole non sono allineate a 128 bit?

Che cosa sta causando il segfault qui? Come posso risolverlo ulteriormente?


Vedere anche Bug 66852 - vmovdqa instructions issued on 64-bit aligned array, causes segfault. È stato archiviato in risposta a questo problema, quindi non è confermato al momento.


$ gdb ./cryptest.exe 
GNU gdb (Debian 7.7.1+dfsg-5) 7.7.1 
... 
(gdb) r v 
... 
Testing MessageDigest algorithm SHA-3-224. 
..... 
Program received signal SIGSEGV, Segmentation fault. 
0x0000000000539fc3 in CryptoPP::xorbuf (buf=0x98549a "efghijde", 
    [email protected]=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' <repeats 106 times>..., [email protected]=0x5e) at misc.cpp:26 
26     ((word64*)buf)[i] ^= ((word64*)mask)[i]; 

(gdb) where 
#0 0x0000000000539fc3 in CryptoPP::xorbuf (buf=0x98549a "efghijde", 
    [email protected]=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' <repeats 106 times>..., [email protected]=0x5e) at misc.cpp:26 
#1 0x0000000000561eb0 in CryptoPP::SHA3::Update (this=0x985480, 
    input=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' <repeats 106 times>..., 
    length=0x5e) at sha3.cpp:264 
#2 0x00000000005bac1a in CryptoPP::HashVerificationFilter::NextPutMultiple (
    this=0x7fffffffd390, 
    inString=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' <repeats 106 times>..., 
    length=0x5e) at filters.cpp:786 
#3 0x00000000005bd8a2 in NextPutMaybeModifiable (modifiable=<optimized out>, 
    length=0x5e, 
    inString=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' <repeats 106 times>..., 
    this=0x7fffffffd390) at filters.h:200 
#4 CryptoPP::FilterWithBufferedInput::PutMaybeModifiable (
    this=0x7fffffffd390, 
    inString=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' <repeats 106 times>..., 
    length=<optimized out>, messageEnd=0x0, blocking=<optimized out>, 
... 

-O3 smontaggio e registrare i valori.

(gdb) disass 0x0000000000539fc3 
Dump of assembler code for function CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long): 
    0x0000000000539ee0 <+0>: lea 0x8(%rsp),%r10 
    0x0000000000539ee5 <+5>: and $0xffffffffffffffe0,%rsp 
    0x0000000000539ee9 <+9>: mov %rdx,%rax 
    0x0000000000539eec <+12>: pushq -0x8(%r10) 
    0x0000000000539ef0 <+16>: push %rbp 
    0x0000000000539ef1 <+17>: shr $0x3,%rax 
    0x0000000000539ef5 <+21>: mov %rsp,%rbp 
    0x0000000000539ef8 <+24>: push %r15 
    0x0000000000539efa <+26>: push %r14 
    0x0000000000539efc <+28>: push %r13 
    0x0000000000539efe <+30>: push %r12 
    0x0000000000539f00 <+32>: push %r10 
    0x0000000000539f02 <+34>: push %rbx 
    0x0000000000539f03 <+35>: je  0x53a00a <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+298> 
    0x0000000000539f09 <+41>: lea 0x20(%rdi),%rcx 
    0x0000000000539f0d <+45>: cmp %rcx,%rsi 
    0x0000000000539f10 <+48>: lea 0x20(%rsi),%rcx 
    0x0000000000539f14 <+52>: setae %r8b 
    0x0000000000539f18 <+56>: cmp %rcx,%rdi 
    0x0000000000539f1b <+59>: setae %cl 
    0x0000000000539f1e <+62>: or  %cl,%r8b 
    0x0000000000539f21 <+65>: je  0x53a300 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+1056> 
    0x0000000000539f27 <+71>: cmp $0x8,%rax 
    0x0000000000539f2b <+75>: jbe 0x53a300 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+1056> 
    0x0000000000539f31 <+81>: mov %rdi,%rcx 
    0x0000000000539f34 <+84>: and $0x1f,%ecx 
    0x0000000000539f37 <+87>: shr $0x3,%rcx 
    0x0000000000539f3b <+91>: neg %rcx 
    0x0000000000539f3e <+94>: and $0x3,%ecx 
    0x0000000000539f41 <+97>: cmp %rax,%rcx 
    0x0000000000539f44 <+100>: cmova %rax,%rcx 
    0x0000000000539f48 <+104>: xor %r8d,%r8d 
    0x0000000000539f4b <+107>: test %rcx,%rcx 
    0x0000000000539f4e <+110>: je  0x539f80 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+160> 
    0x0000000000539f50 <+112>: mov (%rsi),%r8 
    0x0000000000539f53 <+115>: xor %r8,(%rdi) 
    0x0000000000539f56 <+118>: cmp $0x1,%rcx 
    0x0000000000539f5a <+122>: je  0x53a371 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+1169> 
    0x0000000000539f60 <+128>: mov 0x8(%rsi),%r8 
    0x0000000000539f64 <+132>: xor %r8,0x8(%rdi) 
    0x0000000000539f68 <+136>: cmp $0x3,%rcx 
    0x0000000000539f6c <+140>: jne 0x53a366 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+1158> 
    0x0000000000539f72 <+146>: mov 0x10(%rsi),%r8 
    0x0000000000539f76 <+150>: xor %r8,0x10(%rdi) 
    0x0000000000539f7a <+154>: mov $0x3,%r8d 
    0x0000000000539f80 <+160>: mov %rax,%r11 
    0x0000000000539f83 <+163>: xor %r10d,%r10d 
    0x0000000000539f86 <+166>: sub %rcx,%r11 
    0x0000000000539f89 <+169>: shl $0x3,%rcx 
    0x0000000000539f8d <+173>: xor %ebx,%ebx 
    0x0000000000539f8f <+175>: lea -0x4(%r11),%r9 
    0x0000000000539f93 <+179>: lea (%rdi,%rcx,1),%r13 
    0x0000000000539f97 <+183>: shr $0x2,%r9 
    0x0000000000539f9b <+187>: add %rsi,%rcx 
    0x0000000000539f9e <+190>: add $0x1,%r9 
    0x0000000000539fa2 <+194>: lea 0x0(,%r9,4),%r12 
    0x0000000000539faa <+202>: add $0x1,%rbx 
    0x0000000000539fae <+206>: vmovdqu (%rcx,%r10,1),%xmm0 
    0x0000000000539fb4 <+212>: vinsertf128 $0x1,0x10(%rcx,%r10,1),%ymm0,%ymm0 
    0x0000000000539fbc <+220>: vxorps 0x0(%r13,%r10,1),%ymm0,%ymm0 
=> 0x0000000000539fc3 <+227>: vmovdqa %ymm0,0x0(%r13,%r10,1) 
    0x0000000000539fca <+234>: add $0x20,%r10 
    0x0000000000539fce <+238>: cmp %r9,%rbx 
    0x0000000000539fd1 <+241>: jb  0x539faa <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+202> 
    0x0000000000539fd3 <+243>: lea (%r8,%r12,1),%rcx 
    0x0000000000539fd7 <+247>: cmp %r12,%r11 
    0x0000000000539fda <+250>: je  0x53a006 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+294> 
    0x0000000000539fdc <+252>: mov (%rsi,%rcx,8),%r8 
    0x0000000000539fe0 <+256>: xor %r8,(%rdi,%rcx,8) 
    0x0000000000539fe4 <+260>: lea 0x1(%rcx),%r8 
    0x0000000000539fe8 <+264>: cmp %r8,%rax 
    0x0000000000539feb <+267>: jbe 0x53a006 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+294> 
    0x0000000000539fed <+269>: add $0x2,%rcx 
    0x0000000000539ff1 <+273>: mov (%rsi,%r8,8),%r9 
    0x0000000000539ff5 <+277>: xor %r9,(%rdi,%r8,8) 
    0x0000000000539ff9 <+281>: cmp %rcx,%rax 
    0x0000000000539ffc <+284>: jbe 0x53a006 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+294> 
    0x0000000000539ffe <+286>: mov (%rsi,%rcx,8),%r8 
    0x000000000053a002 <+290>: xor %r8,(%rdi,%rcx,8) 
    0x000000000053a006 <+294>: shl $0x3,%rax 

E:

(gdb) info r ymm0 r13 r10 
ymm0   {v8_float = {0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0}, 
    v4_double = {0x8000000000000000, 0x8000000000000000, 0x8000000000000000, 
    0x8000000000000000}, v32_int8 = {0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x65, 
    0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x66, 0x67, 0x68, 0x69, 0x6a, 
    0x6b, 0x6c, 0x6d, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x68, 
    0x69}, v16_int16 = {0x6766, 0x6968, 0x6b6a, 0x6665, 0x6867, 0x6a69, 
    0x6c6b, 0x6766, 0x6968, 0x6b6a, 0x6d6c, 0x6867, 0x6a69, 0x6c6b, 0x6e6d, 
    0x6968}, v8_int32 = {0x69686766, 0x66656b6a, 0x6a696867, 0x67666c6b, 
    0x6b6a6968, 0x68676d6c, 0x6c6b6a69, 0x69686e6d}, v4_int64 = { 
    0x66656b6a69686766, 0x67666c6b6a696867, 0x68676d6c6b6a6968, 
    0x69686e6d6c6b6a69}, v2_int128 = {0x67666c6b6a69686766656b6a69686766, 
    0x69686e6d6c6b6a6968676d6c6b6a6968}} 
r13   0x9854a2 0x9854a2 
r10   0x0 0x0 

Quando compilato con -O2 e un punto di interruzione sulla linea in questione, ecco il disassemblaggio. ((word64*)buf)[i] ^= ((word64*)mask)[i]; spostato alla linea 31:

Breakpoint 1, CryptoPP::xorbuf (buf=0x985488 "", 
    [email protected]=0x7fffffffc01d "The quick brown fox", 'a' <repeats 181 times>..., [email protected]=0x13) at misc.cpp:31 
31     ((word64*)buf)[i] ^= ((word64*)mask)[i]; 
(gdb) disass 
Dump of assembler code for function CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long): 
    0x0000000000532150 <+0>: mov %rdx,%rcx 
    0x0000000000532153 <+3>: shr $0x3,%rcx 
    0x0000000000532157 <+7>: je  0x532170 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+32> 
    0x0000000000532159 <+9>: xor %eax,%eax 
=> 0x000000000053215b <+11>: mov (%rsi,%rax,8),%r8 
    0x000000000053215f <+15>: xor %r8,(%rdi,%rax,8) 
    0x0000000000532163 <+19>: add $0x1,%rax 
    0x0000000000532167 <+23>: cmp %rcx,%rax 
    0x000000000053216a <+26>: jne 0x53215b <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+11> 
    0x000000000053216c <+28>: shl $0x3,%rcx 
    0x0000000000532170 <+32>: sub %rcx,%rdx 
    0x0000000000532173 <+35>: je  0x5321d0 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+128> 
    0x0000000000532175 <+37>: mov %rdx,%r8 
    0x0000000000532178 <+40>: add %rcx,%rdi 
    0x000000000053217b <+43>: add %rcx,%rsi 
    0x000000000053217e <+46>: shr $0x2,%r8 
    0x0000000000532182 <+50>: je  0x5321a8 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+88> 
    0x0000000000532184 <+52>: xor %eax,%eax 
    0x0000000000532186 <+54>: nopw %cs:0x0(%rax,%rax,1) 
    0x0000000000532190 <+64>: mov (%rsi,%rax,4),%ecx 
    0x0000000000532193 <+67>: xor %ecx,(%rdi,%rax,4) 
    0x0000000000532196 <+70>: add $0x1,%rax 
    0x000000000053219a <+74>: cmp %r8,%rax 
    0x000000000053219d <+77>: jne 0x532190 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+64> 
    0x000000000053219f <+79>: shl $0x2,%r8 
    0x00000000005321a3 <+83>: sub %r8,%rdx 
    0x00000000005321a6 <+86>: je  0x5321d8 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+136> 
    0x00000000005321a8 <+88>: lea (%rdi,%r8,1),%rcx 
    0x00000000005321ac <+92>: xor %eax,%eax 
    0x00000000005321ae <+94>: lea (%rsi,%r8,1),%rdi 
    0x00000000005321b2 <+98>: nopw 0x0(%rax,%rax,1) 
    0x00000000005321b8 <+104>: movzbl (%rdi,%rax,1),%esi 
    0x00000000005321bc <+108>: xor %sil,(%rcx,%rax,1) 
    0x00000000005321c0 <+112>: add $0x1,%rax 
    0x00000000005321c4 <+116>: cmp %rdx,%rax 
    0x00000000005321c7 <+119>: jb  0x5321b8 <CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long)+104> 
    0x00000000005321c9 <+121>: retq 
    0x00000000005321ca <+122>: nopw 0x0(%rax,%rax,1) 
    0x00000000005321d0 <+128>: retq 
    0x00000000005321d1 <+129>: nopl 0x0(%rax) 
    0x00000000005321d8 <+136>: retq 
End of assembler dump. 

Da misc.cpp, linea 26 è ((word64*)buf)[i] ^= ((word64*)mask)[i];.

void xorbuf(byte *buf, const byte *mask, size_t count) 
{ 
    size_t i; 

    if (IsAligned<word32>(buf) && IsAligned<word32>(mask)) 
    { 
     if (!CRYPTOPP_BOOL_SLOW_WORD64 && IsAligned<word64>(buf) && IsAligned<word64>(mask)) 
     { 
      for (i=0; i<count/8; i++) 
       ((word64*)buf)[i] ^= ((word64*)mask)[i]; 
      count -= 8*i; 
      if (!count) 
       return; 
      buf += 8*i; 
      mask += 8*i; 
     } 

     for (i=0; i<count/4; i++) 
      ((word32*)buf)[i] ^= ((word32*)mask)[i]; 
     count -= 4*i; 
     if (!count) 
      return; 
     buf += 4*i; 
     mask += 4*i; 
    } 

    for (i=0; i<count; i++) 
     buf[i] ^= mask[i]; 
} 
+0

A quanto spazio punta 'buf'? Ti sei assicurato che non stai semplicemente scrivendo la fine? Sembra sospettosamente come se fosse un cstring lungo 8 caratteri ... strano che l'errore sembra verificarsi proprio mentre sta per scrivere 8 byte a partire da quello che potrebbe essere il terminatore null ... – user657267

+1

@ user657267 - Sì, il codice sta rispettando dimensioni del buffer Ho anche processi in atto per convalidarlo durante i test. Vale a dire, disinfettanti Clang e Valgrind. Mi sto preparando ad aggiungere Coverity poiché questo è un progetto Open Source. (Adoro le analisi statiche e dinamiche). – jww

+0

@jww Puoi disattivare completamente i blocchi iniziali e lasciare solo l'ultimo ciclo "byte alla volta" alla fine? Quindi compilare di nuovo con '-O3'? Forse non è la stessa funzione a fare qualcosa di strano - forse il modo in cui gli argomenti hanno preso non è giusto. – viraptor

risposta

4

È possibile compilare con g++ -Wall -Wextra -O3 -g; si desidera abilitare gli avvisi, poiché alcuni di essi possono essere generati solo nei passaggi GCC abilitati con -O3; si desidera abilitare le informazioni di debug (-g) per utilizzare gdb ma tenere presente che le informazioni di debug non sono sempre affidabili con forti ottimizzazioni.

Potrebbero esserci dei problemi pointer aliasing. Forse usare (o rimuovere) la parola chiave restrict.

Assicurarsi di evitare undefined behavior. È possibile utilizzare le opzioni -fsanitize= (in particolare -fsanitize=address e -fsanitize=undefined ....) nel compilatore g++ (preferibilmente nella versione 5) Utilizzare anche valgrind.

BTW, è possibile utilizzare le opzioni di dump come -fdump-tree-all (avviso, producono centinaia di file!) Per comprendere meglio il comportamento interno di g++; e potresti perfino personalizzare il tuo compilatore GCC con MELT.

Inoltre, se si guarda l'assemblatore prodotto, compilare con g++ -Wall -S -O3 -fverbose-asm poiché lo -fverbose-asm chiede a GCC di emettere alcuni commenti assembler "spiegando" (non molto, ma un po ') il codice compilato.

+0

Sì, mi piace molto Clang e i suoi disinfettanti. So che c'è un comportamento non definito a causa di una definizione chiamata * 'ALLOW_UNALIGNED_DATA_ACCESS' * in vigore su i386 e x86_64. Ma non spiega l'uso di 'vmovdqa' per le parole a 64 bit. – jww

+0

Sì, per definizione un comportamento indefinito spiega l'output di compilazione bizzarra. –

+0

Anche GCC ha disinfettanti .... Non intendevo passare a 'clang ++' –

Problemi correlati