Issue 115323
Summary `sincos` args may get clobbered after #108401 when passed on the stack
Labels compiler-rt:asan, llvm:SelectionDAG
Assignees MacDue
Reporter zmodem
    Consider this program on 32-bit x86, where arguments are passed on the stack:

```
$ cat /tmp/a.cc
#include <math.h>
#include <stdio.h>

double __attribute__((noinline)) g(double a, double b) { return a + b; }

double __attribute__((noinline)) f(double a) {
 double foo = sin(a);
  double bar = cos(a);
  double z = g(bar + 3.14, foo);
  return z;
}

int main() {
  printf("%f\n", f(3.14));
  return 0;
}
```

After 3073c3c2290a6d9b12fbaefa40dd22eef6312895, it fails under ASan:

```
$ build/bin/clang.bad -target i386-unknown-linux-gnu -lm -fsanitize=address -fno-math-errno -O2 /tmp/a.cc && ASAN_OPTIONS=external_symbolizer_path=$PWD/build/bin/llvm-symbolizer ./a.out
AddressSanitizer:DEADLYSIGNAL
=================================================================
==3898196==ERROR: AddressSanitizer: SEGV on unknown address 0x27eb4300 (pc 0x566160ed bp 0xffab1898 sp 0xffab1470 T0)
==3898196==The signal is caused by a READ memory access.
    #0 0x566160ed in QuickCheckForUnpoisonedRegion /work/llvm-project/compiler-rt/lib/asan/asan_interceptors_memintrinsics.h:37:7
 #1 0x566160ed in sincos /work/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors.inc:5167:12
 #2 0x566b25b1 in f(double) (/work/llvm-project/a.out+0x1085b1)
    #3 0x566b25f3 in main (/work/llvm-project/a.out+0x1085f3)
    #4 0xf7c29b84 (/lib/i386-linux-gnu/libc.so.6+0x23b84) (BuildId: d16f2b0239d79fbec67438094f9a9443121ab72d)
    #5 0xf7c29c47 in __libc_start_main (/lib/i386-linux-gnu/libc.so.6+0x23c47) (BuildId: d16f2b0239d79fbec67438094f9a9443121ab72d)
    #6 0x565c43a6 in _start (/work/llvm-project/a.out+0x1a3a6)

==3898196==Register values:
eax = 0x27eb4300  ebx = 0x27eb4303  ecx = 0x27eb4300  edx = 0x3f5a1819  
edi = 0x07eb4303  esi = 0x07eb4302  ebp = 0xffab1898  esp = 0xffab1470 
AddressSanitizer can not provide additional info.
SUMMARY: AddressSanitizer: SEGV (/work/llvm-project/a.out+0x1085b1) in f(double)
==3898196==ABORTING
```

The calls to `sin` and `cos` will get folded to a `sincos` call. After 3073c3c2290a6d9b12fbaefa40dd22eef6312895, the call looks like this:

```
  37:   89 e6                   mov    %esp,%esi
  39: 8d 44 24 18             lea    0x18(%esp),%eax
  3d:   89 44 24 0c mov    %eax,0xc(%esp)    // <-- cos
  41:   8d 46 08 lea    0x8(%esi),%eax
  44:   89 44 24 08             mov %eax,0x8(%esp)    // <-- sin
  48:   f2 0f 11 04 24          movsd %xmm0,(%esp)      // <-- x
  4d:   e8 fc ff ff ff          call   4e <_Z1fd+0x2e>
                        4e: R_386_PLT32 sincos
```

Look at the value of the `sin` argument: it's `0x8(%esi) = 0x8(%esp)` which is the stack slot for `foo` in the following call to `g`. But it's also the stack slot used for `sin` in the `sincos` call. This seems dangerous.

Since it's a 64-bit value, when `sincos` does `*sin = ...` it will clobber both the `sin` and `cos` arguments. ASan happens to notice, because it intercepts `sincos` and checks the validity of the pointers afterwards.
_______________________________________________
llvm-bugs mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-bugs

Reply via email to