This is an archive of the discontinued LLVM Phabricator instance.

[ubsan] Diagnose noreturn functions which return
ClosedPublic

Authored by vsk on Nov 30 2017, 5:59 PM.

Details

Summary

Diagnose 'unreachable' UB when a noreturn function returns.

  1. Insert a check at the end of functions marked noreturn.
  2. A decl may be marked noreturn in the caller TU, but not marked in the TU where it's defined. To diagnose this scenario, strip away the noreturn attribute and insert a check after the call.

Testing: check-clang, check-ubsan, check-ubsan-minimal, D40700

rdar://33660464

Diff Detail

Repository
rC Clang

Event Timeline

vsk created this revision.Nov 30 2017, 5:59 PM
vsk planned changes to this revision.Nov 30 2017, 6:16 PM

Ah, I've found a problem while writing run-time tests. I'll need to take another cut at this.

vsk updated this revision to Diff 125069.Nov 30 2017, 6:56 PM
vsk retitled this revision from [ubsan] Diagnose reached-unreachable after noreturn calls to [ubsan] Diagnose noreturn functions which return.
vsk edited the summary of this revision. (Show Details)
  • Emit the check in the noreturn function, so that the UB does not result in the optimizer throwing away the diagnostic instrumentation.
vsk updated this revision to Diff 125071.Nov 30 2017, 6:59 PM
  • Leave out an unrelated change in the handling of NakedAttr.
efriedma added inline comments.
lib/CodeGen/CGCall.cpp
2761

Unfortunately, this won't catch cases where the caller has a noreturn marking, but the callee doesn't. Maybe strip the noreturn attribute from the caller, then put the sanitizer check into both the caller and callee?

2769

This is likely a problem. Not because the code is supposed to be reachable, but because putting additional code into a naked function can have weird effects. Probably not worth messing with this case.

vsk added inline comments.Nov 30 2017, 7:12 PM
lib/CodeGen/CGCall.cpp
2761

If the caller sees a noreturn marking on the call target, inserting a 'reached-unreachable' check after the call is UB, and the optimizer throws it away. Perhaps you had a different case in mind?

2769

Sorry for the noisy change. I recognized it as a mistake a second after I uploaded the new diff :(.

efriedma added inline comments.Nov 30 2017, 7:16 PM
lib/CodeGen/CGCall.cpp
2761

I'm thinking of the case where the caller can't see the callee, like this:

a.c:
void a(void) __attribute((noreturn));
void b(void) { a(); }

b.c:
void a(void) {}

vsk planned changes to this revision.Nov 30 2017, 7:19 PM
vsk added inline comments.
lib/CodeGen/CGCall.cpp
2761

Got it. So clang would then do:

a.c:
void a(void) /* strip the noreturn attribute */;
void b(void) { a(); /* insert a reached-unreachable check here */}

vsk updated this revision to Diff 125221.Dec 1 2017, 1:52 PM
vsk edited the summary of this revision. (Show Details)
  • Diagnose in the scenario Eli pointed out, by stripping the 'noreturn' attribute and emitting a check after the call.
  • Test updates.
vsk added a reviewer: efriedma.Dec 1 2017, 1:53 PM
vsk marked 6 inline comments as done.
vsk updated this revision to Diff 127424.Dec 18 2017, 3:27 PM
  • Make the patch cleaner by introducing an overload of EmitCall() which doesn't require a SourceLocation argument.
vsk updated this revision to Diff 127426.Dec 18 2017, 3:44 PM
  • Tighten the IR test case.
This revision is now accepted and ready to land.Dec 20 2017, 2:32 PM
This revision was automatically updated to reflect the committed changes.