Skip to content

Addresses of TLS variables are kept alive across fiber/stack-full coroutine context switches which may result in a crash #98479

@omern1

Description

@omern1
; llc --relocation-model=pic ./tls.ll

@tls_foo = hidden thread_local global ptr null, align 8

; Function Attrs: mustprogress nounwind sspstrong uwtable
define hidden noundef i32 @_Z4testv() #0 {
entry:
  %0 = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @tls_foo)
  %1 = load ptr, ptr %0, align 8
  call void @_Z8do_stuffPv(ptr noundef %1)
  %2 = call align 8 ptr @llvm.threadlocal.address.p0(ptr align 8 @tls_foo)
  %3 = load ptr, ptr %2, align 8
  call void @_Z8do_stuffPv(ptr noundef %3)
  ret i32 0
}

declare void @_Z8do_stuffPv(ptr noundef) #1

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare nonnull ptr @llvm.threadlocal.address.p0(ptr nonnull)

Output:

_Z4testv:                               # @_Z4testv
        .cfi_startproc
# %bb.0:                                # %entry
        pushq   %rbx
        .cfi_def_cfa_offset 16
        .cfi_offset %rbx, -16
        leaq    tls_foo@TLSLD(%rip), %rdi
        callq   __tls_get_addr@PLT
        movq    %rax, %rbx
        movq    tls_foo@DTPOFF(%rax), %rdi
        callq   _Z8do_stuffPv@PLT
; The address of tls_foo should be reloaded here.
        movq    tls_foo@DTPOFF(%rbx), %rdi
        callq   _Z8do_stuffPv@PLT
        xorl    %eax, %eax
        popq    %rbx
        .cfi_def_cfa_offset 8
        retq

In our (Sony's) private repro test is executing on a fiber created by an M:N fiber library (stack-full coroutines) and do_stuff causes the fiber to be suspended.
When test resumes execution it's likely that it won't be running on the same OS thread as it was before it was suspended.
This means that the TLS address loaded won't be valid on the new thread and will cause a crash.

MSVC has the /GT commandline option which makes it reload the TLS address before each load of a TLS variable and I think we probably need something similar in LLVM.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions