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

    <tr>
        <th>Summary</th>
        <td>
            UBSan false positive: runtime error: load of address with insufficient space for an object of type 'int'
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            clang,
            compiler-rt:ubsan,
            miscompilation
      </td>
    </tr>

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

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

<pre>
    Please consider this small reduced testcase:
```c++
int x;
int main(void) {
  int array[4] = {0};
  int *ptr;
  if (x) {
    ptr = 0;
 } else {
    ptr = array + 4;
  }
  return ptr[-1];
}
```
This, as far as I know, is a strictly conforming C program. But Clang's UBSan rejects it as of version 15:
```
$ clang-14 test.c -O3 -o test -fsanitize=undefined && ./test
$ clang-15 test.c -O3 -o test -fsanitize=undefined && ./test
test.c:10:10: runtime error: load of address 0xffffd0f236dc with insufficient space for an object of type 'int'
0xffffd0f236dc: note: pointer points here
  00 00 00 00 00 00 00 00  00 38 f2 d0 ff ff 00 00  c4 84 f1 eb 72 e1 00 00  78 38 f2 d0 ff ff 00 00
              ^
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior test.c:10:10 in
```
This continues to be rejected in all later versions too. From what I can tell debugging, it's going wrong in `llvm::lowerObjectSizeCall`: this sets `EvalOptions.EvalMode = ObjectSizeOpts::Mode::ExactSizeFromOffset`. `ExactSizeFromOffset` allows combining `SizeOffsetValue`s if the sizes are the same, even if the offsets are different. So, we combine "0 bytes into a 0-byte-sized object" and "16 bytes into a 16-byte-sized object" into just "0 bytes into a 0-byte-sized object". But that is wrong when we then use that to conclude that we cannot access any bytes before that object.

If I change LLVM as
```diff
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index e1abf5e4d885..8abbb074647c 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -610,7 +610,7 @@ Value *llvm::lowerObjectSizeCall(
     EvalOptions.EvalMode =
         MaxVal ? ObjectSizeOpts::Mode::Max : ObjectSizeOpts::Mode::Min;
   else
- EvalOptions.EvalMode = ObjectSizeOpts::Mode::ExactSizeFromOffset;
+ EvalOptions.EvalMode = ObjectSizeOpts::Mode::ExactUnderlyingSizeAndOffset;

 EvalOptions.NullIsUnknownSize =
 cast<ConstantInt>(ObjectSize->getArgOperand(2))->isOne();
```
then this program gets accepted. But I expect this change to not be right, I expect this to result in poorer codegen where `lowerObjectSizeCall` is already doing the right thing.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJykVt1u4zoOfhrlhnAgy3_JRS6StAEKnG4X250B9lK2aEdzFMmQ5LSZp1_Qdtu0p3N-Zgo3tkSKpKiPHyVD0J1F3LBix4qbhRzi0fnN8az0t98XtVOXzb8NyoDQOBu0Qg_xqAOEkzQGPKqhQQURQ2xkQJZtGb9hfMtKPj0NEzt6xlltIzyz7Gp0ktoysTo7rZhYA6tmGQBJpffywopdzoobYNkNyTmrbl5NTGpMbPvorydbYGL1_MEiQB_9aIa_6bLqBtAE_FxxDACY2EF-ZZ4imD89xsFb0mfFLklZ8Rbbq9ZrLqbhf486MLEHGaCVnl538Lt1TzSnA0gI0esmmgtlvHX-pG0He-i967w8LWE3RNgbaTsmqgBfdo_Sgsdv2MQAOpI918IZfdDOQlr88UjmocihITNJmo_nt2wgecggceMIkjZIq6P-jiy7GazCVltUwETJRAlLJg6k9gdbxa_ampazbJvylx_wg436hIDeO08TxklF25RKeQwB-HPbtq3irchK1cCTjkfQNgxtqxuNNkLoZYPQOg_SgqspW7Q-XnoEJiptIxPVFMB7W-TNukjIht5pG9FP7wBH9PiCA84_f-g_W0ErQHFoW3pmQZPDKoc2BayhEoDpi6BafbriDZxvf6y4naYfv9zfb__zPwryy0t6d3iUZ-3845z6MXGvyU_qWQwfEw7a_hC3BMmo7YABooMaZ-ChAm2BCMFIStCMPlJySzh4d4Kno4xwB420ENEYUFgPXacJxXvQccRy5wjqT97ZjuyxkhtzPhGAs61xT-gfxoN71N9xL42hyLLtTEcYAy24PUvz0EdyvqTve6dwrOS3pQ99DJNNEk5ft89yElKsD20bMLKSL0eLn4pos-6J8nGqtaWwWclH66PGV2kGZCUPREXxiBD0dwwgPU4jeULaN57Rvmi4ceGko3Tbokcbl_DoSPEJZ0-EVsGhvkQMxH0OJPCEhgm5UDO2mRAgLVWYSMv32mn5ufoo_jaE-Lc9TFQU6WB1mI_t6YiWoo30HgJO4ugIOI0Z1DxB-5HWugiyaaiApb3MLmtsnZ_VJlfLGY7j711LKDpK2yH89tvXe5DhA1opedMUfUGSdMSKTBxGMImD0TUTh62V5hKIiQ_3eHL-shu0idqGZdP3UP8j9Zd2pvAZMJV1W2CuVqtiuVzJuq55lZd51UDKeZnnk3KSJP8wphem3U3PT4XIcs5yDkmZcib2FTW2189JNAKXGuqfV55YXdHRj2ruA2Pdy-ev0gDLDn9RjPfyGaiw_0JL26uWPPbwObU_DOgnSOC1mYvdL5klVvbmom1HalurPtqf9nHt4l-DMXfhi6W7gaVVVzltZIgs2--dDVHaeGcjy26ZWL1FkrDstsO49d1Dj15axcRKMLFmYk0iHR4s0jGK9VsM7_l-LOGRXOerB3QjPzUN9hHVVP13gM89NdNRca7L6Khlju1Bd8dIBPZeLzrwGAYTieZ75zx6aJzCjsiD2urI_Z8y_nhFMh6luoAa-wWR5-iHbNtuuVCbTK2ztVzgJq3EKl_zdVkujpu6WKlyXTRpk9arnPMsXeU844UqqoJLyRd6I7jIU87XaSlEXi6Lqq6zRpVtpVZVlTUs53iS2iypOpbOdwsdwoCbNE0rvl4YWaMJ401aiGa6ogkm9jRyp14b9ImPLNsOdZD2VXbSYRJLOniaLm4WfkM-knroAsu50SGGN69RR4Ob6erXSrq99i7oqM_4t25LP3k9WgzebI4x9iPExYGJQ6fjcaiXjTtdsRHF3Xs3dYnDmCEipTlJ5434fwAAAP__5hTe4A">