This is an archive of the discontinued LLVM Phabricator instance.

Fine grain control over some symbol visibility
ClosedPublic

Authored by serge-sans-paille on Aug 30 2021, 1:24 PM.

Details

Summary

Setting -fvisibility=hidden when compiling Target libs has the advantage of
not being intrusive on the codebase, but it also sets the visibility of all
functions within header-only component like ADT. In the end, we end up with
some symbols with hidden visibility within llvm dylib (through the target libs),
and some with external visibility (through other libs). This paves the way for
subtle bugs like https://reviews.llvm.org/D101972

This patch explicitly set the visibility of some classes to default so that
llvm::Any related symbols keep a default visibility. Indeed a template
function with default visibility parametrized by a type with hidden
visibility is granted hidden visibility, and we don't want this for the
uniqueness of llvm::Any::TypeId.

Diff Detail

Event Timeline

serge-sans-paille requested review of this revision.Aug 30 2021, 1:24 PM
Herald added a project: Restricted Project. · View Herald TranscriptAug 30 2021, 1:24 PM

Looks good to me, but I would like to see @tstellar approve as well.

+some people who were interested in visibility annotations based on my very fuzzy memory: @MaskRay @aganea

MaskRay added a comment.EditedAug 30 2021, 4:51 PM

(Background: -fvisibility-inlines-hidden is already the default.)

The description says:

Setting -fvisibility=hidden when compiling Target libs has the advantage of not being intrusive on the codebase, but it also sets the visibility of all functions within header-only component like ADT.

However I cannot connect this with the effect of this patch. With this patch, what exact configurations are now working? Can you show the relevant cflags/ldflags and/or downstream usage?

rnk added a comment.Aug 30 2021, 8:46 PM

With this patch, what exact configurations are now working? Can you show the relevant cflags/ldflags and/or downstream usage?

Previously the failures were described here:
https://reviews.llvm.org/D101972#2746842
Pointed to this task:
https://cbs.centos.org/koji/taskinfo?taskID=2483905
Extracting the cmake command line from the log produces:
https://reviews.llvm.org/P8273

The interesting part is probably just -DLLVM_BUILD_LLVM_DYLIB:BOOL=ON -DLLVM_LINK_LLVM_DYLIB:BOOL=ON, and that it causes some IRTests unit tests to fail (such as IR/./IRTests/CGSCCCallbacksTest.InstrumentedInvalidatingPasses). I haven't replicated this personally.

Presumably what is happening is that llvm::Any::TypeId<llvm::Function>::Id receives hidden visibility, so the typeids of such objects do not compare equal when they are passed between the LLVM DSO and the gtest shell test executable.

serge-sans-paille edited the summary of this revision. (Show Details)Aug 30 2021, 11:53 PM

@MaskRay I've updated the description to reflect the actual impact of that patch wrt. llvm::Any::TypeId.
@rnk I totally agree with your description of the situation.

tstellar accepted this revision.Sep 1 2021, 7:08 AM

LGTM, Thank you.

This revision is now accepted and ready to land.Sep 1 2021, 7:08 AM
This revision was landed with ongoing or failed builds.Sep 1 2021, 8:53 AM
This revision was automatically updated to reflect the committed changes.

OK. The problem is the hidden TypeId<hidden_class>::Id symbol.

template <typename T> struct TypeId {
  static const char Id;
};
template <typename T> const char TypeId<T>::Id = 0;

struct __attribute__((visibility("hidden"))) SCC {
};

const char *foo() {
  // The symbol TypeId<SCC>::Id is weak hidden.
  return &TypeId<SCC>::Id;
}

Such -fvisibility=hidden built shared objects export very few dynamic symbols (API) so may not be usable by other shared objects...
But perhaps your setup doesn't require the built libLLVM.so to be used by others.

rnk added a comment.Sep 1 2021, 12:46 PM

Such -fvisibility=hidden built shared objects export very few dynamic symbols (API) so may not be usable by other shared objects...
But perhaps your setup doesn't require the built libLLVM.so to be used by others.

I believe in the current cmake build that -fvisibility=hidden is only passed into compile actions in lib/Target/*. The intention is to eliminate backend library symbols, but expose all other LLVM symbols. It's a coarse grained way of annotating the LLVM API. I'm guessing the problem is that, for those compiles, they see llvm::Function as a hidden class, when really it is intended to be visible.

Thanks for the explanation! I find CMAKE_CXX_VISIBILITY_PRESET in llvm/lib/Target/CMakeLists.txt and understand the direction now.
This change makes sense.