[cfe-commits] [PATCH] Fix support for naked C/C++ functions writing to unexpected memory regions in debug builds

Eli Friedman eli.friedman at gmail.com
Fri Nov 9 14:39:26 PST 2012


2012/11/8 Jeffrey Lim <jeff at lim.com.au>:
>
>
> Hi Eli (or others),
>
> If you could kindly have a look at this updated proposed patch to correct
> the errors.
>
> The current svn version (r167575) has an additional problem with naked
> functions than the version released with Xcode due to r165914 which inserts
> llvm.trap and unreachable annotations in debug builds in naked functions
> that need to return a value.
>
> test.cpp:
> class MyClass
> {
> public:
> int NakedTest(int value, int value2);
> };
>
> __attribute((noinline, naked)) int MyClass::NakedTest(int value, int value2)
> {
> asm("");
> }
>
> clang -S -flto test.cpp
> test.s:
>
> ; ModuleID = 'test.cpp'
> target datalayout =
> "e-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-v64:64:64-v128:128:128-a0:0:64-s0:64:64-f80:128:128-n8:16:32:64-S128"
> target triple = "x86_64-apple-macosx10.8.0"
>
> %class.MyClass = type { i8 }
>
> define i32 @_ZN7MyClass9NakedTestEii(%class.MyClass* %this, i32 %value, i32
> %value2) nounwind uwtable noinline ssp naked align 2 {
> entry:
>   %retval = alloca i32, align 4
>   %this.addr = alloca %class.MyClass*, align 8
>   %value.addr = alloca i32, align 4
>   %value2.addr = alloca i32, align 4
>   store %class.MyClass* %this, %class.MyClass** %this.addr, align 8
>   store i32 %value, i32* %value.addr, align 4
>   store i32 %value2, i32* %value2.addr, align 4
>   %this1 = load %class.MyClass** %this.addr
>   call void asm sideeffect "", "~{dirflag},~{fpsr},~{flags}"() nounwind,
> !srcloc !0
>   call void @llvm.trap()
>   unreachable
>
> return:                                           ; No predecessors!
>   %0 = load i32* %retval
>   ret i32 %0
> }
>
> declare void @llvm.trap() noreturn nounwind
>
> !0 = metadata !{i32 154}
>
>
> The bolded lines are new compare to the clang that shipped with Xcode 4.5.2
>
> I've added a separate path for naked functions in GenerateCode, and avoid
> the generation of trap/unreachable for undefined return paths for naked
> functions.
>
> I'm also not sure whether I'm doing the right thing with return types -- if
> the function is naked, then there can't be a value around for it to return,
> so I've forced it to be void. This then fails the Verifier for return types,
> so I've attached a llvm.naked.patch which bypasses the return type check for
> naked functions.
>
> I've left a bunch of commented out code in StartNakedFunction( ) for review
> by someone more knowledgeable than me because I'm not particularly confident
> my understanding of what should be there or not is adequate. Ideally all of
> this commented section would be stripped before submitting.
>
> I've also run "make clang-test" before submitting these patches - hopefully
> that means I haven't messed things up too bad :)

Please split the change to factor out
GenerateSubprogramDebugDescriptor and GenerateStartFunctionBlocks into
a separate patch.

I'm assuming you're leaving in the commented-out lines for review
purposes?  We wouldn't want to commit something like that.

+// Naked functions cannot be inline

Yes.

+// OpenCL doesn't support naked functions

Yes.

+// I'm guessing we shouldn't emit instrumentation functions when we
don't even know if we have a standard stack frame

Well, even if the function does have a standard stack frame, we would
be emitting this call before we built the stack frame.  Fine.

+// Naked functions have no prolog

Yes.

+// Class member naked functions also have no prolog, nor should they

Yes.

+// I don't think this is necessary for naked functions either
+//  // If any of the arguments have a variably modified type, make sure to
+//  // emit the type size.

Yes.

-  unsigned N = RI.getNumOperands();
-  if (F->getReturnType()->isVoidTy())
-    Assert2(N == 0,
-            "Found return instr that returns non-void in Function of void "
-            "return type!", &RI, F->getReturnType());
-  else
-    Assert2(N == 1 && F->getReturnType() == RI.getOperand(0)->getType(),
-            "Function return type does not match operand "
-            "type of return inst!", &RI, F->getReturnType());
+  if(!F->isNaked())
+  {
+    unsigned N = RI.getNumOperands();
+    if (F->getReturnType()->isVoidTy())
+      Assert2(N == 0,
+              "Found return instr that returns non-void in Function of void "
+              "return type!", &RI, F->getReturnType());
+    else
+      Assert2(N == 1 && F->getReturnType() == RI.getOperand(0)->getType(),
+              "Function return type does not match operand "
+              "type of return inst!", &RI, F->getReturnType());
+  }

I don't think this is acceptable; this is likely to confuse the
optimizers.  This really needs some design discussion; please bring it
up on llvmdev.

-Eli



More information about the cfe-commits mailing list