This is an archive of the discontinued LLVM Phabricator instance.

Allow externally dlopen-ed libraries to be registered as permanent libraries.
ClosedPublic

Authored by v.g.vassilev on Feb 14 2017, 11:40 AM.

Details

Reviewers
eliben
vsk
Summary

This is very helpful when we want a specific library to be dlopen-ed with different flags.

Diff Detail

Event Timeline

v.g.vassilev created this revision.Feb 14 2017, 11:40 AM
vsk added a subscriber: vsk.Feb 15 2017, 5:06 PM

What's the expected use of the new API? Do we provide a portable way to dlopen() something with special flags?

include/llvm/Support/DynamicLibrary.h
77

Please add some doxygen comments for the new function, with a description of what 'handle' is.

lib/Support/DynamicLibrary.cpp
71

You won't have the symbols mutex held here if you call this method directly. Is that fine? I'm not really sure what that mutex protects (seems like more than just the ExplicitSymbols map)..

v.g.vassilev marked 2 inline comments as done.

Addressed comments; removed old copy-paste code (we shouldn't dlclose if the handle is already registered).

vsk added inline comments.Feb 20 2017, 11:06 AM
lib/Support/DynamicLibrary.cpp
52

This change is a bit out-of-scope for your patch, perhaps? A separate review may be worthwhile to figure out if we really need two layers of locking (one implicit in the ManagedStatic, another with the SymbolsMutex).

71

Is there a double-lock scenario here? getPermanentLibrary() would lock, then addPermanentLibrary() would lock again?

77–92

There is a leak here when this function is called by getPermanentLibrary().

v.g.vassilev marked an inline comment as done.

Address comments; fix an oversight for Windows.

lib/Support/DynamicLibrary.cpp
52

Well, this follows the spirit of 'recent' (to us) changes in the area. I'd prefer to keep it together. It seems the ManagedStatic just handles the destruction at shutdown.

71

Yeah, I am not sure how to avoid this...

This is somewhat related to something I've been trying to get reviewed here: https://reviews.llvm.org/D30107
I think there is a serious problem with DynamicLibrary::getPermanentLibrary on Windows.
I believe D30107 handles the memory leak as well.

vsk added inline comments.Feb 20 2017, 11:41 AM
lib/Support/DynamicLibrary.cpp
52

It seems ManagedStaticBase::RegisterManagedStatic does some locking, but I guess it's just a one-time thing.

At any rate, I'd suggest that the ManagedStatic change be left for a different commit, because it doesn't seem like a required change to make the addPermanentLibrary API work.

71

Maybe std::lock_guard would be a good solution. I.e add an API to grab a std::lock_guard from the DynamicLibrary class, then require the lock_guard to be moved into addPermanentLibrary.

v.g.vassilev added a reviewer: vsk.
  • Split the OpenedHandles leak fix D30178;
  • Add more fine-grained locking, avoiding the double locking issue;
  • Add more information if an error occurred.
v.g.vassilev marked 2 inline comments as done.Feb 20 2017, 12:54 PM
v.g.vassilev added inline comments.
lib/Support/DynamicLibrary.cpp
71

It seems the locking should protect only dlerror. I decided to lock around dlopen/dlclose because I found some bug reports of them not being thread safe on some implementations.

vsk edited edge metadata.Feb 20 2017, 2:50 PM
  • Can you add a private addPermanentLibraryWithLock(void *handle, SmartScopedLock &) method? You can then use this from {add,get}PermanentLibrary, to avoid acquiring the mutex multiple times. That kills the benign race where two clients try to add the same dylib in parallel calls to getPermanentLibrary.
  • Could you rebase this patch on D30178 once it's updated?

As a general note (unrelated to this patch), I'm a bit unhappy with how there is no clear thing that SymbolMutex guards, but we don't have to fix that here.

v.g.vassilev marked an inline comment as done.

Typo.

It seems that we could even avoid using a private member but local static functions. Let me know I should remove the static private method.

vsk accepted this revision.Feb 22 2017, 12:14 AM

Thanks, lgtm. There is some overlap with D30107, but it looks like it'll need to be rebased on this patch anyway.

This revision is now accepted and ready to land.Feb 22 2017, 12:14 AM

FWIW applying D30107 before this would mean addPermanentLibraryWithLock would no longer be necessary.

Otherwise, doesn't this make it impossible to get symbols from an already loaded library unless all libs are searched?
That is, assuming "libSomething" is already loaded:
DynamicLibrary DL = DynamicLibrary::addPermanentLibrary(dlopen("libSomething"));
DL.getAddressOfSymbol("func"); // Fails

In this case how is it possible to get symbols from "libSomething" without searching every loaded module?
On Windows this is a larger issue as it can cache all loaded libraries.

vsk added a comment.Feb 22 2017, 2:15 PM

FWIW applying D30107 before this would mean addPermanentLibraryWithLock would no longer be necessary.

Yeah, I didn't mean to create more work for you in D30107! The 'with-lock' helper seemed like the right solution here, and I have still have some questions/comments about D30107, hence the lgtm.

Otherwise, doesn't this make it impossible to get symbols from an already loaded library unless all libs are searched?
That is, assuming "libSomething" is already loaded:
DynamicLibrary DL = DynamicLibrary::addPermanentLibrary(dlopen("libSomething"));
DL.getAddressOfSymbol("func"); // Fails

In that case, the client could check if DL is invalid, and then simply construct "DynamicLibrary(dlopen'd-value)". Perhaps the API could be cleaned up if we returned "Expected<DynamicLibrary>" from the static constructors, and got rid of the isValid method.

In this case how is it possible to get symbols from "libSomething" without searching every loaded module?

See above.

Yeah, I didn't mean to create more work for you in D30107! The 'with-lock' helper seemed like the right solution here, and I have still have some questions/comments about D30107, hence the lgtm.

It shouldn't be that much work integrating it...was just saying as the addPermanentLibraryWithLock is a bit ugly and would go away anyway.

Otherwise, doesn't this make it impossible to get symbols from an already loaded library unless all libs are searched?
That is, assuming "libSomething" is already loaded:
DynamicLibrary DL = DynamicLibrary::addPermanentLibrary(dlopen("libSomething"));
DL.getAddressOfSymbol("func"); // Fails

In that case, the client could check if DL is invalid, and then simply construct "DynamicLibrary(dlopen'd-value)". Perhaps the API could be cleaned up if we returned "Expected<DynamicLibrary>" from the static constructors, and got rid of the isValid method.

Why not just have addPermanentLibrary take an optional bool* indicating whether it was already loaded or not?
Whether it was loaded or not seems orthogonal to the task of adding a permanent library/getting a platform independent way to do lookups on it?

Either way if D30107 is to be expanded per your comments this could also be discussed then rather than holding this up.

vsk added a comment.Feb 22 2017, 5:30 PM

Yeah, I didn't mean to create more work for you in D30107! The 'with-lock' helper seemed like the right solution here, and I have still have some questions/comments about D30107, hence the lgtm.

It shouldn't be that much work integrating it...was just saying as the addPermanentLibraryWithLock is a bit ugly and would go away anyway.

Otherwise, doesn't this make it impossible to get symbols from an already loaded library unless all libs are searched?
That is, assuming "libSomething" is already loaded:
DynamicLibrary DL = DynamicLibrary::addPermanentLibrary(dlopen("libSomething"));
DL.getAddressOfSymbol("func"); // Fails

In that case, the client could check if DL is invalid, and then simply construct "DynamicLibrary(dlopen'd-value)". Perhaps the API could be cleaned up if we returned "Expected<DynamicLibrary>" from the static constructors, and got rid of the isValid method.

Why not just have addPermanentLibrary take an optional bool* indicating whether it was already loaded or not?
Whether it was loaded or not seems orthogonal to the task of adding a permanent library/getting a platform independent way to do lookups on it?

If you mean 'bool &', then your suggestion is actually very similar to mine (return 'Expected<DynamicLibrary>').

I agree that it's something we could improve, but think that it's something we can address as a follow-up (i.e I don't think the addPermanentLibrary API is broken as-is).

Either way if D30107 is to be expanded per your comments this could also be discussed then rather than holding this up.

Sure.

v.g.vassilev closed this revision.Feb 27 2017, 11:24 PM

Landed in r296442 with minimal modifications allowing multiple dlopen(nullptr).

Reverted in r296463.

The module is loaded twice for clang static analyzer plugins.

  • clang/lib/FrontendTool/ExecuteCompilerInvocation.cpp
  • clang/lib/StaticAnalyzer/Frontend/CheckerRegistration.cpp

Please consider such a case, or tweak clang plugins.
FYI, clang's plugin test can be enabled with CLANG_BUILD_EXAMPLES=ON

Thanks for reverting! I am working on this.

NoQ added a subscriber: NoQ.Feb 28 2017, 2:59 AM

Relanded in r296774.