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

    <tr>
        <th>Summary</th>
        <td>
            memset interception in compiler-rt asan is incompatible with ntdll.dll 10.0.26100.2161 from Windows 11 24H2
        </td>
    </tr>

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

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

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

<pre>
    ntdll
===

[ntdll.dll 10.0.26100.2161](https://msdl.microsoft.com/download/symbols/ntdll.dll/6C29F8C2263000/ntdll.dll) from Windows 11 24H2 26100.2161 differs from previous versions of ntdll.dll in a subtle way.

Previously RtlDispatchException would almost directly reach into the vectored exception handlers:

```
// ntdll 10.0.19041.5007
push    rbp
push    rsi
push    rdi
push r12
push    r13
push    r14
push    r15
sub     rsp, 1D0h
lea rbp, [rsp+40h]
mov     qword ptr [rbp+1E0h], rbx
mov     rax, qword ptr [ntdll!__security_cookie]
xor     rax, rbp
mov     qword ptr [rbp+180h], rax
mov     rax, qword ptr gs:[60h]
xor     ebx, ebx
mov r15, rdx
mov     qword ptr [rbp+40h], rdx
mov     rsi, rcx
mov byte ptr [rbp], bl
test    dword ptr [rax+0BCh], 800000h
jne ntdll!RtlDispatchException+0x687c4
xor     r8d, r8d
mov     rdx, r15
mov     rcx, rsi
call ntdll!RtlpCallVectoredHandlers
```

But now, two buffers of respective sizes 0x58 and 0xD8 are memset to zero before reaching into the vectored exception handlers:

```
// 10.0.26100.2161
 ntdll!RtlDispatchException:
push    rbp
push    rsi
push rdi
push    r12
push    r13
push    r14
push    r15
sub rsp, 210h
lea     rbp, [rsp+60h]
mov     qword ptr [rbp+200h], rbx
mov     rax, qword ptr [ntdll!__security_cookie]
xor     rax, rbp
mov     qword ptr [rbp+1A0h], rax
xor     esi, esi
mov     r15, rdx
mov     rdi, rcx
mov     dword ptr [rbp+20h], esi
xor     edx, edx
lea     rcx, [rbp+50h]
lea     r8d, [rsi+50h]
  // memset(something, 0, 0x50)
call ntdll!memset$thunk$772440563353939046
xor     edx, edx
mov     byte ptr [rbp], sil
mov     r8d, 0D8h
mov     qword ptr [rbp+8], rsi
lea rcx, [rbp+0C0h]
mov     qword ptr [rbp+10h], rsi
mov     qword ptr [rbp+18h], rsi
mov     qword ptr [rbp+48h], rsi
mov     qword ptr [rbp+28h], rsi
mov     qword ptr [rbp+40h], rsi
  // memset(something, 0, 0xD8)
call    ntdll!memset$thunk$772440563353939046
mov     rax, qword ptr gs:[60h]
test    dword ptr [rax+0BCh], 800000h
je ntdll!RtlDispatchException+0xa0
cmp     qword ptr [ntdll!RtlpExceptionLog2], rsi
mov     byte ptr [rbp], 1
jne ntdll!RtlDispatchException+0x609
xor     r8d, r8d
mov     rdx, r15
mov     rcx, rdi
call ntdll!RtlpCallVectoredHandlers
```

Now let me detail why we care here.

memset interception with ASAN
=====================

When compiler-rt ASAN instrumentation is in place, memset is replaced for instrumentation purposes. So any memset will go through:

```c++
#define COMMON_INTERCEPTOR_MEMSET_IMPL(ctx, dst, v, size) \
  { \
    if (COMMON_INTERCEPTOR_NOTHING_IS_INITIALIZED)        \
 return internal_memset(dst, v, size);               \
 COMMON_INTERCEPTOR_ENTER(ctx, memset, dst, v, size);  \
    if (common_flags()->intercept_intrin)                 \
 COMMON_INTERCEPTOR_WRITE_RANGE(ctx, dst, size);     \
    return REAL(memset)(dst, v, size);                    \
  }
```

Which, after following macros, uses:

```c++
#define ACCESS_MEMORY_RANGE(ctx, offset, size, isWrite)                   \
  do {                                                                    \
 uptr __offset = (uptr)(offset);                                       \
 uptr __size = (uptr)(size); \
    uptr __bad = 0; \
    if (UNLIKELY(__offset > __offset + __size)) { \
      GET_STACK_TRACE_FATAL_HERE; \
      ReportStringFunctionSizeOverflow(__offset, __size, &stack); \
    } \
    if (UNLIKELY(!QuickCheckForUnpoisonedRegion(__offset, __size)) &&     \
        (__bad = __asan_region_is_poisoned(__offset, __size))) {          \
      AsanInterceptorContext *_ctx = (AsanInterceptorContext *)ctx;       \
      bool suppressed = false; \
      if (_ctx) { \
        suppressed = IsInterceptorSuppressed(_ctx->interceptor_name);     \
        if (!suppressed && HaveStackTraceBasedSuppressions()) {           \
 GET_STACK_TRACE_FATAL_HERE;                                     \
 suppressed = IsStackTraceSuppressed(&stack);                    \
 }                                                                 \
 }                                                                   \
 if (!suppressed) { \
        GET_CURRENT_PC_BP_SP; \
        ReportGenericError(pc, bp, sp, __bad, isWrite, __size, 0, false); \
      } \
    } \
  } while (0)
```

In particular, `__asan_region_is_poisoned` will access the shadow memory corresponding to the region that we memset, in order to check if the region is poisoned.

Shadow memory lazy commit on Windows
============================

On Windows, shadow memory pages are first allocated as `MEM_RESERVE`. They are dynamically turned to `MEM_COMMIT` on demand -- meaning that we rely on an exception handler `ShadowExceptionHandler` to change the status of the page when we fail to access a reserved shadow memory page because it is not yet commited.

Putting it together
============

The memset interception in ASAN is incompatible with ntdll 10.0.26100.2161. As soon as a first access violation gets raised because a shadow memory page is reserved but not committed, we immediately reach a new call to memset before we get a chance to reach the `ShadowExceptionHandler`. The new call to memset itself triggers a new access violation and a new call to memset, etc. This is a neverending cycle, until eventually we overflow the stack.

```c++
 # Child-SP          RetAddr               Call Site
00 0000003e`f3000fa0 00007ffb`03adf0da     clang_rt_asan_dynamic_x86_64!__asan_wrap_memset+0x18e [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc @ 87] 
01 0000003e`f3001830 00007ffb`03c236de ntdll!RtlDispatchException+0x4a
02 0000003e`f3001a80 00007ffa`8c4c8632 ntdll!KiUserExceptionDispatch+0x2e
03 (Inline Function) --------`-------- clang_rt_asan_dynamic_x86_64!__asan::AddressIsPoisoned+0xe [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_mapping.h @ 395] 
04 0000003e`f3002180 00007ffa`8c4c56a3 clang_rt_asan_dynamic_x86_64!__asan_region_is_poisoned+0xf2 [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_poisoning.cpp @ 189] 
05 0000003e`f30021e0 00007ffb`03adf0da clang_rt_asan_dynamic_x86_64!__asan_wrap_memset+0x193 [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/../sanitizer_common/sanitizer_common_interceptors_memintrinsics.inc @ 87] 
06 0000003e`f3002a70 00007ffb`03c236de ntdll!RtlDispatchException+0x4a
07 0000003e`f3002cc0 00007ffa`8c4c8632 ntdll!KiUserExceptionDispatch+0x2e
08 (Inline Function) --------`-------- clang_rt_asan_dynamic_x86_64!__asan::AddressIsPoisoned+0xe [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_mapping.h @ 395] 
09 0000003e`f30033c0 00007ffa`8c4c56a3 clang_rt_asan_dynamic_x86_64!__asan_region_is_poisoned+0xf2 [/builds/worker/fetches/llvm-project/compiler-rt/lib/asan/asan_poisoning.cpp @ 189] 
// ...
```

Related Firefox bug [here](https://bugzilla.mozilla.org/show_bug.cgi?id=1926680).
</pre>
<img width="1px" height="1px" alt="" src="http://email.email.llvm.org/o/eJzcWltz4jgW_jXKy6mmbJnrQx64dlPTnc4CPV2zLy5hH2NNC4uV5AD967ck22DASSczedhZikqCrHP7zkXnKDCt-SZDvCedEelM7lhuUqnuj3_mG3G3lvHxPjOxEMSbEG9Igkn5Lj4WPzsjt6UVCwG-1_JatOt7Xov6XZ90JoT2U2N2mgRDQmeEzrY6Fq0tj5TUMjGtSG4JncVynwnJYkJn-rhdS6EJnZ3YEjrrjulg1h9T2g08z7t8OIBEyS1851ks9xp8H2j7E4WzGhDzJEGli307hU9c5hqeUGkuMw0ygbMJPAMGOl8bgbBnx1bd1seSVBxhYcSE6x0zUTo9RLgzXGawl7mIgYmt1AZirjAy4ggKWZQCz4wEkyI8YWSkwhjwRJeyLBaoHEh1aLte-S4-OvwKVQuk_YHX9lsdz-sVO3a5TgEA1Hp3taD51UJcX1A-vXrsB9cL7euFTrGg8zUUInaEjsGfeGnxQCBzitAxkM7IPR61vdTGhHu-lU-O8D97qWLYGeW2WYKRPy320TGo9eFyu2IHu35BVcQo9cNQY5Qrbo5hJOUPjidhB6nq1CeAXlKif1aC_UqJjfNdZ9StGVjJxLXbjHVLLHyWcXz4pR7tsxrXu61b7XpUW18fDdYZFKTrMoUNamMp4ws51pqRNxpXgvqefZV-_DNDqABuinpLeuj2e1H7Cup-7JTrx1dKx4ULqgA6rUfFehWqEROiLng3ZkL8XibPpypjGhPF_RzlBjK5tzzNXsI6L2qATECh3mFk-BOC5j9Rg3fo9IFlMXiHSR-YQtjiVqMBI-EnKglrTKTCIpN5tnm_ZL4umO7Zy3BXbF-Z7JeZ7jL37yV7mejUryd6pUg92buvS3bq_S8k-_A22U_5W2QZVrCelHsmhy3i11l5m3Ol7ZXUE_eT1CJNsOJ-QrlIkxOLTg3l054i9Zwn-NUegDL0ihAntK_lFo0Na0vjuR-HjkfooCEPK6K2SfPsB6HtXo-2216nGwSdYBAMvHb3ZTMqMJrLlObiCsvCEm_ST3_pw37lwApKdwJdweWNX3kEnePh2u-NZ8VbdrfftJu-jfet3q_z-KR_6XGAtzv9TcfjXzmKXnESsbLARtvdLUb14-RE9llu6HMIN4ep_5aT0Ru8z7kYv9O5-CD3INDAFiFGw7iAfXqEPUJkD74UFV70vOVJyDOD6tTncpPCcDl8uJ4L_tq7Ju17ihlEcrvjAtUHZZwU4Jk2Kt9iZpiTz7Vt03eCRWihqVTUoNAtxpBIdUO1y9VOatQtWEpg2bGi23MhYGPPcyXzTfrcuR0ROrLv8vgOYkx4hjD--uXL14dw_rCaLsbTx9XXRfhl-mU5XYXzL4-fCe1Hxvkv1sb-eirK3E-0cwvpjE8p2hvVPwLwBAjtN3B_-Lr6NH_4GM6X4fxhvpoPP8__PZ1YduXrzEahyVVW-C5jIjwVgAZlSDCCy9eZT4MWU_v32bqKc6OdjnWDcZHcbmUWJoJtNKG2_nwgwfQUaSHPjOJZzbLXqfZ9MV9Nw8Xw4eP0Bv4rYy-UKtFaTIfWbZVFg9fCdc2Q9CYvZOH3lEep5ccSgwoSKYTc29Zyy-xobJ_kGp9tIp8JxuF4PF0ubQB-XfxxDYFMktJHhQ1j4Pq74gabEL4wJZYuPt_hdWaa26oahoVSQIKJjQi7WEBeKfsc0K_hbc285Vxz4IX7S6I1ix2Nd7OhCNpvD5_nv00__0Fov6b9tGYKHZWynbzBbWoDfJyuwuVqOP4tXC2G42k4G66Gn8NP08X0RirAAndSmaXNhc0szyJbzJb8J359QpUIO-GcNLFOrWSPgdCuNiz60WQt6U1-YR2h_r9yHv0Ypxj9mEn1LdtJrmWG8QI37nRrFFuYTLuEdq_DqHSTpatQDkOmWRYqxzHkOqxkvMC9wrQpUu1rqFk2r4qIVGOZGTxYvwzDyByqgHh-F6EDmzGnuLtiv5ZSgM53O4VaY2FGwoTGBtcVoIYuARsDAa45zXVNqeXpWcnloj5KFWZs-2w5O8sn1K9LKXzziT3h0kbHSrEIR0xjXInjMivr8Q3UNREvx_DbEvYGhLNmFxhcRfSLPG2E_93X-3Kr82vwzLMhYpEef1sspg-r8HEcjh7D5WNDsFWV4iNmqHg0VUoqQvu7yF0Audm8GN1d-l3U_3rVcPNAEdANdaOhclwt2I_7lAu0Bp7HyMZTcJ7BjinDo1ww5UpW13u-JHS9oldjUYRau_sXnbJY7m37IdURIqkU6p3MYnuSllc0BSMwKTO2yz13KjwDqWJUdmNki5x1So2Ca6hEX3TEywuZgv20grdbbkBm1S30-zTGv-qWv57lWede6LVjG9TuLivhShtgQsiIGYyBaQvzl-mXcDFdThe_T0nXa8EqxaPbHh8ztuV2yjiCbYgwtgCVFLbdmq-sJ2QGMW5ZFsOHD7BFljnIS5AViqPdwbLbizHLqoDwNCiVU4tl63zBsg0W7jXM5O7Ozn6yJsHeTgh7hMROLkZWwcBAoUb1hHEDDrDGiOUagbspIZMGjmhKr1159zE3xl3xGTBygyZF9QZn1hit0tM14sXwxLNyqLFDjB11mOFrgcVQVbvcP98KtmCoQUuLpzW09Gdh9xOXohhvNmg0KMZtEa3sZU1guDmpxGrtLkkrKAy6srBH4NstxpwZPP3_gkGGe3DDp5GVYeW96B6tdGDOdRHaDQWR9dpL7nZh18SYG40iAaP4ZoNKl9JvbLbh16SYu3IykWVvYS7on1BhURmiYyRcrcszwwXgE2YmdwG_R5BlW1UFYPSj9esWHAgNYJxyEX9YPp7r_QLNMI7V1SlgB3ZY2sLraD0P3CWHFyDpekngeV7CirVekqxJ1_MCFideXFzuRYJlm1CZokyW2Roe-t2w23bXom59r9juNO-NvIPfRyCdEaGzdc5FrAmd7aX6gYrQWYImStEuCfG0_bBT8k-MDKGz2iBuH_I1oTPLndBZq0XoTLOMG_4TVViMcg1LYa1d0VahYqjTPNItnkVA2h70e6QzgRIM_xoMvx9cgRHRoBu_4uqlzUqe9IYn6594MtL1-lE76ncDeuL5G_-mUZ3YVfwdW1r5LbAn3DwTdvKqGnN7iH8oX6TrVX--zmt22guGNmJQ67l-PPXCI-_wvu5zWmzZbsezTSt1XggGnZob2teQUf8Wsk6XBa-Mx6YOf-QdEvr-ZhUCrGHRbudM8_uDmmmdW9OwOd3-YqoNgn9GqnVvgGC9v5tqvRueUfQOqdb_P061wTVkQXAL2T8y1cr_O7RarRdmgAUK15bOuMJEHmCdb6yiKSps-v7IOt_85EKw1lYWv6Xa2GRI5T5c55tWtOEkmPGYBBN_QLtdN4K07uL7IB4EA3aH934v8Hq0N6DBXXrvx7Hvx93Ahn6_jUHi9dqdiLG1H_sUsX3H76lH277vtf2g3aG0FfcwoQw92vE9r-1FpO3hlnHRsthZbe641jne-367NwjuBFuj0O77NZTaTsU9JZSSzuRO3TvA1_lGk7YnuDb6zMZwI_D-mRayfkduXfFCO9n0zZzGr8zc5UrcX6K94SbN1-W3dKxmtzHi7LGxUxr8dE__GwAA__-tAa7z">