Skip to content

Commit 1880c11

Browse files
ojhuntyuxuanchen1997
authored andcommitted
[clang] Ensure pointers passed to runtime support functions are correctly signed (#98276)
Summary: Updates codegen for global destructors and raising exceptions to ensure that the function pointers being passed are signed using the correct schema. Notably this requires that CodeGenFunction::createAtExitStub to return an opaque Constant* rather than a Function* as the value being emitted is no longer necessarily a raw function pointer depending on the configured ABI. Co-Authored-By: Akira Hatanaka <[email protected]> Co-Authored-By: John McCall <[email protected]> Test Plan: Reviewers: Subscribers: Tasks: Tags: Differential Revision: https://phabricator.intern.facebook.com/D60251016
1 parent c466bea commit 1880c11

File tree

5 files changed

+82
-6
lines changed

5 files changed

+82
-6
lines changed

clang/lib/CodeGen/CGDeclCXX.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -232,7 +232,7 @@ void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
232232

233233
/// Create a stub function, suitable for being passed to atexit,
234234
/// which passes the given address to the given destructor function.
235-
llvm::Function *CodeGenFunction::createAtExitStub(const VarDecl &VD,
235+
llvm::Constant *CodeGenFunction::createAtExitStub(const VarDecl &VD,
236236
llvm::FunctionCallee dtor,
237237
llvm::Constant *addr) {
238238
// Get the destructor function type, void(*)(void).
@@ -264,7 +264,12 @@ llvm::Function *CodeGenFunction::createAtExitStub(const VarDecl &VD,
264264

265265
CGF.FinishFunction();
266266

267-
return fn;
267+
// Get a proper function pointer.
268+
FunctionProtoType::ExtProtoInfo EPI(getContext().getDefaultCallingConvention(
269+
/*IsVariadic=*/false, /*IsCXXMethod=*/false));
270+
QualType fnType = getContext().getFunctionType(getContext().VoidTy,
271+
{getContext().VoidPtrTy}, EPI);
272+
return CGM.getFunctionPointer(fn, fnType);
268273
}
269274

270275
/// Create a stub function, suitable for being passed to __pt_atexit_np,
@@ -333,7 +338,8 @@ void CodeGenFunction::registerGlobalDtorWithLLVM(const VarDecl &VD,
333338
llvm::FunctionCallee Dtor,
334339
llvm::Constant *Addr) {
335340
// Create a function which calls the destructor.
336-
llvm::Function *dtorStub = createAtExitStub(VD, Dtor, Addr);
341+
llvm::Function *dtorStub =
342+
cast<llvm::Function>(createAtExitStub(VD, Dtor, Addr));
337343
CGM.AddGlobalDtor(dtorStub);
338344
}
339345

clang/lib/CodeGen/CodeGenFunction.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4864,7 +4864,7 @@ class CodeGenFunction : public CodeGenTypeCache {
48644864
void EmitCXXGlobalVarDeclInit(const VarDecl &D, llvm::GlobalVariable *GV,
48654865
bool PerformInit);
48664866

4867-
llvm::Function *createAtExitStub(const VarDecl &VD, llvm::FunctionCallee Dtor,
4867+
llvm::Constant *createAtExitStub(const VarDecl &VD, llvm::FunctionCallee Dtor,
48684868
llvm::Constant *Addr);
48694869

48704870
llvm::Function *createTLSAtExitStub(const VarDecl &VD,

clang/lib/CodeGen/ItaniumCXXABI.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1321,8 +1321,16 @@ void ItaniumCXXABI::emitThrow(CodeGenFunction &CGF, const CXXThrowExpr *E) {
13211321
if (const RecordType *RecordTy = ThrowType->getAs<RecordType>()) {
13221322
CXXRecordDecl *Record = cast<CXXRecordDecl>(RecordTy->getDecl());
13231323
if (!Record->hasTrivialDestructor()) {
1324+
// __cxa_throw is declared to take its destructor as void (*)(void *). We
1325+
// must match that if function pointers can be authenticated with a
1326+
// discriminator based on their type.
1327+
const ASTContext &Ctx = getContext();
1328+
QualType DtorTy = Ctx.getFunctionType(Ctx.VoidTy, {Ctx.VoidPtrTy},
1329+
FunctionProtoType::ExtProtoInfo());
1330+
13241331
CXXDestructorDecl *DtorD = Record->getDestructor();
13251332
Dtor = CGM.getAddrOfCXXStructor(GlobalDecl(DtorD, Dtor_Complete));
1333+
Dtor = CGM.getFunctionPointer(Dtor, DtorTy);
13261334
}
13271335
}
13281336
if (!Dtor) Dtor = llvm::Constant::getNullValue(CGM.Int8PtrTy);
@@ -2699,14 +2707,22 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
26992707
if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit.getCallee()))
27002708
fn->setDoesNotThrow();
27012709

2710+
const auto &Context = CGF.CGM.getContext();
2711+
FunctionProtoType::ExtProtoInfo EPI(Context.getDefaultCallingConvention(
2712+
/*IsVariadic=*/false, /*IsCXXMethod=*/false));
2713+
QualType fnType =
2714+
Context.getFunctionType(Context.VoidTy, {Context.VoidPtrTy}, EPI);
2715+
llvm::Constant *dtorCallee = cast<llvm::Constant>(dtor.getCallee());
2716+
dtorCallee = CGF.CGM.getFunctionPointer(dtorCallee, fnType);
2717+
27022718
if (!addr)
27032719
// addr is null when we are trying to register a dtor annotated with
27042720
// __attribute__((destructor)) in a constructor function. Using null here is
27052721
// okay because this argument is just passed back to the destructor
27062722
// function.
27072723
addr = llvm::Constant::getNullValue(CGF.Int8PtrTy);
27082724

2709-
llvm::Value *args[] = {dtor.getCallee(), addr, handle};
2725+
llvm::Value *args[] = {dtorCallee, addr, handle};
27102726
CGF.EmitNounwindRuntimeCall(atexit, args);
27112727
}
27122728

@@ -4907,7 +4923,8 @@ void XLCXXABI::registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
49074923
}
49084924

49094925
// Create __dtor function for the var decl.
4910-
llvm::Function *DtorStub = CGF.createAtExitStub(D, Dtor, Addr);
4926+
llvm::Function *DtorStub =
4927+
cast<llvm::Function>(CGF.createAtExitStub(D, Dtor, Addr));
49114928

49124929
// Register above __dtor with atexit().
49134930
CGF.registerGlobalDtorWithAtExit(DtorStub);
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - \
2+
// RUN: | FileCheck %s --check-prefix=CXAATEXIT
3+
4+
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -emit-llvm -std=c++11 %s -o - \
5+
// RUN: -fno-use-cxa-atexit \
6+
// RUN: | FileCheck %s --check-prefix=ATEXIT
7+
8+
class Foo {
9+
public:
10+
~Foo() {
11+
}
12+
};
13+
14+
Foo global;
15+
16+
// CXAATEXIT: define internal void @__cxx_global_var_init()
17+
// CXAATEXIT: call i32 @__cxa_atexit(ptr ptrauth (ptr @_ZN3FooD1Ev, i32 0), ptr @global, ptr @__dso_handle)
18+
19+
20+
// ATEXIT: define internal void @__cxx_global_var_init()
21+
// ATEXIT: %{{.*}} = call i32 @atexit(ptr ptrauth (ptr @__dtor_global, i32 0))
22+
23+
// ATEXIT: define internal void @__dtor_global() {{.*}} section "__TEXT,__StaticInit,regular,pure_instructions" {
24+
// ATEXIT: %{{.*}} = call ptr @_ZN3FooD1Ev(ptr @global)
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECK
2+
// RUN: %clang_cc1 -fptrauth-function-pointer-type-discrimination -triple arm64-apple-ios -fptrauth-calls -fcxx-exceptions -emit-llvm %s -o - | FileCheck %s --check-prefix=CHECKDISC
3+
4+
class Foo {
5+
public:
6+
~Foo() {
7+
}
8+
};
9+
10+
// CHECK-LABEL: define void @_Z1fv()
11+
// CHECK: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTI3Foo, ptr ptrauth (ptr @_ZN3FooD1Ev, i32 0))
12+
13+
// CHECKDISC-LABEL: define void @_Z1fv()
14+
// CHECKDISC: call void @__cxa_throw(ptr %{{.*}}, ptr @_ZTI3Foo, ptr ptrauth (ptr @_ZN3FooD1Ev, i32 0, i64 10942))
15+
16+
void f() {
17+
throw Foo();
18+
}
19+
20+
// __cxa_throw is defined to take its destructor as "void (*)(void *)" in the ABI.
21+
// CHECK-LABEL: define void @__cxa_throw({{.*}})
22+
// CHECK: call void {{%.*}}(ptr noundef {{%.*}}) [ "ptrauth"(i32 0, i64 0) ]
23+
24+
// CHECKDISC-LABEL: define void @__cxa_throw({{.*}})
25+
// CHECKDISC: call void {{%.*}}(ptr noundef {{%.*}}) [ "ptrauth"(i32 0, i64 10942) ]
26+
27+
extern "C" void __cxa_throw(void *exception, void *, void (*dtor)(void *)) {
28+
dtor(exception);
29+
}

0 commit comments

Comments
 (0)