Comments (31)
It seems the segfault happens due to premature unloading of the shared object. It works for me if I compile the plugin with -Wl,-znodelete
. This linker flag prevents unloading the shared object.
from llvm-pass-skeleton.
At least with clang-9, you can force it to load your shared library via the new pass manager:
$ clang-9 -fexperimental-new-pass-manager -fpass-plugin=myplugin.so a.c
clang
will call llvmGetPassPluginInfo()
and give you a chance to register your pass using the new PassPlugin API. Registering your passes in this way avoids the crashing issue due to the fact that LLVM is not holding onto a std::function
allocated by the shared object after the shared object is unloaded.
I haven't used this myself; I'm content using the DYLD_INSERT_LIBRARIES
hack with opt
right now. I'm not sure if all of the extension points are supported yet with the new PassManager, so that's one reason why I'm waiting.
See this snippet in llvm-tutor for an example of how to use the new PassPlugin API.
from llvm-pass-skeleton.
The bug in RegisterStandardPasses
should be fixed in LLVM 10, I submitted a patch that was accepted some days ago. It was dependent on the type of LLVM build and optimization level being used.
This is the commit, for reference: llvm/llvm-project@52c1d20
A full analysis of the problem can be found here: https://bugs.llvm.org/show_bug.cgi?id=39321
from llvm-pass-skeleton.
In case you were interested, I was able to figure this out without having to do the other method of registering the pass following what was done here.
static RegisterStandardPasses RegisterMyPass(PassManagerBuilder::EP_ModuleOptimizerEarly, registerSkeletonPass); static RegisterStandardPasses RegisterMyPass0(PassManagerBuilder::EP_EnabledOnOptLevel0, registerSkeletonPass);
It works for me, now I can use ModulePass. Thanks for afl-fuzz!
from llvm-pass-skeleton.
I spent a while looking into this today. To be specific, the problem looks like this on my system, at the moment:
$ /usr/local/opt/llvm/bin/clang -fplugin=build/skeleton/libSkeletonPass.so foo.c
I saw a function called foo!
Stack dump:
0. Program arguments: /usr/local/Cellar/llvm/7.0.1/bin/clang-7 -cc1 -triple x86_64-apple-macosx10.14.0 -Wdeprecated-objc-isa-usage -Werror=deprecated-objc-isa-usage -emit-obj -mrelax-all -disable-free -disable-llvm-verifier -discard-value-names -main-file-name foo.c -mrelocation-model pic -pic-level 2 -mthread-model posix -mdisable-fp-elim -masm-verbose -munwind-tables -target-cpu penryn -dwarf-column-info -debugger-tuning=lldb -target-linker-version 409.12 -resource-dir /usr/local/Cellar/llvm/7.0.1/lib/clang/7.0.1 -fdebug-compilation-dir /Users/asampson/cu/llvm-pass-skeleton -ferror-limit 19 -fmessage-length 80 -stack-protector 1 -fblocks -fencode-extended-block-signature -fregister-global-dtors-with-atexit -fobjc-runtime=macosx-10.14.0 -fmax-type-align=16 -fdiagnostics-show-option -fcolor-diagnostics -load build/skeleton/libSkeletonPass.so -o /var/folders/xq/1tgxc1mj0c75vn44tf_6q96c0000gn/T/foo-1708e5.o -x c foo.c
0 clang-7 0x0000000109362adc llvm::sys::PrintStackTrace(llvm::raw_ostream&) + 37
1 clang-7 0x0000000109362ede SignalHandler(int) + 192
2 libsystem_platform.dylib 0x00007fff7ce58b3d _sigtramp + 29
3 libsystem_platform.dylib 0x00007ffee784eb38 _sigtramp + 1788829720
4 clang-7 0x000000010905f74e llvm::object_deleter<llvm::SmallVector<std::__1::pair<llvm::PassManagerBuilder::ExtensionPointTy, std::__1::function<void (llvm::PassManagerBuilder const&, llvm::legacy::PassManagerBase&)> >, 8u> >::call(void*) + 22
5 clang-7 0x0000000109320d85 llvm::llvm_shutdown() + 53
6 clang-7 0x0000000109318c6d llvm::InitLLVM::~InitLLVM() + 15
7 clang-7 0x00000001083b0bf7 main + 141
8 libdyld.dylib 0x00007fff7cc6ded9 start + 1
clang-7: error: unable to execute command: Segmentation fault: 11
clang-7: error: clang frontend command failed due to signal (use -v to see invocation)
clang version 7.0.1 (tags/RELEASE_701/final)
Target: x86_64-apple-darwin18.2.0
Thread model: posix
InstalledDir: /usr/local/opt/llvm/bin
clang-7: note: diagnostic msg: PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace, preprocessed source, and associated run script.
clang-7: error: unable to execute command: Segmentation fault: 11
clang-7: note: diagnostic msg: Error generating preprocessed source(s).
That is, everything goes fine until LLVM tries to shut itself down. The issue does indeed seem to be that recent version of LLVM unloads our shared library before shutting down LLVM. Then, when LLVM does shut down, it tries to free the memory for the pass registration functions, including our registerSkeletonPass
, which is now a dangling pointer. The vector of functions in PassManagerBuilder
that is populated using our RegisterStandardPasses
is the thing that's crashing on destruction.
This problem has been reported to the LLVM bug tracker a few times, but hasn't gotten much traction:
https://bugs.llvm.org/show_bug.cgi?id=34573
https://bugs.llvm.org/show_bug.cgi?id=39321
https://bugs.llvm.org/show_bug.cgi?id=36183
Using -znodelete
is a reasonable workaround, but this does seem like LLVM itself should fix. And that option doesn't seem to be available on my (macOS 10.14) linker.
from llvm-pass-skeleton.
I'm recalling purely from memory, but here's how I remember it being structured: there are ModulePassManager
s and FunctionPassManager
s. The registration has a switch
on the EP flag, and some EPs map to one kind of pass manager and some map to the other. This mapping does no type checking to ensure that only ModulePass
es get registered with ModulePassManager
s and so on. Therefore, it's possible to choose the "wrong" kind of EP and get registered with the wrong pass manager. Then, you'll end up (for example) with a FunctionPassManager
trying to call runOnFunction
on your ModulePass
, which of course doesn't exist.
from llvm-pass-skeleton.
Also, AFAIK, that mechanism is only for linking plugins statically
What does this mean? The whole issue is about dynamic objects being unloaded prematurely leading to segfaults.
That was a bit off-topic, sorry! What I was trying to say is that the mechanism described in the docs (http://llvm.org/docs/WritingAnLLVMPass.html#building-pass-plugins) doesn't really change how we develop and use plugins that are loaded dynamically. However, the introduction of LLVM_${NAME}_LINK_INTO_TOOLS
simplifies immensely how statically linked plugins are developed.
from llvm-pass-skeleton.
Super happy to see this being fixed, thank you @EliaGeretto !
There's also more on the "pass plugin" registration system in the docs:
http://llvm.org/docs/WritingAnLLVMPass.html#building-pass-plugins
@sampsyo That section (and the functionality that it refers to) has only landed recently (commit), so we still have to wait for LLVM 10 to be released. Also, AFAIK, that mechanism is only for linking plugins statically (rather than dynamically). Either way, it's fantastic to have it there!
from llvm-pass-skeleton.
Cool! So, to clarify, you just needed to choose the right extension point (EP_*
) to make a module pass work? Seems right to me.
from llvm-pass-skeleton.
Correct, with EP_EarlyAsPossible I was getting Segmentation faults.
from llvm-pass-skeleton.
Yep, that matches my experience—some EPs are for function passes and some are for module passes, but this isn't well documented.
from llvm-pass-skeleton.
I've been working on it for the last day banging my head, so I'm glad I was able to figure it out. I'm assuming pass hierarchy goes something like this. So Function Passes don't even begin to run until after all of the Module Passes have been performed, and at the point at a point where LLVM can successfully run the pass. When it's classified as EarlyAsPossible for a module, it must place it in front of some setup required by LLVM to run.
Passes:
0. Default module passes that must be performed
- Module
- Function
- BB
- ...
from llvm-pass-skeleton.
Oh okay, that makes more sense. Well either way, I hope this can help others that may come across your examples. There are tons of FunctionPass
code out there that is explained well, not so much for ModulePass
.
from llvm-pass-skeleton.
Indeed; thanks for pointing it out! I'll leave this issue open in the hopes that other Google searchers will find it.
from llvm-pass-skeleton.
Yes, it helped a lot, thank you!
from llvm-pass-skeleton.
I am attempting to use this approach with LLVM 6.0. I get segmentation faults when loading the .so generated by this code, both in clang and in opt. Has the appropriate path been changed in 6?
from llvm-pass-skeleton.
Good question! I don't know what could be wrong—I know people in other threads have successfully used (prereleases of LLVM 6.0). Please let us know if you find the root cause of the segfault.
from llvm-pass-skeleton.
will report back. It's almost certainly something I am doing wrong.
from llvm-pass-skeleton.
Hi! Were you able to find a workaround with the -z flag to the linker for macOS?
I'm trying to dig into this, and I found this, but I don't really want to get into the LLVM code to patch this.
The TLDR is:
"Libraries should export initialization and cleanup routines using the gcc attribute((constructor)) and attribute((destructor)) function attributes. See the gcc info pages for information on these. Constructor routines are executed before dlopen returns (or before main() is started if the library is loaded at load time). Destructor routines are executed before dlclose returns (or after exit() or completion of main() if the library is loaded at load time)."
from llvm-pass-skeleton.
Nope, no current solution! If you find anything good (or can bring it to the attention of the LLVM developers), please let us know.
from llvm-pass-skeleton.
Dug into this issue a bit, here's what I found using LLVM 9 installed via Homebrew.
-
If you are okay using the new
PassManager
infrastructure to run your passes viaopt
, then just use that on macOS and ignore the rest of the message. -
If you want to run your pass via
clang
, then you can use the legacyPassManager
with a simple change: insertDYLD_INSERT_LIBRARIES=path/to/dylib
before yourclang
/opt
invocation. This preloads the pass shared library before starting theclang
/opt
. Whenclang
/opt
eventually request to unload the library, they will decrement the ref count of the shared library, but the OS won't actually unload it, as the preload's ref is still outstanding. This prevents the crash at shutdown.
from llvm-pass-skeleton.
That's a neat idea, @mattgreen! Cool workaround.
from llvm-pass-skeleton.
It should be possible for the shared object to dlopen itself in a constructor such that the refcount is increased. Did someone try this? But I wonder why this hasn't been fixed in upstream llvm yet.
from llvm-pass-skeleton.
@minad I like that idea, but I'm not sure of an easy way to get the absolute path of the currently executing shared library on macOS. If you have any ideas please share!
from llvm-pass-skeleton.
@mattgreen I have no idea about mac. For me things work if I use the nodelete linker flag. But I am pretty sure it is possible on Mac to iterate over the loaded shared objects/the address space of the current process. On Linux there is dl_iterate_phdr or you could access /proc/self/maps.
from llvm-pass-skeleton.
But I am not sure if it is worth the effort to implement such a more sophisticated workaround. Llvm should be fixed instead.
from llvm-pass-skeleton.
Agree. The new PassManager + PassPlugin API doesn't seem to have these issues, I think that's why you're seeing it not be addressed. However, adoption of the new PassManager has been slow. Clang still has it gated behind -fexperimental-new-pass-manager
IIRC, and I'm not sure opt
is even using it yet.
from llvm-pass-skeleton.
@mattgreen How does the new pass manager work? Can we keep all the things as is for the plugin and simply pass -fexperimental-new-pass-manager to clang and things magically start working without znodelete?
from llvm-pass-skeleton.
There's also more on the "pass plugin" registration system in the docs:
http://llvm.org/docs/WritingAnLLVMPass.html#building-pass-plugins
from llvm-pass-skeleton.
Wow! That's awesome! Thank you for tracking this down, @EliaGeretto, and driving the effort to get it fixed. Wahoo!
from llvm-pass-skeleton.
Also, AFAIK, that mechanism is only for linking plugins statically
What does this mean? The whole issue is about dynamic objects being unloaded prematurely leading to segfaults.
In my case it would be really nice if dynamic plugins work properly such that stock clang can be used.
from llvm-pass-skeleton.
Related Issues (20)
- Running annotation module HOT 1
- Fatal Error For Attributes.gen HOT 6
- Unable to run the program HOT 3
- Compile error in the rtlib branch HOT 1
- Error while running the program HOT 7
- Error while making rtlib example HOT 6
- Error while compiling HOT 1
- Support for iOS in XCODE HOT 2
- Getting error : undefined symbol: _ZN4llvm23EnableABIBreakingChecksE HOT 1
- llvm instrumentation HOT 3
- pass has no effect HOT 1
- instrumentation: Linking With a Runtime Library HOT 1
- error: clang frontend command failed due to signal (use -v to see invocation) HOT 1
- Cmake for the "mutate" branch needs C++ 14 support
- Clang 14.0.5 unable to execute command: Aborted HOT 1
- fixes for version 15? HOT 1
- Now Make the Pass Do Something Mildly Interesting HOT 1
- Using C++ files for rtlib HOT 11
- The imported target "LLVMSupport" references the file "/usr/lib/libLLVMSupport.a" Error HOT 3
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from llvm-pass-skeleton.