diff mbox series

[committed] libphobos: Fix SIGBUS in read_encoded_value_with_base on sparc-sun-solaris (PR98584)

Message ID 20210420002902.1132994-1-ibuclaw@gdcproject.org
State New
Headers show
Series [committed] libphobos: Fix SIGBUS in read_encoded_value_with_base on sparc-sun-solaris (PR98584) | expand

Commit Message

Iain Buclaw April 20, 2021, 12:29 a.m. UTC
Hi,

This patch adjusts the `read_encoded_value_with_base' function in
libphobos to correctly handle unaligned loads.  Instead of unsafe
pointer dereferencing, use memcpy() to read encoded values from memory.
The function `read_encoded_value' has been updated to accept a ref
parameter, this simplifies handling of the pointer to memory needing to
be read.

Bootstrapped and regression tested on x86_64-linux-gnu/-m32/-mx32, with
further testing done on sparc-sun-solaris2.11 to verify the target
platform the PR was raised against has been fixed.

Committed to mainline.

Regards,
Iain.

---
libphobos/ChangeLog:

	PR d/98584
	* libdruntime/gcc/deh.d (scanLSDA): Update calls to read_uleb128 and
	read_encoded_value.
	(actionTableLookup): Update calls to read_sleb128 and
	read_encoded_value_with_base.
	* libdruntime/gcc/unwind/pe.d (read_uleb128): Update signature.
	(read_sleb128): Update signature.
	(read_unaligned): New function.
	(read_encoded_value_with_base): Update signature.  Call read_unaligned
	instead of unsafe pointer dereferencing.
	(read_encoded_value): Update signature.
---
 libphobos/libdruntime/gcc/deh.d       | 24 ++++----
 libphobos/libdruntime/gcc/unwind/pe.d | 81 +++++++++++++++------------
 2 files changed, 57 insertions(+), 48 deletions(-)
diff mbox series

Patch

diff --git a/libphobos/libdruntime/gcc/deh.d b/libphobos/libdruntime/gcc/deh.d
index 712f5d7bc9d..eb83751c59d 100644
--- a/libphobos/libdruntime/gcc/deh.d
+++ b/libphobos/libdruntime/gcc/deh.d
@@ -547,7 +547,7 @@  _Unwind_Reason_Code scanLSDA(const(ubyte)* lsda, _Unwind_Exception_Class excepti
     _Unwind_Ptr LPStart = 0;
 
     if (LPStartEncoding != DW_EH_PE_omit)
-        LPStart = read_encoded_value(context, LPStartEncoding, &p);
+        LPStart = read_encoded_value(context, LPStartEncoding, p);
     else
         LPStart = Start;
 
@@ -563,14 +563,14 @@  _Unwind_Reason_Code scanLSDA(const(ubyte)* lsda, _Unwind_Exception_Class excepti
             // hardcoded OS-specific format.
             TTypeEncoding = _TTYPE_ENCODING;
         }
-        auto TTbase = read_uleb128(&p);
+        auto TTbase = read_uleb128(p);
         TType = p + TTbase;
     }
 
     // The encoding and length of the call-site table; the action table
     // immediately follows.
     ubyte CSEncoding = *p++;
-    auto CSTableSize = read_uleb128(&p);
+    auto CSTableSize = read_uleb128(p);
     const(ubyte)* actionTable = p + CSTableSize;
 
     auto TTypeBase = base_of_encoded_value(TTypeEncoding, context);
@@ -608,8 +608,8 @@  _Unwind_Reason_Code scanLSDA(const(ubyte)* lsda, _Unwind_Exception_Class excepti
             _uleb128_t CSLandingPad, CSAction;
             do
             {
-                CSLandingPad = read_uleb128(&p);
-                CSAction = read_uleb128(&p);
+                CSLandingPad = read_uleb128(p);
+                CSAction = read_uleb128(p);
             }
             while (--ip);
 
@@ -626,10 +626,10 @@  _Unwind_Reason_Code scanLSDA(const(ubyte)* lsda, _Unwind_Exception_Class excepti
         while (p < actionTable)
         {
             // Note that all call-site encodings are "absolute" displacements.
-            auto CSStart = read_encoded_value(null, CSEncoding, &p);
-            auto CSLen = read_encoded_value(null, CSEncoding, &p);
-            auto CSLandingPad = read_encoded_value(null, CSEncoding, &p);
-            auto CSAction = read_uleb128(&p);
+            auto CSStart = read_encoded_value(null, CSEncoding, p);
+            auto CSLen = read_encoded_value(null, CSEncoding, p);
+            auto CSLandingPad = read_encoded_value(null, CSEncoding, p);
+            auto CSAction = read_uleb128(p);
 
             // The table is sorted, so if we've passed the ip, stop.
             if (ip < Start + CSStart)
@@ -703,9 +703,9 @@  int actionTableLookup(_Unwind_Action actions, _Unwind_Exception* unwindHeader,
     while (1)
     {
         auto ap = actionRecord;
-        auto ARFilter = read_sleb128(&ap);
+        auto ARFilter = read_sleb128(ap);
         auto apn = ap;
-        auto ARDisp = read_sleb128(&ap);
+        auto ARDisp = read_sleb128(ap);
 
         if (ARFilter == 0)
         {
@@ -725,7 +725,7 @@  int actionTableLookup(_Unwind_Action actions, _Unwind_Exception* unwindHeader,
             // the ClassInfo is stored.
             const(ubyte)* tp = TType - ARFilter * encodedSize;
 
-            auto entry = read_encoded_value_with_base(TTypeEncoding, TTypeBase, &tp);
+            auto entry = read_encoded_value_with_base(TTypeEncoding, TTypeBase, tp);
             ClassInfo ci = cast(ClassInfo)cast(void*)(entry);
 
             // D does not have catch-all handlers, and so the following
diff --git a/libphobos/libdruntime/gcc/unwind/pe.d b/libphobos/libdruntime/gcc/unwind/pe.d
index 361ec12490f..b9b05cbc8f6 100644
--- a/libphobos/libdruntime/gcc/unwind/pe.d
+++ b/libphobos/libdruntime/gcc/unwind/pe.d
@@ -103,40 +103,37 @@  _Unwind_Ptr base_of_encoded_value(ubyte encoding, _Unwind_Context* context)
     assert(0);
 }
 
-// Read an unsigned leb128 value from P, *P is incremented past the value.
+// Read an unsigned leb128 value from P, P is incremented past the value.
 // We assume that a word is large enough to hold any value so encoded;
 // if it is smaller than a pointer on some target, pointers should not be
 // leb128 encoded on that target.
-_uleb128_t read_uleb128(const(ubyte)** p)
+_uleb128_t read_uleb128(ref const(ubyte)* p)
 {
-    auto q = *p;
     _uleb128_t result = 0;
     uint shift = 0;
 
     while (1)
     {
-        ubyte b = *q++;
+        ubyte b = *p++;
         result |= cast(_uleb128_t)(b & 0x7F) << shift;
         if ((b & 0x80) == 0)
             break;
         shift += 7;
     }
 
-    *p = q;
     return result;
 }
 
 // Similar, but read a signed leb128 value.
-_sleb128_t read_sleb128(const(ubyte)** p)
+_sleb128_t read_sleb128(ref const(ubyte)* p)
 {
-    auto q = *p;
     _sleb128_t result = 0;
     uint shift = 0;
     ubyte b = void;
 
     while (1)
     {
-        b = *q++;
+        b = *p++;
         result |= cast(_sleb128_t)(b & 0x7F) << shift;
         shift += 7;
         if ((b & 0x80) == 0)
@@ -147,69 +144,82 @@  _sleb128_t read_sleb128(const(ubyte)** p)
     if (shift < result.sizeof * 8 && (b & 0x40))
         result |= -(cast(_sleb128_t)1 << shift);
 
-    *p = q;
     return result;
 }
 
-// Load an encoded value from memory at P.  The value is returned in VAL;
-// The function returns P incremented past the value.  BASE is as given
+// Similar, but read an unaligned value of type T.
+pragma(inline, true)
+private T read_unaligned(T)(ref const(ubyte)* p)
+{
+    version (X86)         enum hasUnalignedLoads = true;
+    else version (X86_64) enum hasUnalignedLoads = true;
+    else                  enum hasUnalignedLoads = false;
+
+    static if (hasUnalignedLoads)
+    {
+        T result = *cast(T*)p;
+    }
+    else
+    {
+        import core.stdc.string : memcpy;
+        T result = void;
+        memcpy(&result, p, T.sizeof);
+    }
+    p += T.sizeof;
+    return result;
+}
+
+// Load an encoded value from memory at P.  The function returns the
+// encoded value.  P is incremented past the value.  BASE is as given
 // by base_of_encoded_value for this encoding in the appropriate context.
 _Unwind_Ptr read_encoded_value_with_base(ubyte encoding, _Unwind_Ptr base,
-                                         const(ubyte)** p)
+                                         ref const(ubyte)* p)
 {
-    auto q = *p;
+    auto psave = p;
     _Unwind_Internal_Ptr result;
 
     if (encoding == DW_EH_PE_aligned)
     {
-        _Unwind_Internal_Ptr a = cast(_Unwind_Internal_Ptr)q;
+        _Unwind_Internal_Ptr a = cast(_Unwind_Internal_Ptr)p;
         a = cast(_Unwind_Internal_Ptr)((a + (void*).sizeof - 1) & - (void*).sizeof);
         result = *cast(_Unwind_Internal_Ptr*)a;
-        q = cast(ubyte*) cast(_Unwind_Internal_Ptr)(a + (void*).sizeof);
+        p = cast(ubyte*) cast(_Unwind_Internal_Ptr)(a + (void*).sizeof);
     }
     else
     {
         switch (encoding & 0x0f)
         {
             case DW_EH_PE_uleb128:
-                result = cast(_Unwind_Internal_Ptr)read_uleb128(&q);
+                result = cast(_Unwind_Internal_Ptr)read_uleb128(p);
                 break;
 
             case DW_EH_PE_sleb128:
-                result = cast(_Unwind_Internal_Ptr)read_sleb128(&q);
+                result = cast(_Unwind_Internal_Ptr)read_sleb128(p);
                 break;
 
             case DW_EH_PE_udata2:
-                result = cast(_Unwind_Internal_Ptr) *cast(ushort*)q;
-                q += 2;
+                result = cast(_Unwind_Internal_Ptr)read_unaligned!ushort(p);
                 break;
             case DW_EH_PE_udata4:
-                result = cast(_Unwind_Internal_Ptr) *cast(uint*)q;
-                q += 4;
+                result = cast(_Unwind_Internal_Ptr)read_unaligned!uint(p);
                 break;
             case DW_EH_PE_udata8:
-                result = cast(_Unwind_Internal_Ptr) *cast(ulong*)q;
-                q += 8;
+                result = cast(_Unwind_Internal_Ptr)read_unaligned!ulong(p);
                 break;
 
             case DW_EH_PE_sdata2:
-                result = cast(_Unwind_Internal_Ptr) *cast(short*)q;
-                q += 2;
+                result = cast(_Unwind_Internal_Ptr)read_unaligned!short(p);
                 break;
             case DW_EH_PE_sdata4:
-                result = cast(_Unwind_Internal_Ptr) *cast(int*)q;
-                q += 4;
+                result = cast(_Unwind_Internal_Ptr)read_unaligned!int(p);
                 break;
             case DW_EH_PE_sdata8:
-                result = cast(_Unwind_Internal_Ptr) *cast(long*)q;
-                q += 8;
+                result = cast(_Unwind_Internal_Ptr)read_unaligned!long(p);
                 break;
 
             case DW_EH_PE_absptr:
-                if (size_t.sizeof == 8)
-                    goto case DW_EH_PE_udata8;
-                else
-                    goto case DW_EH_PE_udata4;
+                result = cast(_Unwind_Internal_Ptr)read_unaligned!(size_t)(p);
+                break;
 
             default:
                 __builtin_abort();
@@ -218,20 +228,19 @@  _Unwind_Ptr read_encoded_value_with_base(ubyte encoding, _Unwind_Ptr base,
         if (result != 0)
         {
             result += ((encoding & 0x70) == DW_EH_PE_pcrel
-                       ? cast(_Unwind_Internal_Ptr)*p : base);
+                       ? cast(_Unwind_Internal_Ptr)psave : base);
             if (encoding & DW_EH_PE_indirect)
                 result = *cast(_Unwind_Internal_Ptr*)result;
         }
     }
 
-    *p = q;
     return result;
 }
 
 // Like read_encoded_value_with_base, but get the base from the context
 // rather than providing it directly.
 _Unwind_Ptr read_encoded_value(_Unwind_Context* context, ubyte encoding,
-                               const(ubyte)** p)
+                               ref const(ubyte)* p)
 {
     auto base = base_of_encoded_value(encoding, context);
     return read_encoded_value_with_base(encoding, base, p);