forked from OSchip/llvm-project
[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 llvm-svn: 272971
This commit is contained in:
parent
c953bb9953
commit
419996ccb5
|
@ -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; }
|
||||
|
|
|
@ -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 &
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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());
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue