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

    <tr>
        <th>Summary</th>
        <td>
            Optimized HWASan code produces incorrect assembly
        </td>
    </tr>

    <tr>
      <th>Labels</th>
      <td>
            new issue
      </td>
    </tr>

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

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

<pre>
    The following code:

```
struct AndroidSizeClassConfig {
  static constexpr unsigned Classes[] = {
      0x00020, 0x00030, 0x00040, 0x00050, 0x00060, 0x00070, 0x00090, 0x000b0,
      0x000c0, 0x000e0, 0x00120, 0x00160, 0x001c0, 0x00250, 0x00320, 0x00450,
      0x00670, 0x00830, 0x00a10, 0x00c30, 0x01010, 0x01210, 0x01bd0, 0x02210,
      0x02d90, 0x03790, 0x04010, 0x04810, 0x05a10, 0x07310, 0x08210, 0x10010,
 };
};

static const unsigned NumClasses =
 sizeof(AndroidSizeClassConfig::Classes) / sizeof(AndroidSizeClassConfig::Classes[0]);

void func(unsigned);

void printMap() {
  for (unsigned I = 0; I < NumClasses; I++) {
    func(AndroidSizeClassConfig::Classes[I]);
 }
}
```

Compiled with `clang++ --target=aarch64-unknown-linux-gnu -O1 -fvisibility=hidden -fsanitize=hwaddress -fsanitize=undefined -std=c++17 -fno-exceptions -fno-rtti -c /tmp/reproducer.cc -S -o -` results in:

```
 adrp    x23, :pg_hi21_nc:.L_ZN22AndroidSizeClassConfig7ClassesE.hwasan
 adrp    x19, :pg_hi21_nc:_ZN22AndroidSizeClassConfig7ClassesE
 adrp    x21, :pg_hi21_nc:.L__unnamed_1
        movk    x23, #:prel_g3:.L_ZN22AndroidSizeClassConfig7ClassesE.hwasan+4294967296
 movk    x19, #:prel_g3:_ZN22AndroidSizeClassConfig7ClassesE+4294967296
 movk    x21, #:prel_g3:.L__unnamed_1+4294967296
        mov     x22, xzr
        add     x23, x23, :lo12:.L_ZN22AndroidSizeClassConfig7ClassesE.hwasan
        mov     x24, #4611686018427387904
        add     x19, x19, :lo12:_ZN22AndroidSizeClassConfig7ClassesE
        add     x21, x21, :lo12:.L__unnamed_1
.LBB0_1:                                // =>This Inner Loop Header: Depth=1
        add     x8, x23, x22
        add x2, x8, x24
        cmp     x2, x19
        b.lo .LBB0_3
...
.LBB0_3:                                //   in Loop: Header=BB0_1 Depth=1
        mov     x0, x21
        mov     x1, x19
        stp     x8, x2, [sp]                    // 16-byte Folded Spill
        bl      __ubsan_handle_pointer_overflow

...
 .weak   _ZN22AndroidSizeClassConfig7ClassesE
        .hidden _ZN22AndroidSizeClassConfig7ClassesE
.set _ZN22AndroidSizeClassConfig7ClassesE, .L_ZN22AndroidSizeClassConfig7ClassesE.hwasan+4611686018427387904
```

This can incorrectly result in `__ubsan_handle_pointer_overflow` called incorrectly if another definition of `_ZN22AndroidSizeClassConfig7ClassesE` is provided in a separate object file and wins during linking. This is because of how the awkward codegen attempts to get the tagged address for `AndroidSizeClassConfig::Classes` into `x2`:

```
// The relevant bits
        // x23 will have the *untagged* address for _ZN22AndroidSizeClassConfig7ClassesE
        adrp    x23, :pg_hi21_nc:.L_ZN22AndroidSizeClassConfig7ClassesE.hwasan
        movk x23, #:prel_g3:.L_ZN22AndroidSizeClassConfig7ClassesE.hwasan+4294967296
 mov     x22, xzr
        add     x23, x23, :lo12:.L_ZN22AndroidSizeClassConfig7ClassesE.hwasan

        // x24 will have the tag (0x4) which is hardcoded here
        mov     x24, #4611686018427387904
        add     x8, x23, x22

        // Add the tag onto the untagged pointer
        add     x2, x8, x24

 // Do the comparison from here...
```

Now this would technically/arithmetically be fine only if the prevailing definition for `_ZN22AndroidSizeClassConfig7ClassesE` was this object file's definition, but because `_ZN22AndroidSizeClassConfig7ClassesE` is weak, any other object file defining it could win at link time and have a different tag. This means the `x2` produced here will never use the prevailing tag defined elsewhere and is very susceptible to triggering ubsan for pointer comparisons if the prevailing tag happens to be larger than this object file's tag.

The IR for this snippet looks correct:

```
define hidden void @_Z8printMapv() local_unnamed_addr #0 {
...
  %7 = phi i64 [ 0, %0 ], [ %15, %13 ]
  %8 = getelementptr inbounds [32 x i32], ptr @_ZN22AndroidSizeClassConfig7ClassesE, i64 0, i64 %7
  %9 = shl nuw nsw i64 %7, 2
  %10 = add i64 %9, ptrtoint (ptr @_ZN22AndroidSizeClassConfig7ClassesE to i64), !nosanitize !8
  %11 = icmp ult i64 %10, ptrtoint (ptr @_ZN22AndroidSizeClassConfig7ClassesE to i64), !nosanitize !8
  br i1 %11, label %12, label %13, !prof !9, !nosanitize !8

12:                                               ; preds = %6
 tail call void @__ubsan_handle_pointer_overflow(ptr nonnull @0, i64 ptrtoint (ptr @_ZN22AndroidSizeClassConfig7ClassesE to i64), i64 %10) #4, !nosanitize !8
  br label %13, !nosanitize !8
...
}
```

and the unoptimized assembly looks correct:

```
// The tagged symbol is used here
        ldur    w9, [x29, #-20]                 // 4-byte Folded Reload
        adrp    x8, :pg_hi21_nc:_ZN22AndroidSizeClassConfig7ClassesE
        movk    x8, #:prel_g3:_ZN22AndroidSizeClassConfig7ClassesE+4294967296
        add x8, x8, :lo12:_ZN22AndroidSizeClassConfig7ClassesE
        add     x8, x8, w9, uxtw #2
        mov     x9, x8
        str     x9, [sp, #32] // 8-byte Folded Spill
        cbz     x8, .LBB0_9
...
.LBB0_9:                                //   in Loop: Header=BB0_1 Depth=1
        ldr     x2, [sp, #32]                   // 8-byte Folded Reload
        adrp    x0, :pg_hi21_nc:.L__unnamed_2
 movk    x0, #:prel_g3:.L__unnamed_2+4294967296
        add     x0, x0, :lo12:.L__unnamed_2
        adrp    x1, :pg_hi21_nc:_ZN22AndroidSizeClassConfig7ClassesE
        movk    x1, #:prel_g3:_ZN22AndroidSizeClassConfig7ClassesE+4294967296
        add x1, x1, :lo12:_ZN22AndroidSizeClassConfig7ClassesE
        bl __ubsan_handle_pointer_overflow
```

So it seems to me perhaps something in the llvm backend is incorrectly assuming:

```
 adrp    x8, :pg_hi21_nc:_ZN22AndroidSizeClassConfig7ClassesE
        movk x8, #:prel_g3:_ZN22AndroidSizeClassConfig7ClassesE+4294967296
 add     x8, x8, :lo12:_ZN22AndroidSizeClassConfig7ClassesE
```

could be replaced with

```
        adrp    x23, :pg_hi21_nc:.L_ZN22AndroidSizeClassConfig7ClassesE.hwasan
        movk x23, #:prel_g3:.L_ZN22AndroidSizeClassConfig7ClassesE.hwasan+4294967296
 mov     x22, xzr
        add     x23, x23, :lo12:.L_ZN22AndroidSizeClassConfig7ClassesE.hwasan
        mov     x24, #4611686018427387904
        add     x8, x23, x22
        add     x2, x8, x24
```

which is valid but only if _ZN22AndroidSizeClassConfig7ClassesE is non-interposable, which it is.
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzsWV9v6jgW_zTpyxEocUKAhz60Zaq5q7t3VnNHWmlekJMciLeOHdkO0H76lR2TBBpaeqd3nqaqWpPY579_5w9Ua7YViLfB7D4g5D_sX7LhqANCgtnqhjamlOr2-PQmk8Xz7R8lwkZyLvdMbCGXBQbxXRCugvD4Nw39r_uojWpyA3eiUJIV39kLPnCq9YMUG7aFYH7fbgPQhhqWQy6FNnioFTTCCVeAO4DayjhbQRCvhsfsT3gIw5CEAXlol3G_TPrlrF-m_XLeL5f9MrPLVyzyfgN2y6hnHPV0o34v6RnH_d5kNsYi7cVZ9FrQqFvm3dMo7J5GpF9mxXFJ2qdnLEjRqRnPu2XSE0sW3XLWM57H3XLRcYvCcMgimK-C2DvmZO0Dofdv79tvTeXdax3rCWn2gnITkMV41NiAi--OUUGWEJDHj52Z3YfBbBWQ5ZmMO8kK2DQiD8jiKOKFXbViwvyb1gFZOBH6iNxIBYPz8MWFbBjE9275MNDZPQvIvftdnoa1F-M6db6cqeN80Tli7F62fx9kVTOOBeyZKSFIw5xTsW0lgsnEULVFE8QrSlVepsmkEU9C7sWEM9EcJlvRwOS3CCabHdMsY5yZ5yBelawoUMBko6lghr2gfbanRaFQ69PHjShww6yVJtoUQbzKW97RHCYbISd4yLE2TArdflbGMJjk1uOmqgPyqLBWsmhyVNM8h8l3mEiYBGkICnXDjQYm3sYnoIWqrb0PJLZRHcR39XZdMhKtRR7Ed9Ov6z-_ETLuhrn3wC_Tck81Fecko-UYyWsIvhIuuiDcuhGCVliso-FFB6jk7mmoFontYYV8vY0_rBa5T8gyWaZzskw9m46-1_GM_lU6vkXWK_xa7IHCI-d77aElQyyZw4s6fU-LAgbW6X3PZUR-0OuvWCdegySNonSRhtEiIfN4MV-GyQVpWlv2YeOl-UDAvNIvavWLXul3HjjTr_f34ToK4o7IpZ-APFrEtXgd__JHyTR8EQIVfJWyhl-RFqgslRXWpgziVXRBtMXA8tZPr3YdWt_5fWc2y6vaa3g02cnrbMoltCrFXr_pdKhofL2iAEw45eyRo34rZ61LSnZBEB7NP_46GhVem_rERM53s3td2_rnspxROsmeDcKj5AUW8L1mnJ9Zhbf_1-sm01SsSyoKjutaMmFQreUO1YbL_RAuO7PBdI_U3s2PR-PUZ4TrT041muu2kwf4MJZduo-jKdIFeE4FMJFLpTA3_NlnFxsXQRq-Z800hJxym2WHJNgGqJCmRAUuBzKb5kBuHMVrNE9DYBpqJXescLSBgsaaKmoQZPY_zA1sGEegwuZ3oaFolC3aORNPTGyn4FRjGjLMaaPRMi_lHkyJQPdPe6oKV-BvUQA1BqvaaDAStmjcHkO3WyzgmNhd3ZOG1xQsVnRhpN1-INbeb6ZoH96281DIcUeFgYwZfRpkfteBxLBnnENJd-jEDMhdI1pZA3J3Iu6PAOunVws9Jjz9zGzt0fJvy4cXvJOcecfQra2Ww0NiK-B9yfLShmRJVWFjr4ASFX5ehh1NOqOi3hVFJ6C0wWo_HAMJ_CW_ZMWRxHUszFvqq5ZeLquaKqalgI2SlVO2Q9xROPrmLijTsJcNL8BgXgpm4eU5II9UMVNWaNoHkCHY4hqkaPHGcqwV7ijjFgcGsOPv7rW4s6e6FWIAMwGZ6wFJq3vWmA5bPoZqNtVYClQ8Q4uRQ0BruYgtMAO5M8Peop9xyAaGVS3muRijULDNBhUKY13pQa9CKnSLDh6CwPcRbcC1QSpwhwqs9GeWszFxbFyQa9y7M5Yn07BD9Qy60a5zyThayDSKbbfo0NflCmdwH0ODINAjXrK8SlrXKBz4ZgjcdmUKTEnFuBesnqcpDOHL746n268Fq2s0wKV80uBT0tsY3GoLPpG7DjhIwvWfi2MfvPONMJc55V1tacHWXtCw7237ggICMpu75rguGbA0sUUOhO2dnoXgelpX-djP0cy_iGL3pqexcDS2aJBjhcLURgETmWxEoe3pmMABWEw8PfvayX5ddWHlCo8LK_GA89Jx1iUH0exB6H2_iTwAGeyMQrfVIoTfsvSyGBsFFgI_IJcNBJZaxGxtEgl5bKrtp8WQceQYM1svu5Kl5d6OcH4y-0wBi1oh7EZOM-TuIzn96HNeVCtb_pDoTbLtX5eVLtXtF36C-N5erEK3M0QyO2ZHQxl3JVof2O-UdK25hBSi4dwe6CLkU0w6cNLS5bd37fzamKN7-9zy5ljIIlmb7mRtWMVebJmnNVYZf_4IagwqN5839XOVSW5hstGjyZ0XjbL_90t_9w_HKIsnJBxrgDyT5KT5-R25pMWF2m3xF6cyw4qtp_dJE5BBLeEriMWnTQMG9Fr7Ngezt5KTCxXW0h84a0_V4G3bmLYGcBh7dMjivW40z14GYrVt-XK0WV_-1GadF14fMq7PRV6L60MufG98R84HYOF78y_yTvT0VDruI9OfV3OX4-jyk-_I6DjvM-6IH6H81TuS8SunImN4-V3aUlQjVq5GqxBqVCWtNWhZoSldrSocpHK-qyCj-RO21eJwJEC1biomttdOrD8Txz4XxMYQ50e8M2rttuTPEBTWnOb-24u3LHYe3P8073_DMPvd-S5cbJXHvN6NBnaUs8L1lse-9qoCi2lbr03cna6lppltlh6OEwcDTE9vitu4WMZLeoO3UTpPw3S-WMxuyts8SSMkdLMhxYYuN0U0z2ezdJ7GBQ0xipIbdktCEockCgkhSTKbLjd5FpMsTmgeR0myCZIQK8r41N7_qVTbG6Z1g7dpmKaLG1e9af8tvMA9uJf-a3h1a89MsmargyTkTBvdUzHMcLz9ravSfv3v3Xcq3Nju2NEOMKYr4m4axW9LY2ptscZlsy0zZZNNc1kF5NHS9_8mtZK2vQzIo5NKB-TRSf3_AAAA__8aEk1e">