https://github.com/alcxpr updated https://github.com/llvm/llvm-project/pull/165524
>From f303f139966b6753718aa3e12a2b3e2dc4ef5a4c Mon Sep 17 00:00:00 2001 From: typeal <[email protected]> Date: Wed, 29 Oct 2025 14:59:42 +0700 Subject: [PATCH] [Clang][CodeGen] Fix crash when compiling naked lambdas Skip instance and lambda prologue emission when a lambda is marked `naked`, preventing invalid access to `this` during code generation. --- clang/lib/CodeGen/CodeGenFunction.cpp | 82 +++++++++++++++----------- clang/test/CodeGenCXX/naked-lambda.cpp | 20 +++++++ 2 files changed, 66 insertions(+), 36 deletions(-) create mode 100644 clang/test/CodeGenCXX/naked-lambda.cpp diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp index 88628530cf66b..11e9e708f9b73 100644 --- a/clang/lib/CodeGen/CodeGenFunction.cpp +++ b/clang/lib/CodeGen/CodeGenFunction.cpp @@ -46,6 +46,7 @@ #include "llvm/IR/Intrinsics.h" #include "llvm/IR/MDBuilder.h" #include "llvm/Support/CRC.h" +#include "llvm/Support/Casting.h" #include "llvm/Support/xxhash.h" #include "llvm/Transforms/Scalar/LowerExpectIntrinsic.h" #include "llvm/Transforms/Utils/PromoteMemToReg.h" @@ -1271,50 +1272,59 @@ void CodeGenFunction::StartFunction(GlobalDecl GD, QualType RetTy, } } - EmitFunctionProlog(*CurFnInfo, CurFn, Args); + EmitFunctionProlog(*CurFnInfo, CurFn, Args); if (const CXXMethodDecl *MD = dyn_cast_if_present<CXXMethodDecl>(D); MD && !MD->isStatic()) { bool IsInLambda = MD->getParent()->isLambda() && MD->getOverloadedOperator() == OO_Call; - if (MD->isImplicitObjectMemberFunction()) - CGM.getCXXABI().EmitInstanceFunctionProlog(*this); - if (IsInLambda) { - // We're in a lambda; figure out the captures. - MD->getParent()->getCaptureFields(LambdaCaptureFields, - LambdaThisCaptureField); - if (LambdaThisCaptureField) { - // If the lambda captures the object referred to by '*this' - either by - // value or by reference, make sure CXXThisValue points to the correct - // object. - - // Get the lvalue for the field (which is a copy of the enclosing object - // or contains the address of the enclosing object). - LValue ThisFieldLValue = EmitLValueForLambdaField(LambdaThisCaptureField); - if (!LambdaThisCaptureField->getType()->isPointerType()) { - // If the enclosing object was captured by value, just use its - // address. Sign this pointer. - CXXThisValue = ThisFieldLValue.getPointer(*this); - } else { - // Load the lvalue pointed to by the field, since '*this' was captured - // by reference. - CXXThisValue = - EmitLoadOfLValue(ThisFieldLValue, SourceLocation()).getScalarVal(); + + const FunctionDecl *FD = dyn_cast_if_present<FunctionDecl>(D); + bool IsNaked = FD && FD->hasAttr<NakedAttr>(); + + if (!IsNaked) { + if (MD->isImplicitObjectMemberFunction()) + CGM.getCXXABI().EmitInstanceFunctionProlog(*this); + + if (IsInLambda) { + // We're in a lambda; figure out the captures. + MD->getParent()->getCaptureFields(LambdaCaptureFields, + LambdaThisCaptureField); + if (LambdaThisCaptureField) { + // If the lambda captures the object referred to by '*this' - either by + // value or by reference, make sure CXXThisValue points to the correct + // object. + + // Get the lvalue for the field (which is a copy of the enclosing object + // or contains the address of the enclosing object). + LValue ThisFieldLValue = + EmitLValueForLambdaField(LambdaThisCaptureField); + if (!LambdaThisCaptureField->getType()->isPointerType()) { + // If the enclosing object was captured by value, just use its + // address. Sign this pointer. + CXXThisValue = ThisFieldLValue.getPointer(*this); + } else { + // Load the lvalue pointed to by the field, since '*this' was captured + // by reference. + CXXThisValue = + EmitLoadOfLValue(ThisFieldLValue, SourceLocation()).getScalarVal(); + } } - } - for (auto *FD : MD->getParent()->fields()) { - if (FD->hasCapturedVLAType()) { - auto *ExprArg = EmitLoadOfLValue(EmitLValueForLambdaField(FD), - SourceLocation()).getScalarVal(); - auto VAT = FD->getCapturedVLAType(); - VLASizeMap[VAT->getSizeExpr()] = ExprArg; + + for (auto *FD : MD->getParent()->fields()) { + if (FD->hasCapturedVLAType()) { + auto *ExprArg = EmitLoadOfLValue(EmitLValueForLambdaField(FD), + SourceLocation()).getScalarVal(); + auto VAT = FD->getCapturedVLAType(); + VLASizeMap[VAT->getSizeExpr()] = ExprArg; + } } + } else if (MD->isImplicitObjectMemberFunction()) { + // Not in a lambda; just use 'this' from the method. + // FIXME: Should we generate a new load for each use of 'this'? The + // fast register allocator would be happier... + CXXThisValue = CXXABIThisValue; } - } else if (MD->isImplicitObjectMemberFunction()) { - // Not in a lambda; just use 'this' from the method. - // FIXME: Should we generate a new load for each use of 'this'? The - // fast register allocator would be happier... - CXXThisValue = CXXABIThisValue; } // Check the 'this' pointer once per function, if it's available. diff --git a/clang/test/CodeGenCXX/naked-lambda.cpp b/clang/test/CodeGenCXX/naked-lambda.cpp new file mode 100644 index 0000000000000..27ea1af09da01 --- /dev/null +++ b/clang/test/CodeGenCXX/naked-lambda.cpp @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -emit-llvm %s -o - | FileCheck %s +// RUN: %clang_cc1 -triple x86_64-pc-linux-gnu -S %s -o - | FileCheck %s --check-prefix=ASM + +void test_naked_lambda() { + auto l = []() __attribute__((naked)) { + asm volatile("retq"); + }; + l(); +} + +// CHECK: define internal void @"_ZZ17test_naked_lambdavENK3$_0clEv" +// CHECK-NOT: alloca +// CHECK-NOT: store +// CHECK-NOT: call void @_ZN +// ASM-LABEL: _ZZ17test_naked_lambdavENK3$_0clEv: +// ASM-NOT: push +// ASM-NOT: pop +// ASM: retq + + _______________________________________________ cfe-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
