<table border="1" cellspacing="0" cellpadding="8">
    <tr>
        <th>Issue</th>
        <td>
            <a href=https://github.com/llvm/llvm-project/issues/90010>90010</a>
        </td>
    </tr>

    <tr>
        <th>Summary</th>
        <td>
            Function sanitizer is extremely fragile on macOS
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Assignees</th>
      <td>
      </td>
    </tr>

    <tr>
      <th>Reporter</th>
      <td>
          glandium
      </td>
    </tr>
</table>

<pre>
    Because clang/llvm stores the function signature for runtime check as an integer preceding the function in the text section, and because symbols don't have explicit sizes in mach-O, as far as the linker knows, that data belongs to the function that precedes the "annotated" function.

So if you have function `foo` and function `bar`, the signature for `bar` belongs to `foo`. If for some reason, the linker removes `foo`, then the signature for `bar` becomes whatever the signature of `foo` was, and function call checks at runtime for indirect calls to bar fail.

There are two main situations where this can happen in practice: the `-dead_strip` linker flag (which removes dead code), and when `foo` is defined in multiple compilation units (e.g. template instantiations).

Here's a testcase for both cases:
`foo.h`:
```
template<class T>
int foo(T*) {
  return 0;
}
```
`foo.cpp`
```
#include "foo.h"

int call(int(*cb)(int*), int* x) {
  return cb(x);
}

int dead() {
  return 42;
}

int(*bar)(int*) = &foo<int>;

int main() {
  return call(bar, 0);
}
```
`bar.cpp`:
```
#include "foo.h"

template int foo<void>(void*);
template int foo<int>(int*);
```
`baz.cpp`:
```
#include "foo.h"

template int foo<void>(void*);
```

First case: build with `clang++ -o foo foo.cpp -fsanitize=function -fno-sanitize-recover=function -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk -Wl,-dead_strip`
Fails with:
```
foo.cpp:4:10: runtime error: call to function int foo<int>(int*) through pointer to incorrect function type 'int (*)(int *)'
(foo:arm64+0x100003f24): note: int foo<int>(int*) defined here
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior foo.cpp:4:10 
```
The reason it fails in this case is that the signature for the function `foo` is in `dead`, which is removed, so `foo` ends up with the signature of `dead`, from the last bytes of the function that precedes it. If `dead` had the same signature as `foo<int>`, it would not fail, by mere chance.

Second case: build with `clang++ -o foo baz.cpp bar.cpp foo.cpp -fsanitize=function -fno-sanitize-recover=function -isysroot /Library/Developer/CommandLineTools/SDKs/MacOSX.sdk`
The failure output is the same as for the first case, but the reason is different. Because of the order of the .cpp files, `foo<int>` comes from the instantiation in `bar.cpp`. Its signature is thus in `foo<void>`. But `foo<void>` is actually taken from the instantiation in `baz.cpp`, so practically speaking, this works as if `foo<void>` in `bar.cpp` was dead code, so the signature for `foo<int>` comes from the end of whatever was before `foo<void>`, which in our case is text associated with no symbol at all at the beginning of `bar.cpp`, corresponding to the signature of `foo<void>`.

Presumably, if clang emitted symbols for those function signatures, there wouldn't be a problem, because the linker wouldn't think the signature belongs to the preceding function.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzMV99u47rRfxr6ZmBDppzYvvCF4xzjO_jOYosmB22vCooaWWwoUiCpON6nL4aUZDnr3e1VUWARr8jhzG_-zwjv1ckg7tjDE3t4noku1NbtTlqYUnXNrLDlZfeEUnQeQWphTowftX5vwAfr0EOoEarOyKCsAeIlQucQKuvAdSaoBkHWKN9AeBAGlAl4QgetQ4mlMqdbBsrE74AfATzGM8YPIEwJRQ_CX5rCag8lXa0D1OIdAT9araQK4NU39MSmEbKef42PPVTC0Q-x1sq8oYM3Y8-ebkMtApQiCChQW3PyEOwtpkiR8Pb6Ms6FMTaIgCXjfCRdsOyZZfv098WCquBiu4RwZMces8pa9phFrabHhXDsMUug8JMtx-spzJHVAn6vIpm3DYJD4ZPdJgo7bOw7-uub_t78Qpi0DXo41yLgO7pPxLaaqHMWfvDVqJUUWif_exBhjAgSokypHMoQaaI6hXBQCaVvzPhao0MQDiGcLTRCUZSFThB7wkW3oVYepDBQi7bFGEWtEzIoiSzfJ5c9ZvMSRflPH5xqCW5vl0qLEzC-OddK1qOViBSkLZHx7aDUmYx1VVcRVaUMljHcOh1UqxGkbVqlIzzojAqemOPitICATatFQFDGB2GCSjowvr1R-P_QIeNrDwIC-iCFT_YqbKiBvjzLe9IEZlGTNydn_b_4OQhl-UFq4T28svy3dKVMANKFb14Z3zO-BbZ-SlcADkPnDGQs74_Y-vmugB6DbNvp0Q0Fz5WRuitj4iTAnE9VJiQUBYxvlAmMbxjfyyKaPh3sezekD_i4D5aebOjuDuhRDnk2SrjHYcV_8jThosS4BQYsfwbGH8mW-YGO89-ubEbBFLo_FNxrH5kfILuvw3eGL4QbDP8D9__a9pOoTOGQH96tKkkHvon_S9Yf4Nyh71We-moEfwfzt_865s8C4t-jcj7EhKIaUXRKl3BWoaYU7xvdE-NPMLckAvogh3nlhVFBfUOWP491bl4ZOx8u5g6lfUd3Q6D8xTtrAzB-_EMVTrgL48dnfEdtW3SMHw-2aYQp_1AGX63VnvHjy_P_088XIb--_H3hyzeY_00zfrgtZb0-QmkfNfiRYYc8zfcrlu-X5ICxIqNz1tFBrNjBTlvyj_0MoXa2O9XQWmrsjh4qI62Lhf3aQS8t-XJNrFIWjSkEw8d6cP4mCtsL1zyuGH_KPpZZlmV5xVfRpXswNkSX_RTYUJqpP_T9-M8vX_Z__Qe9_NP0109Yi3dl3UvvuWiBbridF_01fLYc3LXvaz30XlAhdjKfBprYnTxSy4jDxPcd92bguOkxKn7HqpV6dmpUyve9qqQzP5kFAE3poWtTMN_r1xNmlbNNmhKED1BcAnoi-sn8o0IcNq5soBZlEiOaqSwxzhqjg5JMFeBsO12SI6OV6LC4QEOtXNbCSLwdpFBaU_7nmdpXGOir4_9I5t5ECWkd_dGFtgspLnoD0rQ6BMS1QpGFuhQ4Q4R5KFVVoUMTFjBM6L3vrCvRDR_JCEpjHM--9wmkEW8MhZvxpI-_a6dZwO_BT9wcsXdDnN4WY6J-6sK9C3onZOiE1hcI4g3NrwCMbSPFez_gxfe-RfGmKA4OKdvO1tHA6WkCvyv8k1I0u05nvijh7lz8C9uhKcns47hMfAusrMN7OCbpbMB27lolaP8R3lupaMdI0W5sv_vQJE1Vuq8kBZ6UMbRKpfSeTAX8ALEY-9aatGx9VsveNdBN_v3Foe8aUehLzN4qrYGAjQqEbdjHUtRaf28d7DctSvCY-mlzKxAEtM4WGpsY4X0QT7aWCXWolXn7hP7TynZdKseNbFbu8nKbb8UMd8v1cpUt8yVfz-rdYymzzWr7uM6yQm5X6021Ltf5ErFaldlDIWZqxzO-ylb8IeOrB75eVHlWCV4-bKpl_rDmW7bKsKF1hdbhhXWnmfK-w902y5bZTIsCtR_WarcjonnRnTxbZVr54K_Pggoad8fRakMzokjAj-CwQX2ByomT0gg27rZfX2ad07s6hDbuA_zI-PGkQt0VC2mbfknvf-ats_9CGRg_RohUmSLKfwcAAP__kBAT5Q">