[llvm-dev] Get segfault with ModulePass

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
5 messages Options
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

[llvm-dev] Get segfault with ModulePass

Gerolf Hoflehner via llvm-dev
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
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] Get segfault with ModulePass

Gerolf Hoflehner via llvm-dev
Hi,

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.

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™.

George

On Fri, Jun 9, 2017 at 4:54 PM, Gerion Entrup via llvm-dev
<[hidden email]> 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
> [hidden email]
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] Get segfault with ModulePass

Gerolf Hoflehner via llvm-dev
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
> <[hidden email]> 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
> > [hidden email]
> > http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev


_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] Get segfault with ModulePass

Gerolf Hoflehner via llvm-dev
On 6/11/2017 9:14 AM, Gerion Entrup via llvm-dev wrote:

> 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.

Have you tried dumping the function declaration which crashes
("F->dump()")?  I suspect you're running into a function that doesn't
have as many arguments as you expect.

-Eli

--
Employee of Qualcomm Innovation Center, Inc.
Qualcomm Innovation Center, Inc. is a member of Code Aurora Forum, a Linux Foundation Collaborative Project

_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Reply | Threaded
Open this post in threaded view
|  
Report Content as Inappropriate

Re: [llvm-dev] Get segfault with ModulePass

Gerolf Hoflehner via llvm-dev
Am Montag, 12. Juni 2017, 19:31:52 CEST schrieben Sie:

> On 6/11/2017 9:14 AM, Gerion Entrup via llvm-dev wrote:
> > 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.
>
> Have you tried dumping the function declaration which crashes
> ("F->dump()")?  I suspect you're running into a function that doesn't
> have as many arguments as you expect.
That was it, thank you. The function has varargs and the i points to the
variable argument.

A simple check prevents the error.

Gerion
_______________________________________________
LLVM Developers mailing list
[hidden email]
http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-dev
Loading...