From bf13b30ff28e64528806076cc88cc46aa2634e62 Mon Sep 17 00:00:00 2001 From: George Burgess IV <george.burgess.iv@gmail.com> Date: Thu, 16 Jun 2016 23:06:04 +0000 Subject: [PATCH] [CodeGen] Fix a segfault caused by pass_object_size. This patch fixes a bug where we'd segfault (in some cases) if we saw a variadic function with one or more pass_object_size arguments. Differential Revision: http://reviews.llvm.org/D17462 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@272971 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/CodeGen/CGFunctionInfo.h | 29 ++++++++++++++++++-------- lib/CodeGen/CGCall.cpp | 16 +++++++------- lib/CodeGen/CGExprCXX.cpp | 9 ++++---- lib/CodeGen/CGVTables.cpp | 5 ++--- test/CodeGen/pass-object-size.c | 15 +++++++++++++ test/CodeGenCXX/pass-object-size.cpp | 27 ++++++++++++++++++++++++ 6 files changed, 78 insertions(+), 23 deletions(-) diff --git a/include/clang/CodeGen/CGFunctionInfo.h b/include/clang/CodeGen/CGFunctionInfo.h index a7f3bb976c8..699b005f5aa 100644 --- a/include/clang/CodeGen/CGFunctionInfo.h +++ b/include/clang/CodeGen/CGFunctionInfo.h @@ -16,8 +16,10 @@ #ifndef LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H #define LLVM_CLANG_CODEGEN_CGFUNCTIONINFO_H +#include "clang/AST/Attr.h" #include "clang/AST/CanonicalType.h" #include "clang/AST/CharUnits.h" +#include "clang/AST/Decl.h" #include "clang/AST/Type.h" #include "llvm/IR/DerivedTypes.h" #include "llvm/ADT/FoldingSet.h" @@ -25,8 +27,6 @@ #include <cassert> namespace clang { -class Decl; - namespace CodeGen { /// ABIArgInfo - Helper class to encapsulate information about how a @@ -393,23 +393,34 @@ public: /// Compute the arguments required by the given formal prototype, /// given that there may be some additional, non-formal arguments /// in play. + /// + /// If FD is not null, this will consider pass_object_size params in FD. static RequiredArgs forPrototypePlus(const FunctionProtoType *prototype, - unsigned additional) { + unsigned additional, + const FunctionDecl *FD) { if (!prototype->isVariadic()) return All; + if (FD) + additional += std::count_if(FD->param_begin(), FD->param_end(), + [](const ParmVarDecl *PVD) { + return PVD->hasAttr<PassObjectSizeAttr>(); + }); return RequiredArgs(prototype->getNumParams() + additional); } - static RequiredArgs forPrototype(const FunctionProtoType *prototype) { - return forPrototypePlus(prototype, 0); + static RequiredArgs forPrototype(const FunctionProtoType *prototype, + const FunctionDecl *FD) { + return forPrototypePlus(prototype, 0, FD); } - static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype) { - return forPrototype(prototype.getTypePtr()); + static RequiredArgs forPrototype(CanQual<FunctionProtoType> prototype, + const FunctionDecl *FD) { + return forPrototype(prototype.getTypePtr(), FD); } static RequiredArgs forPrototypePlus(CanQual<FunctionProtoType> prototype, - unsigned additional) { - return forPrototypePlus(prototype.getTypePtr(), additional); + unsigned additional, + const FunctionDecl *FD) { + return forPrototypePlus(prototype.getTypePtr(), additional, FD); } bool allowsOptionalArgs() const { return NumRequired != ~0U; } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index be52009bfde..dec071440ad 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -141,7 +141,8 @@ arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod, CanQual<FunctionProtoType> FTP, const FunctionDecl *FD) { SmallVector<FunctionProtoType::ExtParameterInfo, 16> paramInfos; - RequiredArgs required = RequiredArgs::forPrototypePlus(FTP, prefix.size()); + RequiredArgs Required = + RequiredArgs::forPrototypePlus(FTP, prefix.size(), FD); // FIXME: Kill copy. appendParameterTypes(CGT, prefix, paramInfos, FTP, FD); CanQualType resultType = FTP->getReturnType().getUnqualifiedType(); @@ -149,7 +150,7 @@ arrangeLLVMFunctionInfo(CodeGenTypes &CGT, bool instanceMethod, return CGT.arrangeLLVMFunctionInfo(resultType, instanceMethod, /*chainCall=*/false, prefix, FTP->getExtInfo(), paramInfos, - required); + Required); } /// Arrange the argument and result information for a value of the @@ -338,7 +339,7 @@ CodeGenTypes::arrangeCXXConstructorCall(const CallArgList &args, ArgTypes.push_back(Context.getCanonicalParamType(Arg.Ty)); CanQual<FunctionProtoType> FPT = GetFormalType(D); - RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs); + RequiredArgs Required = RequiredArgs::forPrototypePlus(FPT, 1 + ExtraArgs, D); GlobalDecl GD(D, CtorKind); CanQualType ResultType = TheCXXABI.HasThisReturn(GD) ? ArgTypes.front() @@ -555,10 +556,11 @@ CodeGenTypes::arrangeBlockFunctionDeclaration(const FunctionProtoType *proto, auto paramInfos = getExtParameterInfosForCall(proto, 1, params.size()); auto argTypes = getArgTypesForDeclaration(Context, params); - return arrangeLLVMFunctionInfo(GetReturnType(proto->getReturnType()), - /*instanceMethod*/ false, /*chainCall*/ false, - argTypes, proto->getExtInfo(), paramInfos, - RequiredArgs::forPrototypePlus(proto, 1)); + return arrangeLLVMFunctionInfo( + GetReturnType(proto->getReturnType()), + /*instanceMethod*/ false, /*chainCall*/ false, argTypes, + proto->getExtInfo(), paramInfos, + RequiredArgs::forPrototypePlus(proto, 1, nullptr)); } const CGFunctionInfo & diff --git a/lib/CodeGen/CGExprCXX.cpp b/lib/CodeGen/CGExprCXX.cpp index 7e17c55ee60..eec2aceb88a 100644 --- a/lib/CodeGen/CGExprCXX.cpp +++ b/lib/CodeGen/CGExprCXX.cpp @@ -54,7 +54,7 @@ commonEmitCXXMemberOrOperatorCall(CodeGenFunction &CGF, const CXXMethodDecl *MD, } const FunctionProtoType *FPT = MD->getType()->castAs<FunctionProtoType>(); - RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size()); + RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, Args.size(), MD); // And the rest of the call args. if (CE) { @@ -324,10 +324,11 @@ CodeGenFunction::EmitCXXMemberPointerCallExpr(const CXXMemberCallExpr *E, // Push the this ptr. Args.add(RValue::get(ThisPtrForCall), ThisType); - RequiredArgs required = RequiredArgs::forPrototypePlus(FPT, 1); - + RequiredArgs required = + RequiredArgs::forPrototypePlus(FPT, 1, /*FD=*/nullptr); + // And the rest of the call args - EmitCallArgs(Args, FPT, E->arguments(), E->getDirectCallee()); + EmitCallArgs(Args, FPT, E->arguments()); return EmitCall(CGM.getTypes().arrangeCXXMethodCall(Args, FPT, required), Callee, ReturnValue, Args); } diff --git a/lib/CodeGen/CGVTables.cpp b/lib/CodeGen/CGVTables.cpp index c016220d846..38461446de5 100644 --- a/lib/CodeGen/CGVTables.cpp +++ b/lib/CodeGen/CGVTables.cpp @@ -290,9 +290,8 @@ void CodeGenFunction::EmitCallAndReturnForThunk(llvm::Value *Callee, const FunctionProtoType *FPT = MD->getType()->getAs<FunctionProtoType>(); #ifndef NDEBUG - const CGFunctionInfo &CallFnInfo = - CGM.getTypes().arrangeCXXMethodCall(CallArgs, FPT, - RequiredArgs::forPrototypePlus(FPT, 1)); + const CGFunctionInfo &CallFnInfo = CGM.getTypes().arrangeCXXMethodCall( + CallArgs, FPT, RequiredArgs::forPrototypePlus(FPT, 1, MD)); assert(CallFnInfo.getRegParm() == CurFnInfo->getRegParm() && CallFnInfo.isNoReturn() == CurFnInfo->isNoReturn() && CallFnInfo.getCallingConvention() == CurFnInfo->getCallingConvention()); diff --git a/test/CodeGen/pass-object-size.c b/test/CodeGen/pass-object-size.c index 1ad3f853ca6..6e2bc2090ed 100644 --- a/test/CodeGen/pass-object-size.c +++ b/test/CodeGen/pass-object-size.c @@ -351,3 +351,18 @@ void test13() { ObjectSize0(++p); ObjectSize0(p++); } + +// There was a bug where variadic functions with pass_object_size would cause +// problems in the form of failed assertions. +void my_sprintf(char *const c __attribute__((pass_object_size(0))), ...) {} + +// CHECK-LABEL: define void @test14 +void test14(char *c) { + // CHECK: @llvm.objectsize + // CHECK: call void (i8*, i64, ...) @my_sprintf + my_sprintf(c); + + // CHECK: @llvm.objectsize + // CHECK: call void (i8*, i64, ...) @my_sprintf + my_sprintf(c, 1, 2, 3); +} diff --git a/test/CodeGenCXX/pass-object-size.cpp b/test/CodeGenCXX/pass-object-size.cpp index 0a093c8deac..7fd8b599aaa 100644 --- a/test/CodeGenCXX/pass-object-size.cpp +++ b/test/CodeGenCXX/pass-object-size.cpp @@ -53,3 +53,30 @@ namespace delegate { // CHECK: define void @_ZN8delegate1AC1EPvU17pass_object_size0({{[^,]*}}, i8*{{[^,]*}}, i64{{[^,]*}}) // CHECK: call void @_ZN8delegate1AC2EPvU17pass_object_size0({{[^,]*}}, i8*{{[^,]*}}, i64{{[^,]*}}) } + +namespace variadic { +// We had an issue where variadic member/operator calls with pass_object_size +// would cause crashes. + +struct AsCtor { + AsCtor(const char *const c __attribute__((pass_object_size(0))), double a, + ...) {} +}; + +struct AsMember { + void bar(const char *const c __attribute__((pass_object_size(0))), double a, + ...) {} + void operator()(const char *const c __attribute__((pass_object_size(0))), + double a, ...) {} +}; + +// CHECK-LABEL: define void @_ZN8variadic4testEv() +void test() { + // CHECK-RE: call{{[^@]+}}@_ZN8variadic6AsCtorC1EPKcU17pass_object_size0dz + AsCtor("a", 1.0); + // CHECK-RE: call{{[^@]+}}@_ZN8variadic8AsMember3barEPKcU17pass_object_size0dz + AsMember{}.bar("a", 1.0); + // CHECK-RE: call{{[^@]+}}@_ZN8variadic8AsMemberclEPKcU17pass_object_size0dz + AsMember{}("a", 1.0); +} +} -- GitLab