This is an archive of the discontinued LLVM Phabricator instance.

[SantizerCoverage] handle missing DBG MD when inserting libcalls
ClosedPublic

Authored by nickdesaulniers on Apr 8 2021, 6:02 PM.

Details

Summary

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.

Diff Detail

Event Timeline

nickdesaulniers requested review of this revision.Apr 8 2021, 6:02 PM
nickdesaulniers created this revision.
Herald added a project: Restricted Project. · View Herald TranscriptApr 8 2021, 6:02 PM
nickdesaulniers planned changes to this revision.EditedApr 8 2021, 6:04 PM

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)

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.

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.

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.

Sure. Should we do that unconditionally for the inserted CallInst, or predicate it on debug info being requested for the compilation, or something else?

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)

  • handle case where existing DebugLoc was invalid
nickdesaulniers planned changes to this revision.Apr 9 2021, 2:14 PM

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.

nickdesaulniers requested review of this revision.Apr 9 2021, 2:18 PM
nickdesaulniers retitled this revision from [SantizerCoverage] test case demonstrating PR39531 to [SantizerCoverage] handle missing DBG MD when inserting libcalls.
nickdesaulniers edited the summary of this revision. (Show Details)
nickdesaulniers edited the summary of this revision. (Show Details)
  • fix lint about auto*
dblaikie added inline comments.Apr 9 2021, 5:46 PM
llvm/test/Instrumentation/SanitizerCoverage/crit-edge-sancov.ll
24

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?)

25

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.

  • add DBG7 check, specific lines
nickdesaulniers marked 2 inline comments as done.Apr 9 2021, 6:58 PM
nickdesaulniers added inline comments.
llvm/test/Instrumentation/SanitizerCoverage/crit-edge-sancov.ll
24

I can add it.

I guess it (the EntryLoc = IP->getDebugLoc(); line, I guess) is hopefully already tested by existing tests?

Yes, llvm/test/Instrumentation/SanitizerCoverage/coverage2-dbg.ll does.

25

I think it will be scopeLine of parent plus 0.

nickdesaulniers marked 2 inline comments as done.Apr 12 2021, 1:01 PM
dblaikie added inline comments.Apr 12 2021, 1:55 PM
llvm/test/Instrumentation/SanitizerCoverage/crit-edge-sancov.ll
25

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)

  • fix line 0 DILocation
nickdesaulniers marked an inline comment as done.Apr 12 2021, 3:20 PM
dblaikie accepted this revision.Apr 12 2021, 3:38 PM

Looks good - thanks!

This revision is now accepted and ready to land.Apr 12 2021, 3:38 PM

Thanks as always for the review; appreciated!

This revision was landed with ongoing or failed builds.Apr 12 2021, 4:06 PM
This revision was automatically updated to reflect the committed changes.