ghidra
ghidra copied to clipboard
Misdecompilation with overlapping reads and writes
Describe the bug Certain functions when decompiled will produce code that doesn't match the original behavior of the function due to a read being re-ordered to after a multi-byte write has overridden the source value. This seems to happen only when the write and read don't happen at the exact same address. For example, the compiled code
int test_decomp(unsigned char *a)
{
unsigned char num = a[4];
*(unsigned long long*)&a[2] = 0;
return num == 42;
}
will decompile to
int __cdecl test_decomp(uchar *param_1)
{
uint local_14;
*(undefined8 *)(param_1 + 2) = 0;
local_14 = (uint)(param_1[4] == '*');
return local_14;
}
which will always return 0 due to the first line overriding the value of param_1[4].
To Reproduce Steps to reproduce the behavior: I've attached a source file that when compiled and decompiled shows the issue. It was tested by building with Visual Studio/MSVC, targeting Windows x64, and importing the built exe into Ghidra. Optimizations must be disabled in this example so the function doesn't get removed from the final binary. To confirm the behavior is different, the decompiled C can be copied into the original program which will cause the output to change.
Expected behavior The decompiled source should preserve the order of reads and writes in all cases where it is significant, for example
int __cdecl test_decomp(uchar *param_1)
{
uchar uVar1;
uint local_14;
uVar1 = param_1[4];
*(undefined8 *)(param_1 + 2) = 0;
local_14 = (uint)(uVar1 == '*');
return local_14;
}
Screenshots
Attachments I've attached the source code I used to test this issue. test.c.txt
Environment (please complete the following information):
- OS: Microsoft Windows [Version 10.0.19044.4291]
- Java Version: 17.0.11
- Ghidra Version: 11.0.3
- Ghidra Origin: official GitHub