macaw-symbolic
: Inconsistent reporting of memory writes to read-only sections of memory
#418
Labels
macaw-symbolic
: Inconsistent reporting of memory writes to read-only sections of memory
#418
The default implementation of
mkGlobalPointerValidityPred
(here) is designed to check if you are attempting a memory write to a read-only section of the global address space, and if so, it will throw an assertion failure. I've discovered that this only works some of the time, however. To see what I mean, let's cook up a small test case that demonstrates writing to a read-only part of memory:Writing to
x
is fine on its own, but I will useobjcopy
to mark the ELF section thatx
resides in as read-only (as thoughx
were a constant):(I am using a
musl
-based, PPC32 version ofgcc
in the example above, but the same principle should apply to any architecture.)Let's test this out. The easier way I know how to test this is to make the following change to
macaw-symbolic
:Then compile
macaw-{ppc,x86}-symbolic
, and then run this test harness program (based on themacaw-{ppc,x86}-symbolic
test suites):If you do all that, you should get the following error:
So far, so good.
The example above used PPC32, however. What happens if we use an x86-64 version of
gcc
instead?Huh? How come the x86-64 version passes the test, but the PPC32 version fails? There is a hint in this part of
mkGlobalPointerValidityPredCommon
:macaw/symbolic/src/Data/Macaw/Symbolic/Memory/Common.hs
Lines 168 to 177 in 3e83b3e
Note that this will only attempt to emit an
outside of static memory range
assertion failure if theLLVMPtr
representing the global address has a block number of zero. If it has a non-zero block number, then there is no chance of an assertion failure. And sure enough, if we add some additional debug-printing to this function:And then if we re-run the x86-64 version of the program, we see:
In the
x86-64
version of the binary, 0x4000 isx
's address. Here, we see that the block number is 1, somacaw-symbolic
won't check if the offset is out of range.On the other hand, if we run the PPC32 version of the program, we see:
This time, we see that the block number is 0 (by virtue of the fact that it's not printing a pair).
What is causing this discrepancy? Ultimately, it's because when simulating the x86-64 version of the program,
macaw-symbolic
attempts to write to an address that was resolved usingMacawGlobalPtr
. This will translate an absolute address (e.g.,0x4000
with a block number of 0) into an offset from theLLVMPtr
that backs global memory (e.g.,(1, 0x4000)
). When simulating the PPC32 version of the program, however,macaw-symbolic
attempts to write to an absolute address (0x2000
) that was not resolved usingMacawGlobalPtr
. (I'm very unclear on why the two architectures differ in this way.)What should we do about this? We could investigate why the two architectures differ here, although I'm unsure how deep that rabbit hole goes. In principle,
mkGlobalPointerValidityPredCommon
ought to be able to handle addresses that were resolved usingMacawGlobalPtr
, so perhaps we should teach it to also make assertions aboutLLVMPtr
s whose block number matches that of theLLVMPtr
backing global memory.The text was updated successfully, but these errors were encountered: