This is an archive of the discontinued LLVM Phabricator instance.

Verifier: Don't reject varargs callee cleanup functions
ClosedPublic

Authored by rnk on Aug 25 2014, 6:41 PM.

Details

Summary

We've rejected these kinds of functions since r28405 in 2006 because
it's impossible to lower the return of a callee cleanup varargs
function. However there are lots of legal ways to leave such a function
without returning, such as aborting. Today we can leave a function with
a musttail call to another function with the correct prototype, and
everything works out.

Therefore I'd like to remove the verifier check just say that a normal
return from such a function is UB.

Diff Detail

Repository
rL LLVM

Event Timeline

rnk updated this revision to Diff 12929.Aug 25 2014, 6:41 PM
rnk retitled this revision from to Verifier: Don't reject varargs callee cleanup functions.
rnk updated this object.
rnk added reviewers: rafael, nlewycky.
rnk added a subscriber: Unknown Object (MLST).
rnk updated this revision to Diff 12931.Aug 25 2014, 6:44 PM

Add missing file

liouys removed a subscriber: liouys.
rnk updated this revision to Diff 13055.Aug 28 2014, 1:11 PM
  • Fix calls to callee cleanup varargs functions and test it
nlewycky edited edge metadata.Aug 28 2014, 1:16 PM

Hunh. I'd think I'd prefer it if the verifier could check that the function defined callee cleanup and variadic doesn't return (unless the return is a musttail). I dislike making musttail even more special, but I think I just have to learn to deal with it.

lib/Target/X86/X86ISelLowering.cpp
3550 ↗(On Diff #13055)

Isn't there a fallthrough annotation or comment to use here?

rnk added a comment.Aug 28 2014, 2:01 PM

Clang also used to generate code like:

define x86_thiscallcc i32 @my_vmemptr(i8*, i32, i32) {
entry:
  %retslot = alloca i32
  %r = musttail call @my_target(i8* %0, i32 %1, i32 %2)
  ret i32 %r
exit: ; no predecessors!
  %ret = load i32* %retslot
  ret i32 %ret
}

While we don't do that today, should the verifier reject such code? Should it ignore unreachable blocks?

We could report_fatal_error in TLI::LowerReturn if isVarArgs&&isCalleeCleanup, but then we would abort on this precise example at -O0.

You can also imagine replacing the musttail call with a call to abort + unreachable.

lib/Target/X86/X86ISelLowering.cpp
3550 ↗(On Diff #13055)

I thought it was OK to have multiple case labels one after another without annotating fallthrough. The whitespace in phab isn't actually present in the code, see the missing line number on the left.

rnk updated this revision to Diff 13059.Aug 28 2014, 3:38 PM
rnk edited edge metadata.

Add a verifier check for normal returns

Yup, I've changed my mind.

A pass should be able to fold "br i1 false, label %bb1, label %bb2" into "br label %bb2" without worrying about making the module fail verification. Hence, testing for "isReachableFromEntry" is a bad idea here. Please allow it, then commit it.

rnk closed this revision.Aug 29 2014, 2:35 PM
rnk updated this revision to Diff 13110.

Closed by commit rL216779 (authored by @rnk).

rnk added a comment.Aug 29 2014, 2:35 PM
In D5059#14, @nlewycky wrote:

Yup, I've changed my mind.

A pass should be able to fold "br i1 false, label %bb1, label %bb2" into "br label %bb2" without worrying about making the module fail verification. Hence, testing for "isReachableFromEntry" is a bad idea here. Please allow it, then commit it.

OK, sounds good. :) Thanks!