[Mono-dev] Possible bugs in tramp-amd64.c when addresses span 4Gb boundary
benml at saillune.net
Tue Sep 23 10:02:23 UTC 2014
I've been looking into a bug that I've encountered running Mono on a
64-bit x86 system - specifically, where the "((code - start) < buf_len)"
assert in mono_arch_get_static_rgctx_trampoline() fires. This seems to
be a result of this code:
if ((((guint64)addr) >> 32) == 0)
buf_len = 16;
buf_len = 30;
...which assumes that if the destination address is <4Gb then a 32-bit
jump will be used, which isn't true if the code being generated is more
than ~2Gb away.
Looking further into this, I found that this pattern appears elsewhere
in tramp-amd64.c as well - and may explain another problem I've been
seeing where trampolines get "randomly" corrupted to point to
Specifically, what I think is happening there is that
mono_arch_create_specific_trampoline() is creating the trampoline, and
that at the time of creation the target address is within a 32-bit jump
from the source, so it generates a regular 32-bit CALL.
However, mono_arch_patch_callsite() appears to only check for the
target address being >4Gb when patching, meaning that it can (as far as
I can see) end up doing a 32-bit InterlockedExchange() that truncates
the offset in the case where the target is too far away. This would then
result in what I'm seeing, which is that the trampoline code is
well-formed by the target of the CALL is non-executable memory with
nothing in it.
Does this sound like a reasonable hypothesis? Or is there something
that I'm missing about how trampolines operate that means that offsets
of this nature shouldn't occur in the first place?
Thanks for any ideas or advice!
Ben Carter - ben at saillune.net
More information about the Mono-devel-list