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

    <tr>
        <th>Summary</th>
        <td>
            clang-15 regression w/ `-fsantize=local-bounds` and fortify source
        </td>
    </tr>

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

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

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

<pre>
    In the Linux kernel, our fortified string rountines, we basically have:

```c
#include <stddef.h>

#define __compiletime_strlen(p)                                 \
({                                                              \
        const char *__p = (const char *)(p);                    \
        size_t __ret = (size_t)-1;                              \
        size_t __p_size = __builtin_object_size(p, 1);          \
        if (__p_size != (size_t)-1) {                           \
                size_t __p_len = __p_size - 1;                  \
                if (__builtin_constant_p(__p[__p_len]) &&       \
                    __p[__p_len] == '\0')                       \
                        __ret = __builtin_strlen(__p);          \
        }                                                       \
        __ret;                                                  \
})

#define __RENAME(x) __asm__(#x)
extern size_t __real_strnlen(const char *, size_t) __RENAME(strnlen);

# define __pass_object_size(type)       __attribute__((__pass_object_size__(type)))
#define POS __pass_object_size(1)

extern void fortify_panic(const char*);

__attribute__((always_inline, gnu_inline, overloadable))
static inline
size_t strnlen(const char * const POS p, size_t maxlen)
{
        size_t p_size = __builtin_object_size(p, 1);
        size_t p_len = __compiletime_strlen(p);
        size_t ret;

        /* We can take compile-time actions when maxlen is const. */
        if (__builtin_constant_p(maxlen) && p_len != (size_t)-1) {
                /* If p is const, we can use its compile-time-known len. */
                if (maxlen >= p_size)
                        return p_len;
        }

        /* Do not check characters beyond the end of p. */
        ret = __real_strnlen(p, maxlen < p_size ? maxlen : p_size);
        if (p_size <= ret && maxlen != ret)
                fortify_panic(__func__);
        return ret;
}

#define __is_constexpr(x) (sizeof(int) == sizeof(*(8 ? ((void *)((long)(x) * 0l)) : (int *)8)))

#define strlen(p)                                                       \
        __builtin_choose_expr(__is_constexpr(__builtin_strlen(p)),      \
                __builtin_strlen(p), __fortify_strlen(p))

extern size_t __underlying_strlen(const char *p) __RENAME(strlen);

__attribute__((always_inline, gnu_inline, overloadable, diagnose_as_builtin(__builtin_strlen, 1)))
static inline
size_t __fortify_strlen(const char * const POS p)
{
        size_t ret;
        size_t p_size = __builtin_object_size(p, 1);

        /* Give up if we don't know how large p is. */
        if (p_size == (size_t)-1)
                return __underlying_strlen(p);
        ret = strnlen(p, p_size);
        if (p_size <= ret)
                fortify_panic(__func__);
        return ret;
}


extern int x;
extern size_t len;

void foo (void) {
    const char* suffix = NULL;
    switch (x) {
    case 42:
        suffix = "hello";
        break;
    case 100:
        suffix = "goodbye";
        break;
    case 1000:
        suffix = "asdfasdfasdf";
        break;
    }
    if (suffix)
        len = strlen(suffix);
}
```
in clang-15, after commit d8e0a6d5e9dd ("[LowerConstantIntrinsics] Support phi operand in __builtin_object_size folder"), we observe a runtime trap due to the `ud2` emitted from the above:
```sh
$ clang -fno-pic -S -O2 -fsanitize=local-bounds -o - x.c
```
```asm
        .text
        .file   "x.c"
        .globl  foo                             # -- Begin function foo
        .p2align        4, 0x90
        .type   foo,@function
foo:                                    # @foo
        .cfi_startproc
# %bb.0:                                # %entry
        pushq   %rbx
        .cfi_def_cfa_offset 16
        .cfi_offset %rbx, -16
        movl    x(%rip), %eax
        cmpl    $42, %eax
        je      .LBB0_1
# %bb.2:                                # %entry
        cmpl    $1000, %eax                     # imm = 0x3E8
        je      .LBB0_5
# %bb.3:                                # %entry
        cmpl    $100, %eax
        jne     .LBB0_12
# %bb.4:                                # %sw.bb1
        movl    $.L.str.1, %edi
        xorl    %eax, %eax
        jmp     .LBB0_6
.LBB0_1:
        movl    $.L.str, %edi
        xorl    %eax, %eax
        jmp     .LBB0_6
.LBB0_5:                                # %sw.bb2
        movl    $.L.str.2, %edi
        movb    $1, %al
.LBB0_6:                                # %if.end.i
        testb   %al, %al
        je      .LBB0_13
# %bb.7:                                # %if.end14.i.i
        movl    $13, %esi
        callq   strnlen
        movq    %rax, %rbx
        cmpq    $14, %rax
        jb      .LBB0_9
# %bb.8:                                # %if.then23.i.i
        movl    $.L__func__._ZL7strnlenPKcU17pass_object_size1m, %edi
        callq   fortify_panic
.LBB0_9:                                # %_ZL7strnlenPKcU17pass_object_size1m.exit.i
        cmpq    $13, %rbx
        jb      .LBB0_11
# %bb.10:                               # %if.then3.i
        movl    $.L__func__._ZL16__fortify_strlenPKcU17pass_object_size1, %edi
        callq   fortify_panic
.LBB0_11:                               # %_ZL16__fortify_strlenPKcU17pass_object_size1.exit
        movq    %rbx, len(%rip)
.LBB0_12:                               # %if.end
        popq    %rbx
        .cfi_def_cfa_offset 8
        retq
.LBB0_13:                               # %trap
        .cfi_def_cfa_offset 16
        ud2
.Lfunc_end0:
        ...
```
tagging this as regression until I have a better handle on what precisely is going wrong here. Apologies on the late report; we're a bit behind in the toolchain upgrade for Android, which is where we hit this.

I think `__builtin_object_size` when passed a runtime-dependent value has surprising behavior: it returns the max of the two rather than `-1`. The NUL-termination check is getting tripped with `-fsanitize=local-bounds`.  Maybe that code needs to be rewritten...

cc @serge-sans-paille @nikic 
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJy9WVlv67oR_jXOC2FBi9cHPyTOSRE0d0FPLwr0RaAk2uINLeqQUmz313eGolbLsXN6UcOxLVGc-WafYSKZnDevGSlSRt54Vp7IO1MZExN_S2SpyE6qgu84S4guFM_2RMkyK3jGND5xZCSimsdUiDNJ6QebBI8T93ni1p8Lt3rH9toPeBaLMmFkEmx1kSRs56ST4Ftvkx_AbWBBwjCWh5wLVvADCwGAYNnEX-UTf01uvSbzbU1uNVk-3Xz-PmL1jVhmuiBxShWZ-I9hmIM8z_Bz1V8AoBbvJBiFcEFY8_-wsADJFStqmtU9IDL1rpC5h2Ae4k9DMwyjkguwYiijP1lcmJUK6JZ4Q7QXJPkOUbUUfW8EKJjoc7VfkB1BDPa2gC2vKRlXwVViNdZaYGMfmhVhXokwmT9ZRpP5swHtL-B9iyy-hrsRaaWIJexz8euqn35KuCJeO0CLvQkA5HzLSJPl8zXaN14XpAyWm573KSlAg4ivRPk_vv36-Ms3EOyEGgtDqg9hiHHrB6dmGzsVkJm6AUIFqiSrdDIMvC1pvLHLodmA6hvgIQ2gnGo9iI3inDODZQ34CsiFUVkwi3J1ucOs1Huq90Ds33_7Ps7JG2jKCv4heWLT8Rm2ZTzuSW2zTV-oEahUHOlZhzwTAALVtM_KzpX8YEpImtBIsC5uCJqCx8Q-WN2qLHHNBDZHoph5aw5yoCerf-sYT6P56ovZ6gqNNn9cLSTXNlcu31Vm49T-C4r3L0ZiCoWTvsOPivoUyRMaFxxEJ8cUuFfiEq4rdTiVc76MJ9TRJNUorE5NVqxPsu54arG4X3ckb_DYIo6ClJoRXuieLNP3TB4zAvzGgfcFsLJiOQdkubXT-vNEB3ouwburJDq0BaaN6xZ4liST6HAsfjduB5pnSpOInWWWmJaGwbcEgcfhtyl2kEyMazXibFtvfGnvPnYkHOKu9NHs2iITw6yyYE2jMiF62jUtDeM9DHdlFmMsXzK1muw5bl9_3ZzLdeVm7JSrOvNaZ5I7-MEzkzptTWtuGzWuVkYVVUIxeanpdeAtZLavLizRR-KKKpcYtVXE7ZbVMD8OgH6t6Rt_jRS0JtJSKTULrRIutDJSe_Ma8PYK8Usmg71bWKrtekH2Mu83Ba_MEsjNZ2jC2239lJtfFrvRWve_loUtSTjdZ6g5qmsxR9VlE_RdhWREK59VlBsFpBsGg6Wfqi2jGehv_IORMsd4hyyaSMC8LAgmTZLCn6Bqz0y2_Szvt3BGE_q4d9lgH_eK0bpWJ7tBlvtyEvt_5apuDGC-ODVP9gOjWzeqT9spSWKz00VV7HVNRJe7HT8Z3fz6x9tbD6s-8iJOSZPLelQoVMyZ34y8jZe19Ca-nzIhJHxfqCCCmvPeu2sIeq57g-JeyiQ6s6_RvEWU6mRX_91HubFX6ysVyQsHqbuwxj_b5y6NX58YVJc8I7Gg2X7qzdFZ6Q4sjx3KgRckWTGXLpI5WydJVYt8mMfe5JGprW2gXjM8tNA81jiffS_zHHyU5CknMmeKQnPAs_EcAP4jILCQZpWzIb5lpJmCgKdE4RkItHqFojlJSvghTbsBuMvEh0_CAGHBwA2VPJglGsnu8Ugtpk7rijerJCXTXSanOaTI6Xcy_c2Haw0BVWCQBs9CxlRMIwlRr8lUwjx8cuJRzTWXMEzVwbF2oLAV7dUO-jz4BiGRCojarOyFjAT8wCj67IVT03RKntgeFInhjq0vxl5LKvep4PsMfs5Qj-5p7Xbw4IRk2MDaZObWJKon8HZwtXMc4sDtXcbxjkNKpKrIlWzPn-DReRQ57h2E7dMMnOjckM1Lnf4wSpur6NTnBj1LGO9oKHc7DdnWW_SX7W27E3Qx7TxxkB-o8JNx5Lnida-AAGjLJz7kwnCfQea5XP4Ttem8PT25oTcU2f9ZkVueJpE0XK9S4IeDCXj3FHxbjWGbD7EFfwm2MYVkHY34Q7az-9nqoxNF3tBcwNd5cyCxOV7NPOHNQyepqocMpBFwh7wBZz2htl17jnrB6q9kNP-iAvzrCvBHcMFDkbWOXaWiy35xP3u-c2CYc1raBdNFRRyJ9qkPIiEY2n35Vb7ezOEOHxEeaFuxdbuM5-GYI-pWq7OtTh2NmbpJBJz5hyU7q5e7VowakdZDiVZfkggKUuYHV0Ry3urOzQn__ba0Qvz-9_gPbzk8rvIOI1avxe83hB2zr-8HewcCh5140ZGko8VgRMkdLXoXOdK7oy701RjcoUNvMZxtrsjyM8r0vLshfwWK0eqY51alq2rk2krVBXRHoekFV1tbZX5naW2rCowQP3rc7yglljt2b_cWcGzrLBdjV4B92VI7jjPaixV0v8f_nRUp14RqGHv2immNrRI2koK8mn-eQWMZsQI73BRaUwENZ0aOKYWGVbGYaybOeG63l0jqqCR8pkwxhzzmUsg9Zxo3YK8paMGACTa7eGx_hFlhqQx5aJsjlvKq8cVHCykFDEJwVeZ7RRNsfBV5zBJlBifoe1MOAxA3x5lAA9rgFIigJLWs5vMVb2Xv2AGPz9TQE5sDUXQ06IubHnqasByUCVWdfFABrXQKCtKlyhXXKCjApR9cKrQqL-zgqA32A7QgcleJcZREUfil4JJmCAOG54XrkH_CKox1U1DrgWfU9KfViSHqEtRtDANenAMqmPZSs_daz21Ikl_oOWLICIZICSrLGIN2HGaACNV-VNj6Z60zmM84xgYVBog9mwJxPc0pF2BjuJnxd2j3H9jGWyx8dzH33eAh2QTJOljTh4IXgm3qIajrOseJ_9KAHcdKcMSx4U60LFXMHkolNmlR5BrdF48xXvYgdRk5MFbBhRAf9dcUGmc0IFxyrUv8l-_LfDn33Id0Eyc-TahHvVWMI9h8FS1n1GPzZbBkq-Vq_SBoxITewEQGg4U9U1ZTdMjHMgLAZrLCbOe3IpkJ7vmBb3zX99216_nubDELHG-VBMB3EdCdF8TBGnTGDqA-B1E6Uu0f1MYAjsq9hkXBdaHbRfA4GEAYM2CAPi2LVKoN5NH3hGlaiowzpR-MjBsj4H8Bb9J-IQ">