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

    <tr>
        <th>Summary</th>
        <td>
            [DebugInfo] dereferencing pointer to local variable shows uninitialized data due to DSE
        </td>
    </tr>

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

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

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

<pre>
    cc @jmorse

When Dead Store Elimination (`DSEPass`) eliminates stores into an object, this is tracked in DWARF debuginfo such that the debugger can still show the logical state of the object; but when the debugger looks at a pointer to the object (in particular, when a pointer to a local variable is passed to an inlined subroutine), when the debugger follows this pointer, it will potentially see uninitialized memory.

This might be related to https://github.com/llvm/llvm-project/issues/38112#issuecomment-981001844 , which is also about DSE causing issues with debugging.

Reproducer:
```
jannh@horn:~/test$ cat debug-dse-pointer-test.c
struct s {
  int a;
  int b;
};

int blah();
int bar(struct s*);

__attribute__((always_inline)) inline int baz(struct s *s) {
  blah();
  s->a = s->a + 1;
  s->b = s->b - 1;
 return bar(s);
}

__attribute__((noinline)) int foo(int a, int b) {
 struct s s = {.a = a, .b = b};
  return baz(&s);
}

int main(void) {
 foo(1, 2);
  return 0;
}
jannh@horn:~/test$ cat debug-dse-pointer-test2.c
struct s {
  int a;
  int b;
};
int blah(){return 0;}
int bar(struct s *s){return 0;}
jannh@horn:~/test$ /usr/local/google/home/jannh/git/foreign/llvmp-build-debug/bin/clang-12 -g -O2 -o debug-dse-pointer-test debug-dse-pointer-test.c debug-dse-pointer-test2.c
jannh@horn:~/test$ gdb ./debug-dse-pointer-test
[...]
(gdb) break baz
Breakpoint 1 at 0x401117: file debug-dse-pointer-test.c, line 10.
(gdb) run
[...]
Breakpoint 1, baz (s=0x7fffffffd6f0) at debug-dse-pointer-test.c:10
10        blah();
(gdb) print *s
$1 = {a = 4198720, b = 0}
(gdb) bt
#0  baz (s=0x7fffffffd6f0) at debug-dse-pointer-test.c:10
#1  foo (a=a@entry=1, b=b@entry=2) at debug-dse-pointer-test.c:18
#2  0x0000000000401150 in main () at debug-dse-pointer-test.c:22
(gdb) frame 1
#1  foo (a=a@entry=1, b=b@entry=2) at debug-dse-pointer-test.c:18
18        return baz(&s);
(gdb) print s
$2 = {a = 1, b = 2}
(gdb)
```
**Note that the outer function `foo` can correctly display the struct contents, wrong data only shows up when following the pointer argument in the inlined callee.**

Relevant DWARF:
```
0x00000059:   DW_TAG_subprogram
                DW_AT_low_pc (0x0000000000401110)
                DW_AT_high_pc   (0x0000000000401138)
 DW_AT_frame_base        (DW_OP_reg7 RSP)
 DW_AT_call_all_calls    (true)
                DW_AT_name      ("foo")
 DW_AT_decl_file ("/usr/local/google/home/jannh/test/debug-dse-pointer-test.c")
 DW_AT_decl_line (16)
                DW_AT_prototyped        (true)
 DW_AT_type      (0x00000038 "int")
 DW_AT_external  (true)

[...]

0x0000007a:     DW_TAG_variable
 DW_AT_location        (indexed (0x2) loclist = 0x0000003e:
 [0x0000000000401117, 0x0000000000401120): DW_OP_reg6 RBP, DW_OP_piece 0x4, DW_OP_reg3 RBX, DW_OP_piece 0x4
 [0x0000000000401120, 0x0000000000401123): DW_OP_piece 0x4, DW_OP_reg3 RBX, DW_OP_piece 0x4
                     [0x0000000000401123, 0x0000000000401125): DW_OP_breg7 RSP+0, DW_OP_piece 0x4, DW_OP_reg3 RBX, DW_OP_piece 0x4
                     [0x0000000000401125, 0x0000000000401129): DW_OP_breg7 RSP+0, DW_OP_piece 0x4
 [0x0000000000401129, 0x0000000000401138): DW_OP_breg7 RSP+0)
 DW_AT_name    ("s")
                  DW_AT_decl_file ("/usr/local/google/home/jannh/test/debug-dse-pointer-test.c")
 DW_AT_decl_line       (17)
                  DW_AT_type    (0x00000041 "s")

0x00000083:     DW_TAG_inlined_subroutine
 DW_AT_abstract_origin (0x00000027 "baz")
                  DW_AT_low_pc (0x0000000000401117)
                  DW_AT_high_pc (0x0000000000401131)
 DW_AT_call_file ("/usr/local/google/home/jannh/test/debug-dse-pointer-test.c")
 DW_AT_call_line       (18)
                  DW_AT_call_column (10)

0x00000090:       DW_TAG_formal_parameter
 DW_AT_location      (DW_OP_reg7 RSP)
 DW_AT_abstract_origin       (0x0000002f "s")
```

Disassembly:
```
$ objdump --disassemble=foo -Mintel ./debug-dse-pointer-test
[...]
0000000000401110 <foo>:
  401110:       55 push   rbp
  401111:       53                      push rbx
  401112:       50                      push   rax
  401113:       89 f3                   mov    ebx,esi
  401115:       89 fd mov    ebp,edi
  401117:       31 c0                   xor    eax,eax
 401119:       e8 42 00 00 00          call   401160 <blah>
  40111e: ff c5                   inc    ebp
  401120:       89 2c 24 mov    DWORD PTR [rsp],ebp
  401123:       ff cb                   dec ebx
  401125:       89 5c 24 04             mov    DWORD PTR [rsp+0x4],ebx
 401129:       48 89 e7                mov    rdi,rsp
  40112c:       e8 3f 00 00 00          call   401170 <bar>
  401131:       48 83 c4 08 add    rsp,0x8
  401135:       5b                      pop    rbx
 401136:       5d                      pop    rbp
  401137:       c3 ret
```

Tested with:
```
clang version 22.0.0git (https://github.com/llvm/llvm-project a9b8dfe7b5f224e2d442352979cf2e0c1c0b539b)
Target: x86_64-unknown-linux-gnu
Thread model: posix
InstalledDir: /usr/local/google/home/jannh/git/foreign/llvmp-build-debug/bin
Build config: +unoptimized, +assertions
```

When building with ` -mllvm --print-after-all`, you can see that the initial two `store` instructions in `foo` disappear during `DSEPass`:
```
[...]
; *** IR Dump After MemCpyOptPass on foo ***
; Function Attrs: noinline nounwind uwtable
define dso_local i32 @foo(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 !dbg !8 {
entry:
  %s = alloca %struct.s, align 4, !DIAssignID !20
 #dbg_assign(i1 poison, !15, !DIExpression(), !20, ptr %s, !DIExpression(), !21)
    #dbg_value(i32 %a, !13, !DIExpression(), !21)
    #dbg_value(i32 %b, !14, !DIExpression(), !21)
  call void @llvm.lifetime.start.p0(ptr nonnull %s) #4, !dbg !22
  store i32 %a, ptr %s, align 4, !dbg !23, !tbaa !24, !DIAssignID !29
    #dbg_assign(i32 %a, !15, !DIExpression(DW_OP_LLVM_fragment, 0, 32), !29, ptr %s, !DIExpression(), !21)
  %b2 = getelementptr inbounds nuw i8, ptr %s, i64 4, !dbg !30
  store i32 %b, ptr %b2, align 4, !dbg !23, !tbaa !31, !DIAssignID !32
 #dbg_assign(i32 %b, !15, !DIExpression(DW_OP_LLVM_fragment, 32, 32), !32, ptr %b2, !DIExpression(), !21)
    #dbg_value(ptr %s, !33, !DIExpression(), !39)
  %call.i = tail call i32 (...) @blah() #4, !dbg !41
  %add.i = add nsw i32 %a, 1, !dbg !42
  store i32 %add.i, ptr %s, align 4, !dbg !43, !tbaa !24, !DIAssignID !44
    #dbg_assign(i32 %add.i, !15, !DIExpression(DW_OP_LLVM_fragment, 0, 32), !44, ptr %s, !DIExpression(), !21)
  %sub.i = add nsw i32 %b, -1, !dbg !45
  store i32 %sub.i, ptr %b2, align 4, !dbg !46, !tbaa !31, !DIAssignID !47
    #dbg_assign(i32 %sub.i, !15, !DIExpression(DW_OP_LLVM_fragment, 32, 32), !47, ptr %b2, !DIExpression(), !21)
  %call3.i = call i32 @bar(ptr noundef nonnull %s) #4, !dbg !48
  call void @llvm.lifetime.end.p0(ptr nonnull %s) #4, !dbg !49
 ret i32 %call3.i, !dbg !50
}
; *** IR Dump After DSEPass on foo ***
; Function Attrs: noinline nounwind uwtable
define dso_local i32 @foo(i32 noundef %a, i32 noundef %b) local_unnamed_addr #0 !dbg !8 {
entry:
  %s = alloca %struct.s, align 4, !DIAssignID !20
    #dbg_assign(i1 poison, !15, !DIExpression(), !20, ptr %s, !DIExpression(), !21)
    #dbg_value(i32 %a, !13, !DIExpression(), !21)
    #dbg_value(i32 %b, !14, !DIExpression(), !21)
  call void @llvm.lifetime.start.p0(ptr nonnull %s) #4, !dbg !22
 #dbg_assign(i32 %a, !15, !DIExpression(DW_OP_LLVM_fragment, 0, 32), !23, ptr %s, !DIExpression(), !21)
  %b2 = getelementptr inbounds nuw i8, ptr %s, i64 4, !dbg !24
    #dbg_assign(i32 %b, !15, !DIExpression(DW_OP_LLVM_fragment, 32, 32), !25, ptr %b2, !DIExpression(), !21)
    #dbg_value(ptr %s, !26, !DIExpression(), !32)
  %call.i = tail call i32 (...) @blah() #4, !dbg !34
 %add.i = add nsw i32 %a, 1, !dbg !35
  store i32 %add.i, ptr %s, align 4, !dbg !36, !tbaa !37, !DIAssignID !42
    #dbg_assign(i32 %add.i, !15, !DIExpression(DW_OP_LLVM_fragment, 0, 32), !42, ptr %s, !DIExpression(), !21)
  %sub.i = add nsw i32 %b, -1, !dbg !43
  store i32 %sub.i, ptr %b2, align 4, !dbg !44, !tbaa !45, !DIAssignID !46
    #dbg_assign(i32 %sub.i, !15, !DIExpression(DW_OP_LLVM_fragment, 32, 32), !46, ptr %b2, !DIExpression(), !21)
  %call3.i = call i32 @bar(ptr noundef nonnull %s) #4, !dbg !47
  call void @llvm.lifetime.end.p0(ptr nonnull %s) #4, !dbg !48
 ret i32 %call3.i, !dbg !49
}
[...]
```
</pre>
<img width="1" height="1" alt="" src="http://email.email.llvm.org/o/eJzsWklv27r2_zTM5sCGREoeFlnYcfJHgXv_LdLi9e0MSqJltjIpkFSGLt5nfzikZMmOMnS4vW9xhQS2KZ6BvzOSErdWlkqIS5KuSbq54I3ba3Pp9uLL_iLTxeNlngNJoi8Hbawg0YpEq897oWAjeAEfnTYCrit5kIo7qRUQuiCzaPPx-gO3lswiQpcg2vvCgkUCC1I5DVyBzr6I3BF6BW4vLUgLzvD8qyhAKth8Xt3eQCGyppRqp8E2-R7cnjtwexHGS2Eg5wqsk1UFdq_v_b1KlzLnFVjHnQC984OtLLaGrHFwj2s44VNp_dUCd8Ch1lI5YcDpASUuTSqouXEybypuUG3P5oSAQ6VR9h03kmeVwEXV3FpRQFizVJVUogDbZEY3TipB6PLI60Slna4qfW8DOK0MnCkd3OOCa-2EcpJX1SNYIaBRUkn8Lb-JAg7ioM3jNNjsE7I4yHLvIBNgRMVd0GjvXG0JWxF6Q-hNKd2-yaa5PhB6U1V33cekNjqY6kZa2whL6A1bxDEllPmBXB8OQrnJchFHUbxIEghLkvkeEeCV1cAz3TjYfLyGnDdWqhICL7iXbt-uWqqy1fhW1EYXTS4Mahet0JnCX7T6wpXakyTaa6MIW_2H0BsnrCM0gZy7wGpSWDFpQZvg3WlOopV1pskdWCDzNYlWgK4InLD-RxZ-kPmm_RKt_HDF9-jcdBmG_Rg6waJjSejqeJdEq-2WO2dk1jix3XrKBa_u-aPdBg_wVl-27hAk828DdkDoyuKMTtNzDQDshLBrDoRtjl_pGuKT21l_O4PJ8aYRrjGqW0Gv93zzrPZKnynuYKe1jwqEEP3Sw9erfFyK9UqQ-XoatPWzp0G17Ig09Fp98yJnI4qhjAOXitDFnZbFQFpQJkbWdABSyzMa8vkh_6E_6EBn3jNfDzXy6jz1pc74Y7NfUJ7Qm8YajFnMQRjPWpeVIPRmrw_4EWh9nBN6s9NGyFK1MV5PskZWxcSvntCbDEG-ySuuyklMYVLC5D2FiX4Gnmej7kU4X1hMWWQwJfRmnBwRTtfT6ZSk3jPooiy872VG8K_ehaLVGr97KogxtUcPSRTH8ZywFexkJZ7PFPQKfFzG0fSEu2nUmeShDCTL-DfwMcU20cN8F65itvOl8KXkxFYx5rY4gvY6D_hei9qgOO8jOJzEXXyF8Eri5WJOI6-NH4ja8OlB8vhRFsFP60soiwGDD7lwwjacJJFQzjwStgmIELbJBoP0DZwXgTMFiB6i44XWSyNsDjAFQADnFVaUnqx8Z_hBQPyXKh4vOhO-kNDOjNlakp5aMu5tSM9seFYSffVZ_b92ou-RdINNya5ReejNZhHmyFnke6ZcGyNyVz1CIW1d8UdP0iagXCtsLawv4karEgruOGiFncYee5KmDg1L6FGwmCN51whxUzbYD6CpcLxrenJeVUJMg7Jdna_EHVcu9HtPa31n_3SJUQuw-bz9tPq_rW2y2ujS8INPvKfX5vN29Wlb6fttnaN1z30ojgKA43R7We6REMZI2aIlDXO9O20zbkXHg9DF5vP2_YetEeUcbj9-OJmPAGzxH7_Ydr4zjXhJIYUu2zEnlPpKR0_4FiKvtj6lhSlvrgQh2z6TZDERjsjxmRFr7ewlrWujnXaPtSgG0AyWGmbhhOPdDmy2AEKpVO5cvHhwwihenfE6Lwa918x58Jqj33R9ec8TEfLx0WspVSEeRBFU8lFf6byS1oVs2mkpgrcCSddPPGyOoXM-Sr3fMS85eMgMbtcfcGoYqaXIBZapfsiIksHt-t9jk8Zlh8z_ZJSdyP5-SWPXmHQ2Kj09kZ71wbGOfmb5b1UqHVVq-X1KPQP3cox3yBPP8R64dBfcIW5t7_FPrr8r0o9hgU79kmpdLA8iGVuT4aoGoblgZ6HZFontYGd81IZn1hmeu602sgylv-ND5yjCl9hXoHuhILyysq4kjBWE-GmC_w3m8XLOzLN4eRGeJNdVc_D4dUVwYJJl1JnkaJSdNgdebWuOhc4J81zefLnsnZvvSHM04u7MT4atTbTaSMutFYesenzaIeBmQWdfiuZQw2RSHKcKwjbY3k3-RCCrt28mzpsFIOwKay67bhM-tE3EEaw0hbqxe-z4srqfEQ9msNFcFchM9tAT0QFR9AIRgOEDMtaTLZawGxN30Hf4IbIHQq-ElT1xekpc9FNrnFoMps77qSyGfEzDB208MfdygpKedtnTigUkFKKo_Tte6KQQRM088H4XxK57BYTfve0gT0dES5V3encENDpZHM2BJt36Np_f327gw6dbTOzG1mh_enVCPcAVhWYjQguRe1CPNKdwpl5ilIzZ4okCdI2VplXjiBwdIJcskKmYP2NdU0hCr5DVUZ38BHa2exn2eYCdmyHqLD5VgEGeQLQAXvjuzmt-FT0seoIBBukYaOjGuvbE_TrZbEBVvELVr5ANnDJnuOt6mkI-CetE4c8an6YQf8oBd8JYTGiUTqNpVEp_5vt9B6TAl9mi2Il5lu4oTQQtkoSylC7ny3xHRZTHeZSlbNnu4D5xUwqHyj8sZttZMmnUV6Xv1aSSqnmYlKrxZ7dGcAzJQlQ4tdZWImLvlHW4nyo20uD4Lz_9iVZrHMPd4E6WQcS6Ubp28iC_iQL7HkLXmG4NVgL7FHX_rMBzxi2iP-jFDejkgDJhMvGb3wnfYSbmVeWfGFzBo27Cub4Y7Gbbs21w9xp5-EcJyEuqsGlFBXC_2W9zsRTUteAGisag_NNHE08LyXAPwdbQblPpCt7dwgbLywoVhT_F4ap-fF875ARatYcIq35by9Zw0227V84ZdCDoDlBB6UbdS1VAc-_avUghdninsHobnh9IRoEkUXvCyqgnKgSWyTQctp6OZe0uhVfbRmFPWWx5URjwhzyExkVW4seiPbdsjzRCNSM0DSe0vEIO_reHdOoPAHglSwVJsHa8ebfyz4zebfAXjXxXTFmRldvwMAn1jaHW0mrV0sTpkfj6oTbCYpi1R1vhRtiz1M544a_OjvtOp5V9xyvcDXqoOohQMvt5XlnHK3k7L59P77Qs0Ijo69NK7oSTBzG1jhs3rSNCF7hepZVqqqpd9xJ16OS0NvMnWBCencFwfUO4To3UUXardxnnfuAZK54B0BvyDM1n7Bg6vz_--Nef253h5UEo_1DP25TRAT7LH7MyGiGcjJXCiUqgAOQiVYYRYEE19yAX58zlLDlHhEVPscwGdBl9O5gsHgWT0dGQOPOl70OS0XMow8iJ1j_o5WfmYK9GDFsO7IKOPpXeNo7LKjh-WOwCkyl6dBL1R9kj_p3EHTNeFC0v7CuUvT9x9_iMbCwskMGbQiN5Y2gkySuh0Un8BeGRJD8cHrbJxpHzDjc5hy59Cp3n8LZISGZvi4Rk_jJ2R5G_IiCS-Q8GROvErMWvd-AkCg_lQpYOlfb1bJ0sXisAQhXfk_6TZfvAtrNUq-3prDTqn5K-0Lq07c8_Tcu4X_7Tt_zyvuWvbinY391S0FcqxC8r-eEQ-y8o-XT2asmnv7bks3CY_p0Vn42UrbdXfPakas3Hqxb9jRWf_q6Kz36u4idn2CXpOHaz31nxZ_8jFX_-qyv-4i0V3_cFbcUfHlx0BxoXxSUrlmzJL8RlPE-XjC3T5fxif7mk0WK2jPNiNhezXZrRNMoZT6N4xnezPOIX8pJGNI2jKI7ndMbm0zktlllGeZxns5zO5ySJxIHLauqXqU154d_ku4xncZqmFxXPRGX9K6WUKnEf3vMjlJJ0c2Eu_XlZ1pQWcZLW2Z6Nk67y76JuRNaU79ROk3QDhTBiJ4xQuVTl8GXLs1ct2zcTTt6C9O8tFI3A6ZuP1xeNqS5__J3HdoF3l_S_AQAA__9lzPzJ">