This is an archive of the discontinued LLVM Phabricator instance.

[CodeGen] Fix a crash that occurs when attribute "naked" is attached to a c++ member function
Needs ReviewPublic

Authored by ahatanak on Dec 16 2015, 6:42 PM.

Details

Reviewers
rnk
Summary

clang crashes when it compiles a member function or a lambda is marked as "naked":

struct S {

__attribute__((naked)) S() {}

}

To fix this bug, this patch defines a function that cleans up the naked function removing all allocas and their users and all basic blocks except the entry block. Also, it makes changes so that, if a non-void function is marked as naked, llvm.trap isn't inserted into the function even if it doesn't have a return statement.

Diff Detail

Event Timeline

ahatanak updated this revision to Diff 43095.Dec 16 2015, 6:42 PM
ahatanak retitled this revision from to [CodeGen] Fix a crash that occurs when attribute "naked" is attached to a c++ member function.
ahatanak updated this object.
ahatanak added a subscriber: cfe-commits.
hans added a reviewer: rnk.Jan 12 2016, 1:47 PM
hans added a subscriber: hans.

Just out of curiosity, where does this come up in practice?

It seems a little backward that we're first emitting a bunch of instructions, only to remove them later. It would be nice if for naked function we wouldn't emit them in the first place. But maybe that's not practical.

Anyway, this seems OK to me but I'd like to hear what Reid thinks too.

lib/CodeGen/CodeGenFunction.cpp
1975

would declaring I as llvm::Instruction* allow you to get rid off the "&*" stuff here and below? If so, same for "auto BB" further down.

1993

i don't think there's any need for curlies around the else branch here, especially since there are none for the then-branch

In D15599#325113, @hans wrote:

Just out of curiosity, where does this come up in practice?

I only have a short test case a user provided so t's not really clear whether it was necessary to mark a member function naked or there were other ways to get the same behavior. But unless we want to disallow marking member functions as naked, we shouldn't let clang crash when it compiles such functions.

It seems a little backward that we're first emitting a bunch of instructions, only to remove them later. It would be nice if for naked function we wouldn't emit them in the first place. But maybe that's not practical.

I initially tried to block the instructions from being emitted but I ended up checking hasAttr<NakedAttr>() in a lot of places. I agree approach taken in this patch might look a bit backward, but it seemed better than the alternative.

Anyway, this seems OK to me but I'd like to hear what Reid thinks too.

Thanks for working on this! A few comments inline.

Manman

lib/CodeGen/CodeGenFunction.cpp
1983

Do we need to check if the user has been erased? I am not sure if the same instruction can be pushed multiple times into InstrsToRemove.

2000

Is it possible that T has been erased in the above?

ahatanak added inline comments.Jan 22 2016, 1:01 PM
lib/CodeGen/CodeGenFunction.cpp
1983

I think you are right: it's incorrect to assume an instruction cannot be pushed twice. I'll change the type of InstrsToRemove to a set to prevent that from happenning.

2000

I'm not sure I understand. getTerminator will return null if there is no terminator or the basic block is empty, so I think this code is safe?

ahatanak added inline comments.Jan 25 2016, 1:37 PM
lib/CodeGen/CodeGenFunction.cpp
1975

We can git rid of the "&*" in the code here if we declare I as Instruction*, but we will need to add "&*" to Entry->begin() to convert it to an Instruction*. In addition, we will have to use getNextNode instead of ++II or I++, so it seems to me that using an iterator is better in this case.

ahatanak updated this revision to Diff 45910.Jan 25 2016, 1:41 PM

Address review comments from Hans and Manman.

manmanren added inline comments.Jan 25 2016, 2:07 PM
lib/CodeGen/CodeGenFunction.cpp
2000

Yes, you are right.

ahatanak updated this revision to Diff 49213.Feb 26 2016, 11:09 AM

ping and rebase.

rnk edited edge metadata.Mar 11 2016, 1:32 PM

I guess I'm OK with the approach.

lib/CodeGen/CodeGenFunction.cpp
1970

This isn't the right approach. Look at Function::dropAllReferences and try modelling this code on that. This does a lot of unnecessary RAUW when we can just null out all operands and delete all instructions except for the inline asm CallInst.

test/CodeGen/attr-naked.c
20

unrelated change?

test/CodeGenCXX/attr-naked.cpp
8

Can you add a test involving vtable thunks? I'm worried that we will clean up the thunk for a naked virtual method implementation. The code looks correct today, but I'd like to defend against that possibility in the future.

31

Won't this require asserts? We don't name BBs in NDEBUG builds.

ahatanak updated this revision to Diff 50759.Mar 15 2016, 11:41 AM
ahatanak edited edge metadata.

Address review comments.

  • Rewrite cleanupNakedFunction.
  • Fix test case attr-naked.cpp. Check that the thunk function doesn't get removed when the virtual function is marked "naked".
ahatanak marked 2 inline comments as done.Mar 15 2016, 11:44 AM
ahatanak added inline comments.
test/CodeGen/attr-naked.c
20

This is a side effect of not exiting early in CodeGenFunction::EmitFunctionProlog.

test/CodeGenCXX/attr-naked.cpp
8

I've also added a check to make sure the thunk isn't marked naked.