Hello,
I use icc (ICC) version 16.0.2 (20160204). I found a bug in the way its MPX transformation pass passes bounds via an indirect call.
Here is the test case that reproduces the problem:
char x = 42; int (*f) (int, char * ); // IF REMOVE INT ARGUMENT: WORKS char* p; int bar(int i, char *q) { return q[0]; } int __attribute__ ((noinline)) foo() { return f(0, p); // return bar(0, p); // WORKS } int main() { f = bar; p = &x; return foo(); }
This code raises the false-positive #BR exception when compiled & run:
>>> icc -O3 -ggdb -check-pointers-mpx=rw -lmpx -lmpxwrappers test.c>>> ./a.out Saw a #BR! status 1 at 0x400b75
Note that the function pointer `f` is used to call `bar` in `foo` (indirect call). When using a direct call `bar(0, p)`, everything compiles and runs correctly. Also note that by removing the first argument for `bar` (integer `i`), the bounds are again correct and no exception is triggered.
Here is the corresponding assembly:
<foo>: mov $0x1,%eax mov 0x203144(%rip),%rsi # 603c90 <p> xor %edi,%edi mov 0x203143(%rip),%rdx # 603c98 <f> bndldx 0x603c90(,%rsi,1),%bnd1 bndmk -0x1(%rax),%bnd0 # NULL bounds are created?! bnd jmpq *%rdx<bar>: rex.W bndcl %rsi,%bnd0 # BR EXCEPTION HERE rex.W bndcu %rsi,%bnd0 movsbl (%rsi),%eax bnd retq
So, `foo` calls `bar` with two bounds passed in BND0 (with NULL bounds) and BND1 (with correct bounds for p), but `bar` assumes that the bounds for its pointer argument are passed in BND0. AFAIK, the way `foo` is compiled is a violation of the X64 calling convention for MPX. Also, this exception does not happen under GCC 6.1. Thus, I believe it's a bug in the ICC MPX pass implementation.