Normally, when correctly configured, the pseudo relocations should
be in fields that are large enough to hold the full target
offset/address. But if the relocations nevertheless end up truncated,
error out clearly instead of running into a hard to diagnose crash
at runtime.

The pseudo relocations can be applied both on absolute pointers and
relative offsets, so when writing a N bit number, we don't know if
the limits for it are unsigned or signed. Thus carefully allow
values from -(2^(N-1)) to (2^N)-1, covering the full range for both
signed and unsigned N bit numbers. This won't catch all cases where
offsets are out of bounds, but should catch the vast majority, allowing
a clearer error message in those situations.

By default, GCC builds for x86_64 with the medium code model, which
adds .refptr stubs when referencing addresses that might end up
autoimported (i.e. when referencing addresses that can be out of range
for a 32 bit offset). Some users, who don't expect to be autoimporting
any data symbols, might be building with -mcmodel=small [1], which
avoids this extra indirection - but which then silently breaks things
if actually ending up autoimporting data symbols from another DLL.

This can also happen if calling a function which is marked "DATA" in
the def files as it's not meant to be called/used normally (because we
provide a replacement in libmingwex or lib*crt* that we think should
be used instead). If the function that is meant to be called is missing
(this can happen in misconfigured builds where the libraries are lacking
symbols that we expect to provide, see [2]), the linker can end up doing
an autoimport of the function into a 32 bit RIP-relative offset.
(This only happens with Clang; GCC creates a .refptr stub for the
function in these cases, while Clang expects such stubs not to be needed
for functions, only for data.)

[1] 
https://code.videolan.org/videolan/dav1d/-/commit/8f7af99687533d15a9b5d16abc7b9d7b0cd4dcd0
[2] https://github.com/ziglang/zig/issues/9845

Signed-off-by: Martin Storsjö <[email protected]>
---
 mingw-w64-crt/crt/pseudo-reloc.c | 18 ++++++++++++++++++
 1 file changed, 18 insertions(+)

diff --git a/mingw-w64-crt/crt/pseudo-reloc.c b/mingw-w64-crt/crt/pseudo-reloc.c
index feab8720f..2452dff5a 100644
--- a/mingw-w64-crt/crt/pseudo-reloc.c
+++ b/mingw-w64-crt/crt/pseudo-reloc.c
@@ -311,6 +311,7 @@ do_pseudo_reloc (void * start, void * end, void * base)
   ptrdiff_t reloc_target = (ptrdiff_t) ((char *)end - (char*)start);
   runtime_pseudo_reloc_v2 *v2_hdr = (runtime_pseudo_reloc_v2 *) start;
   runtime_pseudo_reloc_item_v2 *r;
+  unsigned int bits;
 
   /* A valid relocation list will contain at least one entry, and
    * one v1 data structure (the smallest one) requires two DWORDs.
@@ -440,6 +441,23 @@ do_pseudo_reloc (void * start, void * end, void * base)
       reldata -= ((ptrdiff_t) base + r->sym);
       reldata += addr_imp;
 
+      bits = r->flags & 0xff;
+      if (bits < sizeof(ptrdiff_t)*8)
+        {
+          /* Check for overflows. We don't know if the target address is
+           * interpreted as a relative offset or as a truncated absolute
+           * address - to avoid false positives, allow offsets within the
+           * whole range of signed and unsigned N bits numbers, but error
+           * out for anything outside of that. Thus for relative offsets,
+           * this won't catch offsets that are only barely too large. */
+          ptrdiff_t max_unsigned = (1LL << bits) - 1;
+          ptrdiff_t min_signed = (~(ptrdiff_t)0) << (bits - 1);
+          if (reldata > max_unsigned || reldata < min_signed)
+           __report_error ("%d bit pseudo relocation at %p out of range, "
+                            "targeting %p, yielding the value %p.\n",
+                            bits, reloc_target, addr_imp, reldata);
+        }
+
       /* Write the new relocation value back to *reloc_target */
       switch ((r->flags & 0xff))
        {
-- 
2.25.1



_______________________________________________
Mingw-w64-public mailing list
[email protected]
https://lists.sourceforge.net/lists/listinfo/mingw-w64-public

Reply via email to