четверг, 8 июля 2021 г.

codewars heisenbug

 I got following crash when tried to solve some trivial task:


UndefinedBehaviorSanitizer:DEADLYSIGNAL ==1==ERROR: UndefinedBehaviorSanitizer: SEGV on unknown address 0x000000000020 (pc 0x0000004271a4 bp 0x7ffcf51d9a28 sp 0x7ffcf51d9070 T1) ==1==The signal is caused by a READ memory access. ==1==Hint: address points to the zero page. ==1==WARNING: invalid path to external symbolizer! ==1==WARNING: Failed to use and restart external symbolizer! #0 0x4271a3 (/workspace/test+0x4271a3) #1 0x4276d0 (/workspace/test+0x4276d0) #2 0x4273f0 (/workspace/test+0x4273f0) #3 0x427eed (/workspace/test+0x427eed) #4 0x4282b9 (/workspace/test+0x4282b9) #5 0x42abe3 (/workspace/test+0x42abe3) #6 0x4295ce (/workspace/test+0x4295ce) #7 0x429129 (/workspace/test+0x429129) #8 0x428d1b (/workspace/test+0x428d1b) #9 0x43b625 (/workspace/test+0x43b625) #10 0x42810d (/workspace/test+0x42810d) #11 0x7fdeedfdabf6 (/lib/x86_64-linux-gnu/libc.so.6+0x21bf6) #12 0x405339 (/workspace/test+0x405339)

ok, nothing special, just dereferencing zero ptr. But where? code looks like:
double eval(const std::shared_ptr<ASTNode> &tree) {
    if ( !tree )
      return 0.0;
    switch(tree->token.type) {

At least we have address of crash - lets dump first 0x40 bytes of eval function:

   unsigned char *c = (unsigned char *)&eval;
   for ( int i = 0; i < 0x40; i++ )
     printf("%2.2X ", *(c + i));

And then put them in 64bit disasm:

000000000000000d 55               push rbp
000000000000000e 4157             push r15
0000000000000010 4156             push r14
0000000000000012 53               push rbx
0000000000000013 4883ec18         sub rsp, 0x18
0000000000000017 488b37           mov rsi, [rdi]
000000000000001a 660f57c0         xorpd xmm0, xmm0
000000000000001e 4885f6           test rsi, rsi
0000000000000021 0f849d020000     jz dword 0x2c4
0000000000000027 8b4620           mov eax, [rsi+0x20] ; crash is here

WHAT? how rsi can be zero if it passed check test rsi, rsi? Is it buggy qemu, docker or some speculative read-ahead or what is it? I doubt if I wish continue use this service