Skip to content

Commit 281088e

Browse files
authored
Merge pull request #63204 from meg-gupta/ptrauthcodegenpr
Initial support for ptrauth qualified function pointers in C
2 parents f5c7e4f + 901c279 commit 281088e

23 files changed

+269
-9
lines changed

docs/SIL.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4522,6 +4522,7 @@ begin_access
45224522
sil-enforcement ::= static
45234523
sil-enforcement ::= dynamic
45244524
sil-enforcement ::= unsafe
4525+
sil-enforcement ::= signed
45254526
%1 = begin_access [read] [unknown] %0 : $*T
45264527
// %0 must be of $*T type.
45274528

@@ -4564,6 +4565,9 @@ runtime for the duration of its scope. This access may still conflict with an
45644565
outer access scope; therefore may still require dynamic enforcement at a single
45654566
point.
45664567

4568+
A ``signed`` access is for pointers that are signed in architectures that support
4569+
pointer signing.
4570+
45674571
A ``builtin`` access was emitted for a user-controlled Builtin (e.g. the
45684572
standard library's KeyPath access). Non-builtin accesses are auto-generated by
45694573
the compiler to enforce formal access that derives from the language. A

include/swift/AST/Decl.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5958,6 +5958,8 @@ class VarDecl : public AbstractStorageDecl {
59585958
});
59595959
}
59605960

5961+
clang::PointerAuthQualifier getPointerAuthQualifier() const;
5962+
59615963
// Implement isa/cast/dyncast/etc.
59625964
static bool classof(const Decl *D) {
59635965
return D->getKind() == DeclKind::Var || D->getKind() == DeclKind::Param;

include/swift/AST/SILOptions.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -135,6 +135,10 @@ class SILOptions {
135135
/// temporaries for stack protection.
136136
bool EnableMoveInoutStackProtection = false;
137137

138+
/// Enables codegen support for clang imported ptrauth qualified field
139+
/// function pointers.
140+
bool EnableImportPtrauthFieldFunctionPointers = false;
141+
138142
/// Controls whether or not paranoid verification checks are run.
139143
bool VerifyAll = false;
140144

include/swift/Option/FrontendOptions.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1112,6 +1112,13 @@ def enable_move_inout_stack_protector :
11121112
Flag<["-"], "enable-move-inout-stack-protector">,
11131113
HelpText<"Enable the stack protector by moving values to temporaries">;
11141114

1115+
def enable_import_ptrauth_field_function_pointers :
1116+
Flag<["-"], "enable-import-ptrauth-field-function-pointers">,
1117+
HelpText<"Enable import of custom ptrauth qualified field function pointers">;
1118+
def disable_import_ptrauth_field_function_pointers :
1119+
Flag<["-"], "disable-import-ptrauth-field-function-pointers">,
1120+
HelpText<"Disable import of custom ptrauth qualified field function pointers">;
1121+
11151122
def enable_collocate_metadata_functions :
11161123
Flag<["-"], "enable-collocate-metadata-functions">,
11171124
HelpText<"Enable collocate metadata functions">;

include/swift/SIL/SILInstruction.h

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4446,8 +4446,13 @@ enum class SILAccessEnforcement : uint8_t {
44464446
/// behavior.
44474447
Unsafe,
44484448

4449+
/// Access to pointers that are signed via pointer authentication mechanishm.
4450+
/// Such pointers should be authenticated before read and signed before a
4451+
/// write. Optimizer should avoid promoting such accesses to values.
4452+
Signed,
4453+
44494454
// This enum is encoded.
4450-
Last = Unsafe
4455+
Last = Signed
44514456
};
44524457
StringRef getSILAccessEnforcementName(SILAccessEnforcement enforcement);
44534458

@@ -4520,9 +4525,9 @@ class BeginAccessInst
45204525
: BeginAccessBase(loc, accessKind, enforcement, noNestedConflict,
45214526
fromBuiltin, lvalue, lvalue->getType()) {
45224527

4523-
static_assert(unsigned(SILAccessKind::Last) < (1 << 2),
4528+
static_assert(unsigned(SILAccessKind::Last) < (1 << 3),
45244529
"reserve sufficient bits for serialized SIL");
4525-
static_assert(unsigned(SILAccessEnforcement::Last) < (1 << 2),
4530+
static_assert(unsigned(SILAccessEnforcement::Last) < (1 << 3),
45264531
"reserve sufficient bits for serialized SIL");
45274532

45284533
static_assert(unsigned(SILAccessKind::Last) <

include/swift/SIL/SILNode.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ class alignas(8) SILNode :
122122
enum { NumAssignOwnershipQualifierBits = 2 };
123123
enum { NumAssignByWrapperModeBits = 2 };
124124
enum { NumSILAccessKindBits = 2 };
125-
enum { NumSILAccessEnforcementBits = 2 };
125+
enum { NumSILAccessEnforcementBits = 3 };
126126
enum { NumAllocRefTailTypesBits = 4 };
127127

128128
protected:

lib/AST/TypeWrapper.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,3 +44,12 @@ bool VarDecl::isTypeWrapperLocalStorageForInitializer() const {
4444
}
4545
return false;
4646
}
47+
48+
clang::PointerAuthQualifier VarDecl::getPointerAuthQualifier() const {
49+
if (auto *clangDecl = getClangDecl()) {
50+
if (auto *valueDecl = dyn_cast<clang::ValueDecl>(clangDecl)) {
51+
return valueDecl->getType().getPointerAuth();
52+
}
53+
}
54+
return clang::PointerAuthQualifier();
55+
}

lib/Frontend/CompilerInvocation.cpp

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1826,9 +1826,13 @@ static bool ParseSILArgs(SILOptions &Opts, ArgList &Args,
18261826
Opts.EnableStackProtection =
18271827
Args.hasFlag(OPT_enable_stack_protector, OPT_disable_stack_protector,
18281828
Opts.EnableStackProtection);
1829-
Opts.EnableMoveInoutStackProtection =
1830-
Args.hasFlag(OPT_enable_move_inout_stack_protector, OPT_disable_stack_protector,
1831-
Opts.EnableMoveInoutStackProtection);
1829+
Opts.EnableMoveInoutStackProtection = Args.hasArg(
1830+
OPT_enable_move_inout_stack_protector, OPT_disable_stack_protector,
1831+
Opts.EnableMoveInoutStackProtection);
1832+
Opts.EnableImportPtrauthFieldFunctionPointers =
1833+
Args.hasArg(OPT_enable_import_ptrauth_field_function_pointers,
1834+
OPT_disable_import_ptrauth_field_function_pointers,
1835+
Opts.EnableImportPtrauthFieldFunctionPointers);
18321836
Opts.VerifyAll |= Args.hasArg(OPT_sil_verify_all);
18331837
Opts.VerifyNone |= Args.hasArg(OPT_sil_verify_none);
18341838
Opts.DebugSerialization |= Args.hasArg(OPT_sil_debug_serialization);

lib/IRGen/Callee.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -78,6 +78,9 @@ namespace irgen {
7878
llvm::Value *storageAddress,
7979
const PointerAuthEntity &entity);
8080

81+
static PointerAuthInfo emit(IRGenModule &IGM,
82+
clang::PointerAuthQualifier pointerAuthQual);
83+
8184
static PointerAuthInfo forFunctionPointer(IRGenModule &IGM,
8285
CanSILFunctionType fnType);
8386

lib/IRGen/GenCall.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5036,7 +5036,7 @@ Callee irgen::getCFunctionPointerCallee(IRGenFunction &IGF,
50365036
CalleeInfo &&calleeInfo) {
50375037
auto sig = emitCastOfFunctionPointer(IGF, fnPtr, calleeInfo.OrigFnType);
50385038
auto authInfo =
5039-
PointerAuthInfo::forFunctionPointer(IGF.IGM, calleeInfo.OrigFnType);
5039+
PointerAuthInfo::forFunctionPointer(IGF.IGM, calleeInfo.OrigFnType);
50405040

50415041
auto fn = FunctionPointer::createSigned(FunctionPointer::Kind::Function,
50425042
fnPtr, authInfo, sig);

lib/IRGen/GenPointerAuth.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -238,6 +238,15 @@ PointerAuthInfo PointerAuthInfo::emit(IRGenFunction &IGF,
238238
return PointerAuthInfo(key, discriminator);
239239
}
240240

241+
PointerAuthInfo
242+
PointerAuthInfo::emit(IRGenModule &IGM,
243+
clang::PointerAuthQualifier pointerAuthQual) {
244+
return PointerAuthInfo(
245+
pointerAuthQual.getKey(),
246+
llvm::ConstantInt::get(IGM.Int64Ty,
247+
pointerAuthQual.getExtraDiscriminator()));
248+
}
249+
241250
llvm::ConstantInt *
242251
PointerAuthInfo::getOtherDiscriminator(IRGenModule &IGM,
243252
const PointerAuthSchema &schema,

lib/IRGen/IRGenSIL.cpp

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5794,6 +5794,44 @@ void IRGenSILFunction::visitBeginAccessInst(BeginAccessInst *access) {
57945794
setLoweredDynamicallyEnforcedAddress(access, addr, scratch);
57955795
return;
57965796
}
5797+
case SILAccessEnforcement::Signed: {
5798+
auto &ti = getTypeInfo(access->getType());
5799+
auto *sea = cast<StructElementAddrInst>(access->getOperand());
5800+
auto *Int64PtrTy = llvm::Type::getInt64PtrTy(IGM.getLLVMContext());
5801+
auto *Int64PtrPtrTy = Int64PtrTy->getPointerTo();
5802+
if (access->getAccessKind() == SILAccessKind::Read) {
5803+
// When we see a signed read access, generate code to:
5804+
// authenticate the signed pointer, and store the authenticated value to a
5805+
// shadow stack location. Set the lowered address of the access to this
5806+
// stack location.
5807+
auto pointerAuthQual = sea->getField()->getPointerAuthQualifier();
5808+
auto *pointerToSignedFptr = getLoweredAddress(sea).getAddress();
5809+
auto *pointerToIntPtr =
5810+
Builder.CreateBitCast(pointerToSignedFptr, Int64PtrPtrTy);
5811+
auto *signedFptr = Builder.CreateLoad(pointerToIntPtr, Int64PtrTy,
5812+
IGM.getPointerAlignment());
5813+
auto *resignedFptr = emitPointerAuthResign(
5814+
*this, signedFptr, PointerAuthInfo::emit(IGM, pointerAuthQual),
5815+
PointerAuthInfo::emit(*this,
5816+
IGM.getOptions().PointerAuth.FunctionPointers,
5817+
pointerToSignedFptr, PointerAuthEntity()));
5818+
auto temp = ti.allocateStack(*this, access->getType(), "ptrauth.temp");
5819+
auto *tempAddressToIntPtr =
5820+
Builder.CreateBitCast(temp.getAddressPointer(), Int64PtrPtrTy);
5821+
Builder.CreateStore(resignedFptr, tempAddressToIntPtr,
5822+
IGM.getPointerAlignment());
5823+
setLoweredAddress(access, temp.getAddress());
5824+
return;
5825+
}
5826+
if (access->getAccessKind() == SILAccessKind::Modify) {
5827+
// When we see a signed modify access, create a shadow stack location and
5828+
// set the lowered address of the access to this stack location.
5829+
auto temp = ti.allocateStack(*this, access->getType(), "ptrauth.temp");
5830+
setLoweredAddress(access, temp.getAddress());
5831+
return;
5832+
}
5833+
llvm_unreachable("Incompatible access kind with begin_access [signed]");
5834+
}
57975835
}
57985836
llvm_unreachable("bad access enforcement");
57995837
}
@@ -5812,6 +5850,7 @@ void IRGenSILFunction::visitBeginUnpairedAccessInst(
58125850

58135851
case SILAccessEnforcement::Static:
58145852
case SILAccessEnforcement::Unsafe:
5853+
case SILAccessEnforcement::Signed:
58155854
// nothing to do
58165855
return;
58175856

@@ -5873,6 +5912,39 @@ void IRGenSILFunction::visitEndAccessInst(EndAccessInst *i) {
58735912
Builder.CreateLifetimeEnd(scratch);
58745913
return;
58755914
}
5915+
5916+
case SILAccessEnforcement::Signed: {
5917+
if (access->getAccessKind() != SILAccessKind::Modify) {
5918+
// nothing to do.
5919+
return;
5920+
}
5921+
// When we see a signed modify access, get the lowered address of the
5922+
// access which is the shadow stack slot, sign the value and write back to
5923+
// the struct field.
5924+
auto *Int64PtrTy = llvm::Type::getInt64PtrTy(IGM.getLLVMContext());
5925+
auto *Int64PtrPtrTy = Int64PtrTy->getPointerTo();
5926+
auto pointerAuthQual = cast<StructElementAddrInst>(access->getOperand())
5927+
->getField()
5928+
->getPointerAuthQualifier();
5929+
auto tempAddress = getLoweredAddress(access);
5930+
auto *tempAddressToIntPtr =
5931+
Builder.CreateBitCast(tempAddress.getAddress(), Int64PtrPtrTy);
5932+
auto *tempAddressValue = Builder.CreateLoad(tempAddressToIntPtr, Int64PtrTy,
5933+
IGM.getPointerAlignment());
5934+
auto *signedFptr = emitPointerAuthResign(
5935+
*this, tempAddressValue,
5936+
PointerAuthInfo::emit(*this,
5937+
IGM.getOptions().PointerAuth.FunctionPointers,
5938+
tempAddress.getAddress(), PointerAuthEntity()),
5939+
PointerAuthInfo::emit(IGM, pointerAuthQual));
5940+
5941+
auto *pointerToSignedFptr =
5942+
getLoweredAddress(access->getOperand()).getAddress();
5943+
auto *pointerToIntPtr =
5944+
Builder.CreateBitCast(pointerToSignedFptr, Int64PtrPtrTy);
5945+
Builder.CreateStore(signedFptr, pointerToIntPtr, IGM.getPointerAlignment());
5946+
return;
5947+
}
58765948
}
58775949
llvm_unreachable("bad access enforcement");
58785950
}
@@ -5884,6 +5956,7 @@ void IRGenSILFunction::visitEndUnpairedAccessInst(EndUnpairedAccessInst *i) {
58845956

58855957
case SILAccessEnforcement::Static:
58865958
case SILAccessEnforcement::Unsafe:
5959+
case SILAccessEnforcement::Signed:
58875960
// nothing to do
58885961
return;
58895962

lib/SIL/IR/SILInstructions.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1206,6 +1206,8 @@ StringRef swift::getSILAccessEnforcementName(SILAccessEnforcement enforcement) {
12061206
case SILAccessEnforcement::Static: return "static";
12071207
case SILAccessEnforcement::Dynamic: return "dynamic";
12081208
case SILAccessEnforcement::Unsafe: return "unsafe";
1209+
case SILAccessEnforcement::Signed:
1210+
return "signed";
12091211
}
12101212
llvm_unreachable("bad access enforcement");
12111213
}

lib/SIL/Parser/ParseSIL.cpp

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4455,6 +4455,8 @@ bool SILParser::parseSpecificSILInstruction(SILBuilder &B,
44554455
setEnforcement(SILAccessEnforcement::Dynamic);
44564456
} else if (attr == "unsafe") {
44574457
setEnforcement(SILAccessEnforcement::Unsafe);
4458+
} else if (attr == "signed") {
4459+
setEnforcement(SILAccessEnforcement::Signed);
44584460
} else if (attr == "init") {
44594461
setKind(SILAccessKind::Init);
44604462
} else if (attr == "read") {

lib/SILGen/SILGenLValue.cpp

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -853,8 +853,17 @@ namespace {
853853
// TODO: if the base is +1, break apart its cleanup.
854854
auto Res = SGF.B.createStructElementAddr(loc, base.getValue(),
855855
Field, SubstFieldType);
856-
return ManagedValue::forLValue(Res);
856+
857+
if (!Field->getPointerAuthQualifier() ||
858+
!SGF.getOptions().EnableImportPtrauthFieldFunctionPointers) {
859+
return ManagedValue::forLValue(Res);
860+
}
861+
auto beginAccess =
862+
enterAccessScope(SGF, loc, base, Res, getTypeData(), getAccessKind(),
863+
SILAccessEnforcement::Signed, takeActorIsolation());
864+
return ManagedValue::forLValue(beginAccess);
857865
}
866+
858867
void dump(raw_ostream &OS, unsigned indent) const override {
859868
OS.indent(indent) << "StructElementComponent("
860869
<< Field->getName() << ")\n";

lib/SILOptimizer/Mandatory/AccessMarkerElimination.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@ bool AccessMarkerElimination::shouldPreserveAccess(
7777
switch (enforcement) {
7878
case SILAccessEnforcement::Static:
7979
case SILAccessEnforcement::Unsafe:
80+
case SILAccessEnforcement::Signed:
8081
return false;
8182
case SILAccessEnforcement::Unknown:
8283
case SILAccessEnforcement::Dynamic:

lib/SILOptimizer/Utils/SILInliner.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -770,6 +770,7 @@ static InlineCost getEnforcementCost(SILAccessEnforcement enforcement) {
770770
return InlineCost::Expensive;
771771
case SILAccessEnforcement::Static:
772772
case SILAccessEnforcement::Unsafe:
773+
case SILAccessEnforcement::Signed:
773774
return InlineCost::Free;
774775
}
775776
llvm_unreachable("bad enforcement");

test/IRGen/Inputs/module.modulemap

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,7 @@ module SynthesizedProtocol {
3131
header "synthesized_protocol.h"
3232
export *
3333
}
34+
35+
module PointerAuth {
36+
header "ptrauth_field_fptr_import.h"
37+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifndef TEST_C_FUNCTION
2+
#define TEST_C_FUNCTION
3+
4+
int returnInt() { return 111; }
5+
struct SecureStruct {
6+
int (*__ptrauth(2, 0, 88)(secure_func_ptr))();
7+
};
8+
9+
struct SecureStruct *ptr_to_secure_struct;
10+
#endif
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
// RUN: %swift-frontend %s -enable-import-ptrauth-field-function-pointers -emit-ir -target arm64e-apple-ios13.0 -I %S/Inputs/ -validate-tbd-against-ir=none 2>&1 | %FileCheck %s
2+
// REQUIRES: CPU=arm64e
3+
// REQUIRES: OS=ios
4+
5+
import PointerAuth
6+
7+
// CHECK: define hidden swiftcc i32 @"$s25ptrauth_field_fptr_import05test_B8_fn_reads5Int32VyF"() #0 {
8+
// CHECK: [[LD:%.*]] = load i64, i64* bitcast (%struct.SecureStruct** @ptr_to_secure_struct to i64*), align 8
9+
// CHECK: 5: ; preds = %entry
10+
// CHECK: [[CAST0:%.*]] = inttoptr i64 [[LD]] to i8*
11+
// CHECK: br label %12
12+
// CHECK: 12:
13+
// CHECK: [[SECURESTRUCT:%.*]] = phi i8* [ [[CAST0]], %5 ]
14+
// CHECK: [[CAST1:%.*]] = bitcast i8* [[SECURESTRUCT]] to %TSo12SecureStructV*
15+
// CHECK: %.secure_func_ptr = getelementptr inbounds %TSo12SecureStructV, %TSo12SecureStructV* %14, i32 0, i32 0
16+
// CHECK: [[CAST2:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64*
17+
// CHECK: [[PTR:%.*]] = load i64*, i64** [[CAST2]], align 8
18+
// CHECK: [[SIGNEDINT:%.*]] = ptrtoint i64* [[PTR]] to i64
19+
// CHECK: [[DEFAULTSIGNVAL:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[SIGNEDINT]], i32 2, i64 88, i32 0, i64 0)
20+
// CHECK: [[AUTHPTR:%.*]] = inttoptr i64 [[DEFAULTSIGNVAL]] to i64*
21+
// CHECK: [[TMPCAST1:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64**
22+
// CHECK: store i64* [[AUTHPTR]], i64** [[TMPCAST1]], align 8
23+
// CHECK: [[TMPCAST2:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64*
24+
// CHECK: [[FUNCPTR:%.*]] = load i64, i64* [[TMPCAST2]], align 8
25+
func test_field_fn_read() -> Int32 {
26+
let fn = ptr_to_secure_struct!.pointee.secure_func_ptr!
27+
return fn()
28+
}
29+
30+
// CHECK-LABEL: define hidden swiftcc void @"$s25ptrauth_field_fptr_import05test_B14_fn_ptr_modifyyyF"() #0 {
31+
// CHECK: 11: ; preds = %4
32+
// CHECK: [[SECURESTRUCT:%.*]] = phi i8* [ %5, %4 ]
33+
// CHECK: [[CAST1:%.*]] = bitcast i8* [[SECURESTRUCT]] to %TSo12SecureStructV*
34+
// CHECK: %.secure_func_ptr = getelementptr inbounds %TSo12SecureStructV, %TSo12SecureStructV* [[CAST1]], i32 0, i32 0
35+
// CHECK: [[CAST2:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64*
36+
// CHECK: store i64 ptrtoint ({ i8*, i32, i64, i64 }* @returnInt.ptrauth to i64), i64* [[CAST2]], align 8
37+
// CHECK: [[CAST3:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %ptrauth.temp to i64**
38+
// CHECK: [[LD:%.*]] = load i64*, i64** [[CAST3]], align 8
39+
// CHECK: [[CAST4:%.*]] = ptrtoint i64* [[LD]] to i64
40+
// CHECK: [[SIGN:%.*]] = call i64 @llvm.ptrauth.resign(i64 [[CAST4]], i32 0, i64 0, i32 2, i64 88)
41+
// CHECK: [[CAST5:%.*]] = inttoptr i64 [[SIGN]] to i64*
42+
// CHECK: [[CAST6:%.*]] = bitcast %Ts5Int32VIetCd_Sg* %.secure_func_ptr to i64**
43+
// CHECK: store i64* [[CAST5]], i64** [[CAST6]], align 8
44+
func test_field_fn_ptr_modify() {
45+
ptr_to_secure_struct!.pointee.secure_func_ptr = returnInt
46+
}
47+
48+
print(test_field_fn_read())
49+
print(test_field_fn_ptr_modify())

test/SILGen/Inputs/module.map

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module PointerAuth {
2+
header "ptrauth_field_fptr_import.h"
3+
}
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
#ifndef TEST_C_FUNCTION
2+
#define TEST_C_FUNCTION
3+
4+
struct SecureStruct {
5+
int (*__ptrauth(2, 0, 88)(secure_func_ptr1))();
6+
int (*__ptrauth(3, 0, 66)(secure_func_ptr2))();
7+
};
8+
9+
struct SecureStruct *ptr_to_secure_struct;
10+
#endif

0 commit comments

Comments
 (0)