[llvm-dev] Get segfault with ModulePass

Gerion Entrup via llvm-dev llvm-dev at lists.llvm.org
Sun Jun 11 09:14:32 PDT 2017


Hi,

thanks for the answer.

Am Sonntag, 11. Juni 2017, 02:16:36 CEST schrieben Sie:
> Have you tried building LLVM with assertions enabled? Assertions are
> often a good way to catch API misuses, but they aren't on by default
> for release builds.
Good advice. You're right. Now an assertion triggers. The problem
seems to be the argument iterator.

Do you know some way to circumvent this. I've found no way to directly
get the ith argument of a function.

New stacktrace (same file btw):
-----------------
...
op_code: phi
clang-4.0: /usr/lib/llvm/4/include/llvm/ADT/ilist_iterator.h:139: llvm::ilist_iterator<OptionsT, IsReverse, IsConst>::reference llvm::ilist_iterator<OptionsT, IsReverse, IsConst>::operator*() const [with OptionsT = llvm::ilist_detail::node_options<llvm::Argument, true, false, void>; bool IsReverse = false; bool IsConst = true; llvm::ilist_iterator<OptionsT, IsReverse, IsConst>::reference = const llvm::Argument&]: Assertion `!NodePtr->isKnownSentinel()' failed.
#0 0x00007fc2b953a338 llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/usr/lib64/llvm/4/bin/../lib64/libLLVMSupport.so.4+0xf6338)
#1 0x00007fc2b9537f4e llvm::sys::RunSignalHandlers() (/usr/lib64/llvm/4/bin/../lib64/libLLVMSupport.so.4+0xf3f4e)
#2 0x00007fc2b95382f2 (/usr/lib64/llvm/4/bin/../lib64/libLLVMSupport.so.4+0xf42f2)
#3 0x00007fc2b6ef1170 (/lib64/libc.so.6+0x33170)
#4 0x00007fc2b6ef10f7 gsignal (/lib64/libc.so.6+0x330f7)
#5 0x00007fc2b6ef254a abort (/lib64/libc.so.6+0x3454a)
#6 0x00007fc2b6eea17d (/lib64/libc.so.6+0x2c17d)
#7 0x00007fc2b6eea232 (/lib64/libc.so.6+0x2c232)
#8 0x00007fc2aed8bd48 llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Argument, true, false, void>, false, true>::operator*() const /usr/lib/llvm/4/include/llvm/ADT/ilist_iterator.h:140:0
#9 0x00007fc2aed8b482 llvm::ilist_iterator<llvm::ilist_detail::node_options<llvm::Argument, true, false, void>, false, true>::operator->() const /usr/lib/llvm/4/include/llvm/ADT/ilist_iterator.h:142:0
#10 0x00007fc2aed895da (anonymous namespace)::GremlinPass::runOnModule(llvm::Module&) /home/gerion/sourcecode/debug-pass/debugpass/DebugPass.cpp:41:0
...
--------------------


> FWIW, StringRefs aren't guaranteed to be nul-terminated. They support
> a similar comparison API as std::strings, though, so things like
> `user->getOpcodeName() == "<Invalid operator>"` should just work™.
getOpcodeName returns a const char* (only reason I use strcmp, not a
big fan of this function either).

Gerion


> On Fri, Jun 9, 2017 at 4:54 PM, Gerion Entrup via llvm-dev
> <llvm-dev at lists.llvm.org> wrote:
> > Hi,
> >
> > don't know if this is the right list. Please post a better place,
> > otherwise.
> >
> > I'm currently writing a LLVM ModulePass and ran into strange segfaults or
> > endless loops within LLVM. My main question is, if this is a programming error
> > or API misuse from me or a LLVM bug?
> >
> > Here is some minimal code, that triggers the bug:
> > ----------------
> >         class DebugPass : public ModulePass {
> >         public:
> >                 static char ID;
> >                 DebugPass() : ModulePass(ID) {}
> >
> >                 virtual bool runOnModule(Module &M) override {
> >                         DILocation* loc;
> >                         for (auto &F : M) {
> >                                 for (auto &B : F) {
> >                                         for (auto &I : B) {
> >                                                 errs() << "op_code: " << I.getOpcodeName() << '\n';
> >                                                 loc = I.getDebugLoc();
> >                                                 if (loc != nullptr) {
> >                                                         errs() << "file: " << loc->getFilename() << '\n';
> >                                                 }
> >                                                 for (const auto& use : I.uses()) {
> >                                                         if (const CallInst* c = dyn_cast<CallInst>(use.getUser())) {
> >                                                                 const Function* f = c->getCalledFunction();
> >                                                                 if (f != nullptr) {
> >                                                                         for (unsigned i = 0; i < c->getNumArgOperands(); ++i) {
> >                                                                                 const Use& u = c->getArgOperandUse(i);
> >                                                                                 if (u.operator->() == &I) {
> >                                                                                         Function::const_arg_iterator ai = f->arg_begin();
> >                                                                                         std::advance(ai, i);
> >                                                                                         for (const auto& use : ai->uses()) {
> >                                                                                                 errs() << "next one\n";
> >                                                                                                 if (const Instruction* user = dyn_cast<Instruction>(use.getUser())) {
> >                                                                                                         errs() << "op_code2: " << user->getOpcodeName() << '\n';
> >                                                                                                         //if (std::strcmp("<Invalid operator> ", user->getOpcodeName()) == 0) {
> >                                                                                                         //      continue;
> >                                                                                                         //}
> >                                                                                                         loc = user->getDebugLoc();
> >                                                                                                         if (loc != nullptr) {
> >                                                                                                                 errs() << "file: " << loc->getFilename() << '\n';
> >                                                                                                         }
> >                                                                                                 }
> >                                                                                                 if (const Instruction* user = dyn_cast<Instruction>(use.operator->())) {
> >                                                                                                         errs() << "op_code3: " << user->getOpcodeName() << '\n';
> >                                                                                                         loc = user->getDebugLoc();
> >                                                                                                         if (loc != nullptr) {
> >                                                                                                                 errs() << "file: " << loc->getFilename() << '\n';
> >                                                                                                         }
> >                                                                                                 }
> >                                                                                         }
> >                                                                                         errs() << "loop end\n";
> >                                                                                         break;
> >                                                                                 }
> >                                                                         }
> >                                                                 }
> >                                                         }
> >                                                 }
> >                                         }
> >                                 }
> >                         }
> >                         return false;
> >                 }
> >         };
> > ------------------
> >
> > The segfault backtrace is this one:
> > ----------------
> > ...
> > op_code: phi
> > next one
> > op_code2: <Invalid operator>
> > #0 0x00007fa7135446b8 llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/usr/lib64/llvm/4/bin/../lib64/libLLVMSupport.so.4+0xe56b8)
> > #1 0x00007fa71354258e llvm::sys::RunSignalHandlers() (/usr/lib64/llvm/4/bin/../lib64/libLLVMSupport.so.4+0xe358e)
> > #2 0x00007fa71354280c (/usr/lib64/llvm/4/bin/../lib64/libLLVMSupport.so.4+0xe380c)
> > #3 0x00007fa711210170 (/lib64/libc.so.6+0x33170)
> > #4 0x00007fa709a06bf0 llvm::MDOperand::get() const /usr/lib/llvm/4/include/llvm/IR/Metadata.h:690:0
> > #5 0x00007fa709a06c0e llvm::MDOperand::operator llvm::Metadata*() const /usr/lib/llvm/4/include/llvm/IR/Metadata.h:691:0
> > #6 0x00007fa709a074d7 llvm::DILocation::getRawScope() const /usr/lib/llvm/4/include/llvm/IR/DebugInfoMetadata.h:1336:0
> > #7 0x00007fa709a07486 llvm::DILocation::getScope() const /usr/lib/llvm/4/include/llvm/IR/DebugInfoMetadata.h:1274:0
> > #8 0x00007fa709a074a8 llvm::DILocation::getFilename() const /usr/lib/llvm/4/include/llvm/IR/DebugInfoMetadata.h:1280:0
> > #9 0x00007fa709a062e2 (anonymous namespace)::DebugPass::runOnModule(llvm::Module&) /home/gerion/sourcecode/debug-pass/debugpass/DebugPass.cpp:50:0
> > ...
> > ----------------
> >
> > If I filter out the invalid operators I get an endless loop (the outcommented
> > lines).
> >
> > To get this running, I have used the gremlin-pass-skeleton I found on
> > Github [1] together with the modification for modules here [2].
> >
> > I load the pass with:
> > clang ... -g -Xclang load -Xclang /path/to/my/pass sourcefile.c
> >
> > I've tested the pass with the FFmpeg sources (and a modified configure).
> > The error happens in af_aformat.c [3].
> >
> > The meaning of the code is to get first an instruction, and if this
> > instruction is used as an argument in some function extract the instructions,
> > that uses the argument inside of the function body.
> >
> > Can somebody help me, to find another way to achive the (argument-)connection
> > between the instructions? And is the segfault a LLVM bug?
> >
> >
> > Regards,
> > Gerion
> >
> > [1] https://github.com/sampsyo/llvm-pass-skeleton
> > [2] https://github.com/sampsyo/llvm-pass-skeleton/issues/7
> > [3] https://github.com/FFmpeg/FFmpeg/blob/master/libavfilter/af_aformat.c
> > _______________________________________________
> > LLVM Developers mailing list
> > llvm-dev at lists.llvm.org
> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev




More information about the llvm-dev mailing list