2015-07-13 6 views
5

У меня возникли проблемы с определением причины segfault при компиляции программы с помощью -O3 с GCC 4.8/4.9/5.1. Для GCC 4.9.x я видел его на Cygwin, Debian 8 (x64) и Fedora 21 (x64). Другие испытали это на GCC 4.8 and 5.1.Определите причину segfault при использовании -O3?

Программа прекрасно под -O2, отлично подходит для других версий GCC и отлично подходит для других компиляторов (например, MSVC, ICC и Clang).

Ниже приведена ошибка под GDB, но на меня ничего не выпрыгивает. Исходный код из misc.cpp:26 ниже, но простой XOR:

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

код в вопросительных проверки для 64-битного слова выравнивания перед в гипсе. Из разборки под -O3, я знаю, что есть что-то делать с 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 

Он появляется GCC использует векторы SSE в -O3, а не использовать их в -O2. (Спасибо Алехандро за предложение).

Я собираюсь наивно спросить: vmovdqa имеют требования к выравниванию более 64-битного слова? Так, почему GCC выбирает его, когда слова не выровнены по 128 бит?

Что вызывает здесь segfault? Как устранить его дальше?


См. Также Bug 66852 - vmovdqa instructions issued on 64-bit aligned array, causes segfault. Он был подан в ответ на этот вопрос, поэтому его неподтвержденный на данный момент.


$ 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 разборка и значения регистров.

(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 

И:

(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 

При компиляции с -O2 и контрольной точкой на линии в вопросе, вот разборки. ((word64*)buf)[i] ^= ((word64*)mask)[i]; переехал в строке 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. 

От misc.cpp, строка 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

Сколько места занимает 'buf'? Уверены ли вы, что вы просто не списываете с конца? Кажется подозрительно, что это 8-символьный длинный cstring ... странно, что ошибка, похоже, происходит так же, как она собирается написать 8 байт, начиная с того, что может быть нулевым терминатором ... – user657267

+1

@ user657267 - Да, код соблюдается размеры буфера. У меня также есть процессы для проверки его во время тестирования. А именно, дезинфицирующие средства Clang и Valgrind. Я собираюсь добавить Coverity, так как это проект с открытым исходным кодом. (Я обожаю статический и динамический анализ). – jww

+0

@jww Можете ли вы полностью отключить ранние блоки и оставить в конце только последний цикл «byte-at-time»? Затем скомпилируйте с помощью '-O3' снова? Может быть, это не сама функция, которая делает что-то странное - может быть, доводы, доведенные до него, неверны. – viraptor

ответ

4

Вы можете компилировать номер с g++ -Wall -Wextra -O3 -g; вы хотите включить предупреждения, потому что некоторые из них, возможно, сгенерированы только в GCC проходах, включенных с помощью -O3; вы хотите включить информацию об отладке (-g), чтобы использовать gdb, но имейте в виду, что отладочная информация не всегда надежна при сильной оптимизации.

Возможно, у вас есть pointer aliasing вопросов. Возможно, используйте (или удалите) ключевое слово restrict.

Обязательно избегайте undefined behavior. Вы можете использовать опции -fsanitize= (в частности, -fsanitize=address и -fsanitize=undefined ....) для компилятора g++ (вариант 5 предпочтительно). Также используйте valgrind.

Кстати, вы можете использовать параметры дампа, такие как -fdump-tree-all (предупреждение, они производят сотни файлов!), Чтобы больше понять внутреннее поведение g++; и вы даже можете настроить свой компилятор GCC с помощью MELT.

Кроме того, если смотреть на ассемблере производства, компилировать с g++ -Wall -S -O3 -fverbose-asm поскольку -fverbose-asm просит GCC испускать некоторые ассемблерные комментарии «объясняющие» (не так много, но чуть-чуть) скомпилированный код.

+0

Да, мне очень нравится Кланг и его дезинфицирующие средства. Я знаю, что существует неопределенное поведение из-за определения, называемого * 'ALLOW_UNALIGNED_DATA_ACCESS' *, действующего на i386 и x86_64. Но это не объясняет использование 'vmovdqa' для 64-битных слов. – jww

+0

Да, по определению неопределенное поведение объясняет необычный результат компиляции. –

+0

GCC тоже имеет дезинфицирующие средства .... Я не хотел переключаться на 'clang ++' –