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

    <tr>
        <th>Summary</th>
        <td>
            Faulty -fsanitize=shift-exponent checks (seen with _BitInt)
        </td>
    </tr>

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

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

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

<pre>
    Consider these examples:
```
int test_left(unsigned _BitInt(17) x) {
  return x << 3uwb;  // Shift exponent is OK (3 < 17)  
}

int test_right(unsigned _BitInt(4) x) {
  return x >> 16uwb; // Shift exponent is NOK (16 >= 4)
}
```

When compiled with `-O1 -fsanitize=shift-exponent -emit-llvm -g0` the result is:
```
define dso_local noundef i32 @test_left(i17 noundef zeroext %0) local_unnamed_addr #0 {
  %2 = zext i17 %0 to i64
  tail call void @__ubsan_handle_shift_out_of_bounds(ptr nonnull @2, i64 %2, i64 3) #3
  %3 = shl i17 %0, 3
  %4 = zext i17 %3 to i32
  ret i32 %4
}

define dso_local noundef i32 @test_right(i4 noundef zeroext %0) local_unnamed_addr #2 {
  %2 = zext i4 %0 to i32
  ret i32 %2
}
```

So we actually see the opposite from the expected result (test_left will report UB and test_right will not report UB).

Quick analysis show:
Faults seem to be in ScalarExprEmitter::EmitShl / ScalarExprEmitter::EmitShr / ScalarExprEmitter::GetWidthMinusOneValue.

For the left shift  EmitShl uses the type of the right hand side when doing the ubsan checks. But when using the GetWidthMinusOneValue helper  it is not considered that the upper shift count limit given by the size of the left hand side operand might not fit in the type used by the right hand side. So the value is simply truncated and that results in an incorrect upper bound when doing the check.

For the right shift EmitShr is truncating the shift exponent operand to the size of the left hand side operand before doing the out-of-bounds check. This seems incorrect, as the check really should be performed using the type of the shift exponent operand.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJyUVstu6zYTfhp6M7Ahk_Jt4UWcxD9-FO1BkbZnKVDiyOI5FCnwEtt5-oKUZStpkqZA4IjkXL6Z-WZI7pw8aMQtWewIpeUP0yGhlCweJjz4xtht2pqURpy390Y7KdCCb9Ah4Im3nUJH2B3JHkh2R5bZ5S8tpfbg0flCYe0JXQedfAkodtL_X8et-YrQDZziD1ntejUAiz5YDScg7J6we2DhWBK2AyB0T-genhpZe8BTZzRqD9LBt1-A0DWLCtDbhAuk1cPl4zUkKw_NB5jyf4H0SNgjzJcXTB9C-q3HNF_2Kg8Q7b4F9Tph_e_3BjVUpu2kQgFH6Rsgy2z6bQ7T2nEtvXxBwh5c9Di9epxiK_1UqecWpodoMhYJLLqgIpyPaiSwlhpBOFMoU3EF2gQtsAbJKJA8G9dPzlfX4xe0Bk8eCF1kMVVJuQha8xZFwYWwQCjLxikkdEEhJuIlKkZjURm8AbnMByHPpYKKKwXPRoqIoChC6bguGq6FwiKFXZjgC1MXZUTjCF133oI2Wgelog4l9D5aTT6Hb5ZKShkbAWIJkGvUFU-UHkvk_4DMEmRGR9Tos0UX-buk-1KOB0LK_D_mmH6S4_yW4nfx0q_w8cnAEYFXPnClzuAQE7VM1xknPUJtTZt28NRh5VEMrCN0faUPHKVSYLEz1sOfO-BajBqxP9XG3yQI3czGKH4PsvoJXHN1dtKBa8zxyuk9D8q7iKyNsZYIUsNTxRW3j6fOPrbSe7RRnN3FxVOjIDXtZyL2M5H_of8uhW9-lTq4bxr_4irgK7x7k8YkpOATaQEG38GhS4f-3CGYum_VlIjIcohDFo5xDAgj9SEdpyaAqsHqp5vBLvheILhB4F1I0KDq0ALINJNihqvLEEcBvuG-N95FoR5lZYL2oGQrPRzkM2ooz0nIyZcr2BTVDavp0MZFm2KIXuroUN-CDA7FYOhNpDN4Mmn_OSGOxZVtp87gbdAVj4RKbIlge2a5aJprkLoy1mLlLwGkcfA2cSll75amx9FHPdRcusHtoO9eT_YhVG--mpQSa2NxhMgEPzX1tB9eF3zwRyN7BrtbWHEWcXeLAiz2LdiYoKJh6NDWxrYoRkQYk-p98LOJ2DKxYRs-we18lS1XWb7I2KTZ0pKXVFRLUTK2Xq9qmnFRi-VCLNia5_lyIrc0o3k2Z_M5ZfliPeMMl_ONWNB8sxYMkeQZtlyqWbyKZsYeJtK5gNt1NmeLieIlKjc8NsIhPjXoPaG0UlyPVpTdvvub0E6tJ-wutcHlgWK30ce0DAdH8kxJ593Nq5de4TZNhvOnF2ffUnFYOUTd37fXx8BmEqzaNt536QZNd_1B-iaUs8q0hO6jv8u_aWfNj1S1fQrZEbpPUf8dAAD__xSY_a4">