-
-
Notifications
You must be signed in to change notification settings - Fork 424
sections_elf_shared: Do not access TLS of dead thread in finiTLSRanges() #1655
sections_elf_shared: Do not access TLS of dead thread in finiTLSRanges() #1655
Conversation
finiTLSRanges() is called from the destructor of core.Thread. At this point, the OS thread has already ceased to exist, so what was formerly a pointer to _loadedDSOs is no longer valid. In other words, `tdsos.reset()` was a use-after-free bug. It is unclear why the issue didn't surface on Linux/FreeBSD yet; for example, glibc might not actually re-use the TLS address range after a thread exits. On OS X, however, this did quite frequently trigger a crash when running the Phobos unit tests, since `tdsos` would have already been overwritten with unrelated contents.
Fixing random crashes is always good! |
Auto-merge toggled on |
@WalterBright: To be precise, this doesn't fix any random crashes yet, at least none that I could trigger on Linux. It might be that the TLS areas are only freed on The fix is very relevant for shared libraries on OS X, though, which still need backend support work in DMD. |
Your analysis is correct, finiTLSRanges gets called from the Thread finalizer ( |
With ldc 1.1.0 (and earlier) it turns out finiTLSRanges() does crash randomly in sambamba on Linux. Both in the original version and the later fixed version of druntime as is discussed in biod/sambamba#219. When I removed the line in the static version of the library with this patch https://github.com/genenetwork/guix-bioinformatics/blob/master/ldc-druntime-finiTLSRanges.patch the segfault no longer happens. We are still running tests, but so far it looks good. |
@pjotrp: It seems like your patch should avoid the crash, but introduces a small memory leak on every thread exit. We are hitting what seems to be at least a very similar issue – again on OS X – in ldc-developers/ldc#2006, so this should be properly fixed. The easiest fix is probably to just allocate the |
…n-version(Shared) See dlang#1655 for a discussion of the analogous issue for version(Shared).
…n-version(Shared) See dlang#1655 for a discussion of the analogous issue for version(Shared).
Similar to the issue fixed here dlang#1655 (comment) , static version of the sections_elf_shared accesses TLS of a dead thread. The simplest fix is to allocate _tlsRanges somewhere that would persist outside of the thread scope, for example the C heap. This was encountered while porting ldc 1.24.0 to Alpine Linux which uses Musl. https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/14364 But this issue should be affecting other libc implementations as well.
Similar to the issue fixed here dlang#1655 (comment) , static version of the sections_elf_shared accesses TLS of a dead thread. The simplest fix is to allocate _tlsRanges somewhere that would persist outside of the thread scope, for example the C heap. This was encountered while porting ldc 1.24.0 to Alpine Linux which uses Musl. https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/14364 But this issue should be affecting other libc implementations as well.
Similar to the issue fixed here dlang#1655 (comment) , static version of the sections_elf_shared accesses TLS of a dead thread. The simplest fix is to allocate _tlsRanges somewhere that would persist outside of the thread scope, for example the C heap. This was encountered while porting ldc 1.24.0 to Alpine Linux which uses Musl. https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/14364 But this issue should be affecting other libc implementations as well.
Similar to the issue fixed here dlang#1655 (comment) , static version of the sections_elf_shared accesses TLS of a dead thread. The simplest fix is to allocate _tlsRanges somewhere that would persist outside of the thread scope, for example the C heap. This was encountered while porting ldc 1.24.0 to Alpine Linux which uses Musl. https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/14364 But this issue should be affecting other libc implementations as well.
Similar to the issue fixed here dlang#1655 (comment) , static version of the sections_elf_shared accesses TLS of a dead thread. The simplest fix is to allocate _tlsRanges somewhere that would persist outside of the thread scope, for example the C heap. This was encountered while porting ldc 1.24.0 to Alpine Linux which uses Musl. https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/14364 But this issue should be affecting other libc implementations as well.
Similar to the issue fixed here #1655 (comment) , static version of the sections_elf_shared accesses TLS of a dead thread. The simplest fix is to allocate _tlsRanges somewhere that would persist outside of the thread scope, for example the C heap. This was encountered while porting ldc 1.24.0 to Alpine Linux which uses Musl. https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/14364 But this issue should be affecting other libc implementations as well.
Similar to the issue fixed here dlang#1655 (comment) , static version of the sections_elf_shared accesses TLS of a dead thread. The simplest fix is to allocate _tlsRanges somewhere that would persist outside of the thread scope, for example the C heap. This was encountered while porting ldc 1.24.0 to Alpine Linux which uses Musl. https://gitlab.alpinelinux.org/alpine/aports/-/merge_requests/14364 But this issue should be affecting other libc implementations as well.
finiTLSRanges() is called from the destructor of core.Thread. At this point,
the OS thread has already ceased to exist, so what was formerly a pointer
to _loadedDSOs is no longer valid.
In other words,
tdsos.reset()
was a use-after-free bug. It is unclear whythe issue didn't surface on Linux/FreeBSD yet; for example, glibc might not
actually re-use the TLS address range after a thread exits. On OS X, however,
this did quite frequently trigger a crash when running the Phobos unit tests,
since
tdsos
would have already been overwritten with unrelated contents.@MartinNowak