Instruction::getDebugLoc can return an invalid DebugLoc. For such cases
where metadata was accidentally removed from the libcall insertion
point, simply insert a DILocation with line 0 scoped to the caller. When
we can inline the libcall, such as during LTO, then we won't fail a
Verifier check that all calls to functions with debug metadata
themselves must have debug metadata.
Details
Diff Detail
- Repository
- rG LLVM Github Monorepo
Event Timeline
WIP since I need to think more about the best way to fix this, but here's an example that trips the assertion. Very relevant is the statement in llvm::SplitCriticalEdge:
NewBI->setDebugLoc(TI->getDebugLoc());
where the synthesized block gets its debug info from the predecessor's branch (which can be none by accident).
Also, this is forked from https://reviews.llvm.org/D100137.
My best guess would be that any call synthesized from an instruction without a location should probably just get a zero line scoped directly to the current function. It's not ideal (not only the lack of location, but it also punches holes in scopes which can bloat debug info/make stepping more difficult as you hit discontiguous hunks of lines potentially, etc)
Sure. Should we do that unconditionally for the inserted CallInst, or predicate it on debug info being requested for the compilation, or something else?
It's not ideal (not only the lack of location, but it also punches holes in scopes which can bloat debug info/make stepping more difficult as you hit discontiguous hunks of lines potentially, etc)
For the purpose of ModuleSanitizerCoveragePass, I think that's ok. Developers accept a large increase in binary size anyways using the most aggressive level of tracing every edge, and stepping in a debugger probably isn't the use case folks are intending when using ModuleSanitizerCoveragePass. I would think the major use case for debug info with coverage is to symbolicate traces.
This constraint (that calls have a !dbg location) only exists when the calling llvm::Function has a !dbg attached DISubprogram. So basically retrieve the caller's DISubprogram, if it exists, create a line 0 DILocation with the DISubprogram as the scope.
(we might already have some code for this in the merge debug location code? some fallback for call instructions when merged locations disagree or one is empty, etc)
So basically retrieve the caller's DISubprogram, if it exists, create a line 0 DILocation with the DISubprogram as the scope.
Cool, yeah, that's what this pass already did; it just did not forsee that EntryLoc = IP->getDebugLoc(); could return an invalid DebugLoc (ie. because !dbg metadata was missing from the insertion point). Let me rephrase the description of this bug, then I think it's ready for review.
llvm/test/Instrumentation/SanitizerCoverage/crit-edge-sancov.ll | ||
---|---|---|
23 | DBG7 isn't checked against anything - should it be? (I guess it (the EntryLoc = IP->getDebugLoc(); line, I guess) is hopefully already tested by existing tests?) | |
24 | Probably good to check this is actually line 0, since that's what the code does intentionally - it'd be weird/problematic if we invented/used some other location. |
llvm/test/Instrumentation/SanitizerCoverage/crit-edge-sancov.ll | ||
---|---|---|
23 | I can add it.
Yes, llvm/test/Instrumentation/SanitizerCoverage/coverage2-dbg.ll does. | |
24 | I think it will be scopeLine of parent plus 0. |
llvm/test/Instrumentation/SanitizerCoverage/crit-edge-sancov.ll | ||
---|---|---|
24 | hmm, wait, that doesn't sound right - sorry, didn't realize that's what the code is doing. The code should be setting the line to 0, not the scopeLine. (line 0 is for lines that aren't related to any particular/identifiable line of source code) |
clang-tidy: warning: 'auto SP' can be declared as 'auto *SP' [llvm-qualified-auto]
not useful