New issue
Advanced search Search tips

Issue 829078 link

Starred by 3 users

Issue metadata

Status: Verified
Owner:
Closed: Today
Cc:
Components:
EstimatedDays: ----
NextAction: ----
OS: Mac
Pri: 3
Type: Bug

Blocked on:
issue 922384

Blocking:
issue 806358



Sign in to add a comment

clang generates globally visible symbols for TLS wrappers on Mac

Project Member Reported by lfg@chromium.org, Apr 4 2018

Issue description

Here's a minimal test case:

$ cat test.cc 
thread_local int tls_global = 42;
int& global() {
  return tls_global;
}
$ clang -fPIC -shared -std=c++11 test.cc
$ nm | grep global
0000000000000f90 T __Z6globalv
0000000000000fa0 T __ZTW10tls_global # globally exported TLS wrapper
0000000000001000 s _tls_global
0000000000001018 s _tls_global$tlv$init

Setting visibility=hidden does not affect these symbols:

$ clang -fPIC -shared -std=c++11 test.cc -fvisibility=hidden
$ nm | grep global
0000000000000f90 t __Z6globalv
0000000000000fa0 T __ZTW10tls_global # visibility=hidden does not work here
0000000000001000 s _tls_global
0000000000001018 s _tls_global$tlv$init

 

Comment 1 by lfg@chromium.org, Apr 4 2018

I also tested on Linux, and it works correctly:

$ cat test.cc 
thread_local int tls_global = 42;
int& global() {
  return tls_global;
}
$ clang-3.9 -shared test.cc -std=c++11 -fPIC 
$ llvm-nm-3.9 |grep global
00000000000006d0 T _Z6globalv
00000000000006e0 t _ZTW10tls_global # locally exported wrapper
0000000000000680 t __do_global_dtors_aux
0000000000200de8 n __do_global_dtors_aux_fini_array_entry
0000000000000000 D tls_global

Cc: r...@chromium.org p...@chromium.org h...@chromium.org
cc'ing a few folks in case they know something about this

Comment 3 by h...@chromium.org, Apr 5 2018

I don't know exactly what's going on here, but this seems to be the code for computing the wrapper's linkage, and it has a Darwin-specific thing:

static bool isThreadWrapperReplaceable(const VarDecl *VD,
                                       CodeGen::CodeGenModule &CGM) {
  assert(!VD->isStaticLocal() && "static local VarDecls don't need wrappers!");
  // Darwin prefers to have references to thread local variables to go through
  // the thread wrapper instead of directly referencing the backing variable.
  return VD->getTLSKind() == VarDecl::TLS_Dynamic &&
         CGM.getTarget().getTriple().isOSDarwin();
}

/// Get the appropriate linkage for the wrapper function. This is essentially
/// the weak form of the variable's linkage; every translation unit which needs
/// the wrapper emits a copy, and we want the linker to merge them.
static llvm::GlobalValue::LinkageTypes
getThreadLocalWrapperLinkage(const VarDecl *VD, CodeGen::CodeGenModule &CGM) {
  llvm::GlobalValue::LinkageTypes VarLinkage =
      CGM.getLLVMLinkageVarDefinition(VD, /*isConstant=*/false);

  // For internal linkage variables, we don't need an external or weak wrapper.
  if (llvm::GlobalValue::isLocalLinkage(VarLinkage))
    return VarLinkage;

  // If the thread wrapper is replaceable, give it appropriate linkage.
  if (isThreadWrapperReplaceable(VD, CGM))
    if (!llvm::GlobalVariable::isLinkOnceLinkage(VarLinkage) &&
        !llvm::GlobalVariable::isWeakODRLinkage(VarLinkage))
      return VarLinkage;
  return llvm::GlobalValue::WeakODRLinkage;
}


(From lib/CodeGen/ItaniumCXXABI.cpp)
Status: Assigned (was: Untriaged)
Mac triage: marking Assigned.
Cc: vtsyrklevich@chromium.org
lfg@ I'm interested in using thread_local in chromium as well and reached this bug. Could you explain why the symbol visibility is an issue? It seems like on Darwin the __ZTW* thread wrapper is used instead of the symbol to reference the TLS var and doing some simple tests on macOS using thread_local I wasn't able to hit a failure that explained this bug.
I pinged lfg@ over gchat and he gave me the following link for context https://groups.google.com/a/google.com/forum/#!msg/chrome-mac-dev/lXZB33SF5nk/ETnTT69lAQAJ

I had mistakenly assumed that the issue had to do with cross-DSO symbol resolution in component builds instead of simply visible symbols in the final build. I'm looking at the original Darwin visibility changes in LLVM to try to understand the context of why they were added.
Cc: -vtsyrklevich@chromium.org thakis@chromium.org
Owner: vtsyrklevich@chromium.org
I've filed an LLVM bug https://bugs.llvm.org/show_bug.cgi?id=40327

Comment 8 by vtsyrklevich@chromium.org, Jan 17 (5 days ago)

Blockedon: 922384

Comment 9 by vtsyrklevich@chromium.org, Jan 17 (5 days ago)

It should be fixed upstream, just needs a clang roll.

Comment 10 by vtsyrklevich@chromium.org, Today (17 hours ago)

Status: Verified (was: Assigned)
The clang roll has landed. I've verified that the new clang on macOS correctly handles symbol visibility for the provided example.

Sign in to add a comment