Open edumoot opened 5 months ago
@llvm/issue-subscribers-debuginfo
Author: Yachao Zhu (edumoot)
GDB produces similar things:
Breakpoint 1, func_1 () at case.c:20
20 *ptr_to_global_pointer = &local_var;
(gdb) info locals
local_var = 3
ptr_local_var = 0x7fffffffdaf4
ptr_global = 0x7fffffffdaf4
ptr_to_global_pointer = <optimised out>
(gdb) p *ptr_local_var
$1 = 21845
(gdb) p *ptr_global
$2 = 21845
(gdb)
This feels like the kind of thing we'd need DW_OP_implicit_pointer to fix. That said, this particular example looks tricky because AFAICT the pointer variables do point to the stack slot of local_var
correctly (i.e., the implicit pointer locations are correct in DWARF), it's just that a particular value hasn't been written to that address.
The variable local_var
still gets a stack slot, just nothing is written to it - DSE removes the store (presumably because it would be UB to dereference ptr_global outside the function?).
This feels like the kind of thing we'd need DW_OP_implicit_pointer to fix. That said, this particular example looks tricky because AFAICT the pointer variables do point to the stack slot of
local_var
correctly (i.e., the implicit pointer locations are correct in DWARF), it's just that a particular value hasn't been written to that address.The variable
local_var
still gets a stack slot, just nothing is written to it - DSE removes the store (presumably because it would be UB to dereference ptr_global outside the function?).
The following is what we get on line 9 by insertting a marker to force the debugger stop. "21845" is stored at the address "0x00007fffffffd894". It seems that clang compiler returns "local_var" directly without initializing its value to the address .
* thread #1, name = 'case_r.out', stop reason = breakpoint 1.1
frame #0: 0x0000555555555141 case_r.out`main [inlined] func_1 at .modifiedcase.c:9:9
6 static int func_1(void)
7 {
8 int *ptr_global = &global_var;
-> 9 int local_var = 3;
10 int *ptr_local_var = &local_var;
11 int **ptr_to_global_pointer = &global_pointer;
12
(lldb) fr v
(int) local_var = 21845
(int *) ptr_local_var = <variable not available>
(int *) ptr_global = <variable not available>
(lldb) fr v -L
0x00007fffffffd8a4: (int) local_var = 21845
: (int *) ptr_local_var = <variable not available>
: (int *) ptr_global = <variable not available>
"DSE removes the store instruction" @OCHyams also effects static global variables. After dereferencing global_pointer
, we get 21845
, although printf function works well.
frame #0: 0x000055555555514d case.out`main at case.c:28:5
25
26 int main(void)
27 {
-> 28 printf("%d", func_1());
29 return 0;
30 }
(lldb) ta v
Global variables for /home/ad/Downloads/lldb/reproduce_bug/case.c in /home/ad/Downloads/lldb/reproduce_bug/case.out:
(int *) global_pointer = 0x00007fffffffd8a4
(lldb) p *global_pointer
(int) 21845
although printf function works well.
The value 3
is never stored to memory - func_1
is inlined and then the constant literal 3
is passed to printf
directly. I imagine the compiler is eliding the store to the stack slot because the local value isn't used, and that it keeps the stack slot because its address is taken (I don't think saving the local's address itself is an issue). I think that to dereference that address of the local saved in the global variable is UB. To illustrate that I've modified main
to dereference global_pointer
after the call and ASAN gets upset: https://godbolt.org/z/Gv9WjWa7E
That is to say, I still think the variable locations for the pointers are correct. The pointer value is the address of the local_var
- local_var
is just never initialised because the only situation in which local_var
's address would be read from is undefined behaviour, therefore the compiler can elide the store even though the stack slot still exists. I am inclined to say that this isn't a bug so much as a feature request (and I think it would be quite hard to fix, but I might be being pessimistic here).
Might be worth someone else having a quick look too to make sure I'm not barking up the wrong tree here (cc @jmorse).
@OCHyams Yes, I agree. The variable location for the pointers are correct, indicating to 0x00007fffffffd8a4
, the address of local_var
, and the variable of local_var
is not be initialized. Is this UB triggered by optimizations?
Tricky -- almost all of this program can be optimised away by LLVM, but it has the added complication of having stores to global variables, which LLVM is reluctant to remove because they're global. That then leads to variables of the original program not being deleted because they need to support the stores to the global, but all the meaning has been optimised away. Hence: being able to view some uninitialized memory here.
IMO it's interesting that we can see these slices of program state preserved by the globals, but if the optimiser is allowed to optimise away the redundant calculations, we're stuck with presenting slightly misleading information. I don't believe there's anything in DWARF that allows the value/location of a global variable to be altered for a range of instructions?
Tricky -- almost all of this program can be optimised away by LLVM, but it has the added complication of having stores to global variables, which LLVM is reluctant to remove because they're global. That then leads to variables of the original program not being deleted because they need to support the stores to the global, but all the meaning has been optimised away. Hence: being able to view some uninitialized memory here.
IMO it's interesting that we can see these slices of program state preserved by the globals, but if the optimiser is allowed to optimise away the redundant calculations, we're stuck with presenting slightly misleading information. I don't believe there's anything in DWARF that allows the value/location of a global variable to be altered for a range of instructions?
Technically there's no reason you couldn't use a loclist for a global, I think? It might be hard to do, but I guess at least for a static/file-scoped global, you might be able to do it - use the memory location as the default location, and explicit location list regions for the optimized-to-local/constant/etc portions.
But I'd say it's a fair bit of work and not something we're likely to do any time soon so far as I can guess.
We get a wrong value -21845- while dereferencing the pointer "ptr_global" in lldb environment. It should be pointing to "local_var" on line 20, instead of other address, so the correct one should be 3 .
The pointer variable "ptr_local_var" has the same problem.
cat case.c
We can reproduce it in LLVM 18.1.2, LLVM17.0.6, and LLVM16.0.3, with: