[PR,d/90250] Committed fix segfault in runtime caused by unexpected GC of TLS data.

Message ID CABOHX+dL=6BPK=0JobshpS-AZvBE=nxS1KkTo2uBt+52wyD1SA@mail.gmail.com
State New
Headers show
Series
  • [PR,d/90250] Committed fix segfault in runtime caused by unexpected GC of TLS data.
Related show

Commit Message

Iain Buclaw April 25, 2019, 3:59 p.m.
Hi,

Patch fixes a tlsgc bug on non-glibc targets.

As explained in the bug report, glibc puts the TLS area for each new
thread at the beginning of the newly created stack. Due to the way
libdruntime detects the stack bottom, we end up marking all TLS data
along with what we think is the stack.

On other platforms, this is not the case, so memory referenced by
thread-local data will get unexpectedly freed, making the use of
threads and TLS unworkable.

Regression tested on x86_64-linux-gnu and x86_64-freebsd.

Committed to trunk as r270576.

-- 
Iain
---
libphobos/ChangeLog:

2019-04-25  Iain Buclaw  <ibuclaw@gdcproject.org>

        * libdruntime/gcc/sections/elf_shared.d (initTLSRanges): Populate
        _tlsRanges in every startup thread.
        * testsuite/libphobos.thread/thread.exp: Load libphobos-dg.exp.
        * testsuite/libphobos.thread/tlsgc_sections.d: New test.

---

Patch

diff --git a/libphobos/libdruntime/gcc/sections/elf_shared.d b/libphobos/libdruntime/gcc/sections/elf_shared.d
index 3a2c85cba64..1eafecdd322 100644
--- a/libphobos/libdruntime/gcc/sections/elf_shared.d
+++ b/libphobos/libdruntime/gcc/sections/elf_shared.d
@@ -308,7 +308,13 @@  else
      */
     Array!(void[])* initTLSRanges() nothrow @nogc
     {
-        return &_tlsRanges();
+        auto rngs = &_tlsRanges();
+        if (rngs.empty)
+        {
+            foreach (ref pdso; _loadedDSOs)
+                rngs.insertBack(pdso.tlsRange());
+        }
+        return rngs;
     }
 
     void finiTLSRanges(Array!(void[])* rngs) nothrow @nogc
diff --git a/libphobos/testsuite/libphobos.thread/thread.exp b/libphobos/testsuite/libphobos.thread/thread.exp
index d35df567ab3..3e760d3e370 100644
--- a/libphobos/testsuite/libphobos.thread/thread.exp
+++ b/libphobos/testsuite/libphobos.thread/thread.exp
@@ -14,6 +14,8 @@ 
 # along with GCC; see the file COPYING3.  If not see
 # <http://www.gnu.org/licenses/>.
 
+load_lib libphobos-dg.exp
+
 # Initialize dg.
 dg-init
 
diff --git a/libphobos/testsuite/libphobos.thread/tlsgc_sections.d b/libphobos/testsuite/libphobos.thread/tlsgc_sections.d
new file mode 100644
index 00000000000..1421d926a38
--- /dev/null
+++ b/libphobos/testsuite/libphobos.thread/tlsgc_sections.d
@@ -0,0 +1,39 @@ 
+final class Class
+{
+    // This gets triggered although the instance always stays referenced.
+    ~this()
+    {
+        import core.stdc.stdlib;
+        abort();
+    }
+}
+
+Class obj;
+
+static this()
+{
+    obj = new Class;
+}
+
+static ~this()
+{
+    // Free without destruction to avoid triggering abort()
+    import core.memory;
+    GC.free(cast(void*)obj);
+}
+
+void doit()
+{
+    foreach (i; 0 .. 10_000)
+        new ubyte[](100_000);
+}
+
+void main()
+{
+    import core.thread;
+    auto t = new Thread(&doit);
+    t.start();
+
+    // This triggers the GC that frees the still referenced Class instance.
+    doit();
+}