Déterminer la cause de la segfault lors de l’utilisation de -O3?

Je n’arrive pas à déterminer la cause d’une erreur de segmentation lorsqu’un programme est compilé avec -O3 avec GCC 4.8 / 4.9 / 5.1. Pour GCC 4.9.x, je l’ai vu sur Cygwin, Debian 8 (x64) et Fedora 21 (x64). D’autres l’ont expérimenté sur GCC 4.8 et 5.1 .

Le programme fonctionne bien sous -O2 , -O2 avec d’autres versions de GCC et sous d’autres compilateurs (tels que MSVC, ICC et Clang).

Ci-dessous, le crash sous GDB, mais rien ne me saute aux yeux. Le code source de misc.cpp:26 est ci-dessous, mais c’est un simple XOR:

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

Le code en question vérifie l’alignement des mots sur 64 bits avant la conversion. Depuis le désassemblage sous -O3 , je sais que cela a quelque chose à voir avec l’instruction vmovdqa :

 (gdb) disass 0x0000000000539fc3 ... 0x0000000000539fbc : vxorps 0x0(%r13,%r10,1),%ymm0,%ymm0 => 0x0000000000539fc3 : vmovdqa %ymm0,0x0(%r13,%r10,1) 0x0000000000539fca : add $0x20,%r10 

Il semble que GCC utilise des vecteurs SSE à -O3 et non à -O2 . (Merci à Alejandro pour la suggestion).

Je vais naïvement demander: est-ce que vmovdqa a des exigences d’alignement supérieures à 64 bits? Dans ce cas, pourquoi GCC le sélectionne-t-il lorsque les mots ne sont pas alignés sur 128 bits?

Quelle est la cause de la segfault ici? Comment puis-je résoudre le problème plus loin?


Consultez également le bogue 66852 – Les instructions vmovdqa émises sur un tableau aligné 64 bits, provoque un segfault . Il a été déposé en réponse à ce problème, de sorte qu’il n’est pas confirmé pour le moment.


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

 (gdb) where #0 0x0000000000539fc3 in CryptoPP::xorbuf (buf=0x98549a "efghijde", mask=mask@entry=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' ..., count=count@entry=0x5e) at misc.cpp:26 #1 0x0000000000561eb0 in CryptoPP::SHA3::Update (this=0x985480, input=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' ..., length=0x5e) at sha3.cpp:264 #2 0x00000000005bac1a in CryptoPP::HashVerificationFilter::NextPutMultiple ( this=0x7fffffffd390, inSsortingng=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' ..., length=0x5e) at filters.cpp:786 #3 0x00000000005bd8a2 in NextPutMaybeModifiable (modifiable=, length=0x5e, inSsortingng=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' ..., this=0x7fffffffd390) at filters.h:200 #4 CryptoPP::FilterWithBufferedInput::PutMaybeModifiable ( this=0x7fffffffd390, inSsortingng=0x7fffffffbfeb "efghijdefghijkefghijklfghijklmghijklmnhijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu", 'a' ..., length=, messageEnd=0x0, blocking=, ... 

-O3 désassemblage et enregistrer les valeurs.

 (gdb) disass 0x0000000000539fc3 Dump of assembler code for function CryptoPP::xorbuf(unsigned char*, unsigned char const*, unsigned long): 0x0000000000539ee0 : lea 0x8(%rsp),%r10 0x0000000000539ee5 : and $0xffffffffffffffe0,%rsp 0x0000000000539ee9 : mov %rdx,%rax 0x0000000000539eec : pushq -0x8(%r10) 0x0000000000539ef0 : push %rbp 0x0000000000539ef1 : shr $0x3,%rax 0x0000000000539ef5 : mov %rsp,%rbp 0x0000000000539ef8 : push %r15 0x0000000000539efa : push %r14 0x0000000000539efc : push %r13 0x0000000000539efe : push %r12 0x0000000000539f00 : push %r10 0x0000000000539f02 : push %rbx 0x0000000000539f03 : je 0x53a00a  0x0000000000539f09 : lea 0x20(%rdi),%rcx 0x0000000000539f0d : cmp %rcx,%rsi 0x0000000000539f10 : lea 0x20(%rsi),%rcx 0x0000000000539f14 : setae %r8b 0x0000000000539f18 : cmp %rcx,%rdi 0x0000000000539f1b : setae %cl 0x0000000000539f1e : or %cl,%r8b 0x0000000000539f21 : je 0x53a300  0x0000000000539f27 : cmp $0x8,%rax 0x0000000000539f2b : jbe 0x53a300  0x0000000000539f31 : mov %rdi,%rcx 0x0000000000539f34 : and $0x1f,%ecx 0x0000000000539f37 : shr $0x3,%rcx 0x0000000000539f3b : neg %rcx 0x0000000000539f3e : and $0x3,%ecx 0x0000000000539f41 : cmp %rax,%rcx 0x0000000000539f44 : cmova %rax,%rcx 0x0000000000539f48 : xor %r8d,%r8d 0x0000000000539f4b : test %rcx,%rcx 0x0000000000539f4e : je 0x539f80  0x0000000000539f50 : mov (%rsi),%r8 0x0000000000539f53 : xor %r8,(%rdi) 0x0000000000539f56 : cmp $0x1,%rcx 0x0000000000539f5a : je 0x53a371  0x0000000000539f60 : mov 0x8(%rsi),%r8 0x0000000000539f64 : xor %r8,0x8(%rdi) 0x0000000000539f68 : cmp $0x3,%rcx 0x0000000000539f6c : jne 0x53a366  0x0000000000539f72 : mov 0x10(%rsi),%r8 0x0000000000539f76 : xor %r8,0x10(%rdi) 0x0000000000539f7a : mov $0x3,%r8d 0x0000000000539f80 : mov %rax,%r11 0x0000000000539f83 : xor %r10d,%r10d 0x0000000000539f86 : sub %rcx,%r11 0x0000000000539f89 : shl $0x3,%rcx 0x0000000000539f8d : xor %ebx,%ebx 0x0000000000539f8f : lea -0x4(%r11),%r9 0x0000000000539f93 : lea (%rdi,%rcx,1),%r13 0x0000000000539f97 : shr $0x2,%r9 0x0000000000539f9b : add %rsi,%rcx 0x0000000000539f9e : add $0x1,%r9 0x0000000000539fa2 : lea 0x0(,%r9,4),%r12 0x0000000000539faa : add $0x1,%rbx 0x0000000000539fae : vmovdqu (%rcx,%r10,1),%xmm0 0x0000000000539fb4 : vinsertf128 $0x1,0x10(%rcx,%r10,1),%ymm0,%ymm0 0x0000000000539fbc : vxorps 0x0(%r13,%r10,1),%ymm0,%ymm0 => 0x0000000000539fc3 : vmovdqa %ymm0,0x0(%r13,%r10,1) 0x0000000000539fca : add $0x20,%r10 0x0000000000539fce : cmp %r9,%rbx 0x0000000000539fd1 : jb 0x539faa  0x0000000000539fd3 : lea (%r8,%r12,1),%rcx 0x0000000000539fd7 : cmp %r12,%r11 0x0000000000539fda : je 0x53a006  0x0000000000539fdc : mov (%rsi,%rcx,8),%r8 0x0000000000539fe0 : xor %r8,(%rdi,%rcx,8) 0x0000000000539fe4 : lea 0x1(%rcx),%r8 0x0000000000539fe8 : cmp %r8,%rax 0x0000000000539feb : jbe 0x53a006  0x0000000000539fed : add $0x2,%rcx 0x0000000000539ff1 : mov (%rsi,%r8,8),%r9 0x0000000000539ff5 : xor %r9,(%rdi,%r8,8) 0x0000000000539ff9 : cmp %rcx,%rax 0x0000000000539ffc : jbe 0x53a006  0x0000000000539ffe : mov (%rsi,%rcx,8),%r8 0x000000000053a002 : xor %r8,(%rdi,%rcx,8) 0x000000000053a006 : shl $0x3,%rax 

Et:

 (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 

Une fois compilé avec -O2 et un point d’arrêt sur la ligne en question, voici le désassemblage. ((word64*)buf)[i] ^= ((word64*)mask)[i]; déplacé à la ligne 31:

 Breakpoint 1, CryptoPP::xorbuf (buf=0x985488 "", mask=mask@entry=0x7fffffffc01d "The quick brown fox", 'a' ..., count=count@entry=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 : mov %rdx,%rcx 0x0000000000532153 : shr $0x3,%rcx 0x0000000000532157 : je 0x532170  0x0000000000532159 : xor %eax,%eax => 0x000000000053215b : mov (%rsi,%rax,8),%r8 0x000000000053215f : xor %r8,(%rdi,%rax,8) 0x0000000000532163 : add $0x1,%rax 0x0000000000532167 : cmp %rcx,%rax 0x000000000053216a : jne 0x53215b  0x000000000053216c : shl $0x3,%rcx 0x0000000000532170 : sub %rcx,%rdx 0x0000000000532173 : je 0x5321d0  0x0000000000532175 : mov %rdx,%r8 0x0000000000532178 : add %rcx,%rdi 0x000000000053217b : add %rcx,%rsi 0x000000000053217e : shr $0x2,%r8 0x0000000000532182 : je 0x5321a8  0x0000000000532184 : xor %eax,%eax 0x0000000000532186 : nopw %cs:0x0(%rax,%rax,1) 0x0000000000532190 : mov (%rsi,%rax,4),%ecx 0x0000000000532193 : xor %ecx,(%rdi,%rax,4) 0x0000000000532196 : add $0x1,%rax 0x000000000053219a : cmp %r8,%rax 0x000000000053219d : jne 0x532190  0x000000000053219f : shl $0x2,%r8 0x00000000005321a3 : sub %r8,%rdx 0x00000000005321a6 : je 0x5321d8  0x00000000005321a8 : lea (%rdi,%r8,1),%rcx 0x00000000005321ac : xor %eax,%eax 0x00000000005321ae : lea (%rsi,%r8,1),%rdi 0x00000000005321b2 : nopw 0x0(%rax,%rax,1) 0x00000000005321b8 : movzbl (%rdi,%rax,1),%esi 0x00000000005321bc : xor %sil,(%rcx,%rax,1) 0x00000000005321c0 : add $0x1,%rax 0x00000000005321c4 : cmp %rdx,%rax 0x00000000005321c7 : jb 0x5321b8  0x00000000005321c9 : retq 0x00000000005321ca : nopw 0x0(%rax,%rax,1) 0x00000000005321d0 : retq 0x00000000005321d1 : nopl 0x0(%rax) 0x00000000005321d8 : retq End of assembler dump. 

Dans misc.cpp , la ligne 26 est ((word64*)buf)[i] ^= ((word64*)mask)[i]; .

 void xorbuf(byte *buf, const byte *mask, size_t count) { size_t i; if (IsAligned(buf) && IsAligned(mask)) { if (!CRYPTOPP_BOOL_SLOW_WORD64 && IsAligned(buf) && IsAligned(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]; } 

Vous pouvez comstackr avec g++ -Wall -Wextra -O3 -g ; vous souhaitez activer les avertissements, car certains d’entre eux sont éventuellement générés uniquement dans des passes GCC activées avec -O3 ; vous voulez activer les informations de débogage ( -g ) pour utiliser gdb mais sachez que les informations de débogage ne sont pas toujours fiables avec des optimisations fortes

Vous pouvez avoir des problèmes d’ alias de pointeur . Peut-être utiliser (ou supprimer) le mot clé ressortingct .

Veillez à éviter tout comportement indéfini . Vous pouvez utiliser -fsanitize= options (notamment -fsanitize=address et -fsanitize=undefined ….) pour le compilateur g++ (version 5 de préférence). Utilisez aussi valgrind .

En passant, vous pouvez utiliser des options de vidage telles que -fdump-tree-all ( -fdump-tree-all , elles produisent des centaines de fichiers!) Pour mieux comprendre le comportement interne de g++ ; et vous pourriez même personnaliser votre compilateur GCC avec MELT .

De même, si vous regardez l’assembleur produit, comstackz-le avec g++ -Wall -S -O3 -fverbose-asm car -fverbose-asm demande à GCC d’émettre des commentaires d’assembleur “expliquant” (pas beaucoup, mais un tout petit peu) le code compilé. .