At line 25, the value that the pointer local_ptr is referencing differs from the value of g_values[7].
Furthermore, at line 27, an error occurs when attempting to print local_ptr, displaying the message: "error: Couldn't materialize: couldn't get the value of variable local_ptr: variable not available error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression".
Wrong result of pointer assignment operation at line 27. Instead of setting g_values[7] to 0, the operation *g_ptr_wrapper = &local_ptr should set long * pointer to NULL.
We can reproduce this issue in LLVM versions 18.1.8, 17.0.6, and 16.0.3. The behavior of the binary compiled with -O2 is identical to that of the -O3 binary, so we will use the -O3 binary for demonstration purposes.
clang -g -O3 -o 434_O3.out 434.c
(lldb) file 434_O3.out
(lldb) b main
(lldb) r
[...]
* thread #1, name = '434_O3.out', stop reason = breakpoint 2.1
frame #0: 0x0000555555555141 434_O3.out`main [inlined] get_union_value at 434.c:25:29
22 static const union U3 get_union_value(void) {
23 long int *local_ptr = &g_values[7];
24
-> 25 *g_value_ptr = (249UL < g_flag); // Set value based on comparison
26 *local_ptr = 0; // Reset the value at index 7
27 *g_ptr_wrapper = &local_ptr; // Update reference
(lldb) p g_values[7]
(int) -2139292940
(lldb) p *local_ptr
(int) 285576016
(lldb) s
(lldb) s
(lldb) p g_values[7]
(int) 0
(lldb) p *local_ptr
error: Couldn't materialize: couldn't get the value of variable local_ptr: variable not available
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression
(lldb) p *g_ptr_wrapper
(int **) 0x0000555555558078
(lldb) p **g_ptr_wrapper
(int *) 0x000055555555804c
(lldb) p ***g_ptr_wrapper
(int) 0
cat 434.c
#include <stdio.h>
union U3 {
volatile unsigned long f0;
int f1;
volatile signed char f2;
};
static volatile int g_flag = 0x6E54;
static long int g_values[10] = {0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4};
static long int *volatile g_value_ptr = &g_values[3];
static long int *g_ref_value = &g_values[7];
static long int **g_ref_ptr = &g_ref_value;
static long int ***volatile g_ptr_wrapper = &g_ref_ptr;
static const union U3 g_union_vals[7] = {{-1UL}, {-1UL}, {-1UL}, {-1UL}, {-1UL}, {-1UL}, {-1UL}};
static const union U3 get_union_value(void);
static void print_message(void);
static const union U3 get_union_value(void) {
long int *local_ptr = &g_values[7];
*g_value_ptr = (249UL < g_flag); // Set value based on comparison
*local_ptr = 0; // Reset the value at index 7
*g_ptr_wrapper = &local_ptr; // Update reference
return g_union_vals[6]; // Return the last union value
}
int main(void) {
get_union_value();
printf("Hello, world!\n");
return 0;
}
GDB produces a similar issue.
$ gdb 420_O3.out
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
[...]
(gdb) b main
(gdb) r
(gdb) s
get_union_value () at 434.c:25
25 *g_value_ptr = (249UL < g_flag); // Set value based on comparison
(gdb) p *local_ptr
$1 = 285576016
(gdb) p g_values[7]
$2 = -2139292940
(gdb) s
26 *local_ptr = 0; // Reset the value at index 7
(gdb) s
27 *g_ptr_wrapper = &local_ptr; // Update reference
(gdb) p *local_ptr
value has been optimised out
(gdb) p g_values[7]
$3 = 0
(gdb) p g_ptr_wrapper
$4 = (int *** volatile) 0x555555558070 <g_ref_ptr>
(gdb) p *g_ptr_wrapper
$5 = (int **) 0x555555558078 <g_ref_value>
(gdb) p **g_ptr_wrapper
$6 = (int *) 0x55555555804c <g_values+28>
(gdb) p ***g_ptr_wrapper
$7 = 0
[Godblot link](https://godbolt.org/z/7bGbGcnr1)
There are three items needed to be considered:
1. At line 25, the value that the pointer `local_ptr` is referencing differs from the value of `g_values[7]`.
2. Furthermore, at line 27, an error occurs when attempting to print `local_ptr`, displaying the message: "error: Couldn't materialize: couldn't get the value of variable local_ptr: variable not available error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression".
3. Wrong result of pointer assignment operation at line 27. Instead of setting g_values[7] to 0, the operation `*g_ptr_wrapper = &local_ptr` should set `long *` pointer to NULL.
We can reproduce this issue in LLVM versions 18.1.8, 17.0.6, and 16.0.3. The behavior of the binary compiled with -O2 is identical to that of the -O3 binary, so we will use the -O3 binary for demonstration purposes.
```
clang -g -O3 -o 434_O3.out 434.c
(lldb) file 434_O3.out
(lldb) b main
(lldb) r
[...]
* thread #1, name = '434_O3.out', stop reason = breakpoint 2.1
frame #0: 0x0000555555555141 434_O3.out`main [inlined] get_union_value at 434.c:25:29
22 static const union U3 get_union_value(void) {
23 long int *local_ptr = &g_values[7];
24
-> 25 *g_value_ptr = (249UL < g_flag); // Set value based on comparison
26 *local_ptr = 0; // Reset the value at index 7
27 *g_ptr_wrapper = &local_ptr; // Update reference
(lldb) p g_values[7]
(int) -2139292940
(lldb) p *local_ptr
(int) 285576016
(lldb) s
(lldb) s
(lldb) p g_values[7]
(int) 0
(lldb) p *local_ptr
error: Couldn't materialize: couldn't get the value of variable local_ptr: variable not available
error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression
(lldb) p *g_ptr_wrapper
(int **) 0x0000555555558078
(lldb) p **g_ptr_wrapper
(int *) 0x000055555555804c
(lldb) p ***g_ptr_wrapper
(int) 0
```
`cat 434.c`
```
#include <stdio.h>
union U3 {
volatile unsigned long f0;
int f1;
volatile signed char f2;
};
static volatile int g_flag = 0x6E54;
static long int g_values[10] = {0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4, 0x807CFAF4};
static long int *volatile g_value_ptr = &g_values[3];
static long int *g_ref_value = &g_values[7];
static long int **g_ref_ptr = &g_ref_value;
static long int ***volatile g_ptr_wrapper = &g_ref_ptr;
static const union U3 g_union_vals[7] = {{-1UL}, {-1UL}, {-1UL}, {-1UL}, {-1UL}, {-1UL}, {-1UL}};
static const union U3 get_union_value(void);
static void print_message(void);
static const union U3 get_union_value(void) {
long int *local_ptr = &g_values[7];
*g_value_ptr = (249UL < g_flag); // Set value based on comparison
*local_ptr = 0; // Reset the value at index 7
*g_ptr_wrapper = &local_ptr; // Update reference
return g_union_vals[6]; // Return the last union value
}
int main(void) {
get_union_value();
printf("Hello, world!\n");
return 0;
}
```
GDB produces a similar issue.
```
$ gdb 420_O3.out
GNU gdb (Ubuntu 15.0.50.20240403-0ubuntu1) 15.0.50.20240403-git
[...]
(gdb) b main
(gdb) r
(gdb) s
get_union_value () at 434.c:25
25 *g_value_ptr = (249UL < g_flag); // Set value based on comparison
(gdb) p *local_ptr
$1 = 285576016
(gdb) p g_values[7]
$2 = -2139292940
(gdb) s
26 *local_ptr = 0; // Reset the value at index 7
(gdb) s
27 *g_ptr_wrapper = &local_ptr; // Update reference
(gdb) p *local_ptr
value has been optimised out
(gdb) p g_values[7]
$3 = 0
(gdb) p g_ptr_wrapper
$4 = (int *** volatile) 0x555555558070 <g_ref_ptr>
(gdb) p *g_ptr_wrapper
$5 = (int **) 0x555555558078 <g_ref_value>
(gdb) p **g_ptr_wrapper
$6 = (int *) 0x55555555804c <g_values+28>
(gdb) p ***g_ptr_wrapper
$7 = 0
```
Godblot link
There are three items needed to be considered:
local_ptr
is referencing differs from the value ofg_values[7]
.local_ptr
, displaying the message: "error: Couldn't materialize: couldn't get the value of variable local_ptr: variable not available error: errored out in DoExecute, couldn't PrepareToExecuteJITExpression".*g_ptr_wrapper = &local_ptr
should setlong *
pointer to NULL.We can reproduce this issue in LLVM versions 18.1.8, 17.0.6, and 16.0.3. The behavior of the binary compiled with -O2 is identical to that of the -O3 binary, so we will use the -O3 binary for demonstration purposes.
cat 434.c
GDB produces a similar issue.