-
Notifications
You must be signed in to change notification settings - Fork 188
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
ModulePasses with Auto Registration #7
Comments
Cool! So, to clarify, you just needed to choose the right extension point ( |
Correct, with EP_EarlyAsPossible I was getting Segmentation faults. |
Yep, that matches my experience—some EPs are for function passes and some are for module passes, but this isn't well documented. |
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:
|
I'm recalling purely from memory, but here's how I remember it being structured: there are |
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 |
Indeed; thanks for pointing it out! I'll leave this issue open in the hopes that other Google searchers will find it. |
Yes, it helped a lot, thank you! |
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? |
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. |
will report back. It's almost certainly something I am doing wrong. |
It seems the segfault happens due to premature unloading of the shared object. It works for me if I compile the plugin with |
It works for me, now I can use ModulePass. Thanks for afl-fuzz! |
I spent a while looking into this today. To be specific, the problem looks like this on my system, at the moment:
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 This problem has been reported to the LLVM bug tracker a few times, but hasn't gotten much traction: Using |
Hi! Were you able to find a workaround with the -z flag to the linker for macOS? The TLDR is: |
Nope, no current solution! If you find anything good (or can bring it to the attention of the LLVM developers), please let us know. |
The trick is to pass -Wl,-znodelete to the linker. See sampsyo/llvm-pass-skeleton#7 for more information.
The trick is to pass -Wl,-znodelete to the linker. See sampsyo/llvm-pass-skeleton#7 for more information. Byfl can now pass regression tests against the Ubuntu package of LLVM/Clang 7.
Dug into this issue a bit, here's what I found using LLVM 9 installed via Homebrew.
|
That's a neat idea, @mattgreen! Cool workaround. |
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. |
@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! |
@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. |
But I am not sure if it is worth the effort to implement such a more sophisticated workaround. Llvm should be fixed instead. |
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 |
@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? |
At least with clang-9, you can force it to load your shared library via the new pass manager:
I haven't used this myself; I'm content using the See this snippet in llvm-tutor for an example of how to use the new PassPlugin API. |
There's also more on the "pass plugin" registration system in the docs: |
The bug in 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 |
Wow! That's awesome! Thank you for tracking this down, @EliaGeretto, and driving the effort to get it fixed. Wahoo! |
Super happy to see this being fixed, thank you @EliaGeretto !
@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! |
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. |
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 |
Please note that replacing -znodelete is actually impossible on macOS, this fix is tested working with LLVM 10 provided by homebrew, still needs proper testing with LLVM 9 where early plugin unloading used to wreak havoc on platforms other than Linux: sampsyo/llvm-pass-skeleton#7
Please note that replacing -znodelete is actually impossible on macOS, this fix is tested working with LLVM 10 provided by homebrew, still needs proper testing with LLVM 9 where early plugin unloading used to wreak havoc on platforms other than Linux: sampsyo/llvm-pass-skeleton#7
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.
As you can see, trying to run the module pass before the other optimizations causes it generate segmentation faults/assertion faults depending on the method. Also,
PassManagerBuilder::EP_ModuleOptimizerEarly
worked as well. I'm assuming the rest of the options should work since they are working within the module. Here is my example that uses your basic framework from your examples.Important Content:
Source Code:
The text was updated successfully, but these errors were encountered: