1//===--- CGPointerAuth.cpp - IR generation for pointer authentication -----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This file contains common routines relating to the emission of
10// pointer authentication operations.
11//
12//===----------------------------------------------------------------------===//
13
14#include "CGCXXABI.h"
15#include "CodeGenFunction.h"
16#include "CodeGenModule.h"
17#include "clang/CodeGen/CodeGenABITypes.h"
18#include "clang/CodeGen/ConstantInitBuilder.h"
19#include "llvm/Analysis/ValueTracking.h"
20#include "llvm/Support/SipHash.h"
21
22using namespace clang;
23using namespace CodeGen;
24
25/// Given a pointer-authentication schema, return a concrete "other"
26/// discriminator for it.
27llvm::ConstantInt *CodeGenModule::getPointerAuthOtherDiscriminator(
28 const PointerAuthSchema &Schema, GlobalDecl Decl, QualType Type) {
29 switch (Schema.getOtherDiscrimination()) {
30 case PointerAuthSchema::Discrimination::None:
31 return nullptr;
32
33 case PointerAuthSchema::Discrimination::Type:
34 assert(!Type.isNull() && "type not provided for type-discriminated schema");
35 return llvm::ConstantInt::get(
36 Ty: IntPtrTy, V: getContext().getPointerAuthTypeDiscriminator(T: Type));
37
38 case PointerAuthSchema::Discrimination::Decl:
39 assert(Decl.getDecl() &&
40 "declaration not provided for decl-discriminated schema");
41 return llvm::ConstantInt::get(Ty: IntPtrTy,
42 V: getPointerAuthDeclDiscriminator(GD: Decl));
43
44 case PointerAuthSchema::Discrimination::Constant:
45 return llvm::ConstantInt::get(Ty: IntPtrTy, V: Schema.getConstantDiscrimination());
46 }
47 llvm_unreachable("bad discrimination kind");
48}
49
50uint16_t CodeGen::getPointerAuthTypeDiscriminator(CodeGenModule &CGM,
51 QualType FunctionType) {
52 return CGM.getContext().getPointerAuthTypeDiscriminator(T: FunctionType);
53}
54
55uint16_t CodeGen::getPointerAuthDeclDiscriminator(CodeGenModule &CGM,
56 GlobalDecl Declaration) {
57 return CGM.getPointerAuthDeclDiscriminator(GD: Declaration);
58}
59
60/// Return the "other" decl-specific discriminator for the given decl.
61uint16_t
62CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl Declaration) {
63 uint16_t &EntityHash = PtrAuthDiscriminatorHashes[Declaration];
64
65 if (EntityHash == 0) {
66 const auto *ND = cast<NamedDecl>(Val: Declaration.getDecl());
67 if (ND->hasAttr<AsmLabelAttr>() &&
68 ND->getAttr<AsmLabelAttr>()->getLabel().starts_with(
69 Prefix: LLDBManglingABI::FunctionLabelPrefix)) {
70 // If the declaration comes from LLDB, the asm label has a prefix that
71 // would producing a different discriminator. Compute the real C++ mangled
72 // name instead so the discriminator matches what the original translation
73 // unit used.
74 SmallString<256> Buffer;
75 llvm::raw_svector_ostream Out(Buffer);
76 getCXXABI().getMangleContext().mangleCXXName(GD: Declaration, Out);
77 EntityHash = llvm::getPointerAuthStableSipHash(S: Out.str());
78 } else {
79 StringRef Name = getMangledName(GD: Declaration);
80 EntityHash = llvm::getPointerAuthStableSipHash(S: Name);
81 }
82 }
83
84 return EntityHash;
85}
86
87/// Return the abstract pointer authentication schema for a pointer to the given
88/// function type.
89CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) {
90 const auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers;
91 if (!Schema)
92 return CGPointerAuthInfo();
93
94 assert(!Schema.isAddressDiscriminated() &&
95 "function pointers cannot use address-specific discrimination");
96
97 llvm::Constant *Discriminator = nullptr;
98 if (T->isFunctionPointerType() || T->isFunctionReferenceType())
99 T = T->getPointeeType();
100 if (T->isFunctionType())
101 Discriminator = getPointerAuthOtherDiscriminator(Schema, Decl: GlobalDecl(), Type: T);
102
103 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
104 /*IsaPointer=*/false, /*AuthenticatesNull=*/false,
105 Discriminator);
106}
107
108llvm::Value *
109CodeGenFunction::EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress,
110 llvm::Value *Discriminator) {
111 StorageAddress = Builder.CreatePtrToInt(V: StorageAddress, DestTy: IntPtrTy);
112 auto Intrinsic = CGM.getIntrinsic(IID: llvm::Intrinsic::ptrauth_blend);
113 return Builder.CreateCall(Callee: Intrinsic, Args: {StorageAddress, Discriminator});
114}
115
116/// Emit the concrete pointer authentication informaton for the
117/// given authentication schema.
118CGPointerAuthInfo CodeGenFunction::EmitPointerAuthInfo(
119 const PointerAuthSchema &Schema, llvm::Value *StorageAddress,
120 GlobalDecl SchemaDecl, QualType SchemaType) {
121 if (!Schema)
122 return CGPointerAuthInfo();
123
124 llvm::Value *Discriminator =
125 CGM.getPointerAuthOtherDiscriminator(Schema, Decl: SchemaDecl, Type: SchemaType);
126
127 if (Schema.isAddressDiscriminated()) {
128 assert(StorageAddress &&
129 "address not provided for address-discriminated schema");
130
131 if (Discriminator)
132 Discriminator =
133 EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);
134 else
135 Discriminator = Builder.CreatePtrToInt(V: StorageAddress, DestTy: IntPtrTy);
136 }
137
138 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
139 Schema.isIsaPointer(),
140 Schema.authenticatesNullValues(), Discriminator);
141}
142
143CGPointerAuthInfo
144CodeGenFunction::EmitPointerAuthInfo(PointerAuthQualifier Qual,
145 Address StorageAddress) {
146 assert(Qual && "don't call this if you don't know that the Qual is present");
147 if (Qual.hasKeyNone())
148 return CGPointerAuthInfo();
149
150 llvm::Value *Discriminator = nullptr;
151 if (unsigned Extra = Qual.getExtraDiscriminator())
152 Discriminator = llvm::ConstantInt::get(Ty: IntPtrTy, V: Extra);
153
154 if (Qual.isAddressDiscriminated()) {
155 assert(StorageAddress.isValid() &&
156 "address discrimination without address");
157 llvm::Value *StoragePtr = StorageAddress.emitRawPointer(CGF&: *this);
158 if (Discriminator)
159 Discriminator =
160 EmitPointerAuthBlendDiscriminator(StorageAddress: StoragePtr, Discriminator);
161 else
162 Discriminator = Builder.CreatePtrToInt(V: StoragePtr, DestTy: IntPtrTy);
163 }
164
165 return CGPointerAuthInfo(Qual.getKey(), Qual.getAuthenticationMode(),
166 Qual.isIsaPointer(), Qual.authenticatesNullValues(),
167 Discriminator);
168}
169
170/// Return the natural pointer authentication for values of the given
171/// pointee type.
172static CGPointerAuthInfo
173getPointerAuthInfoForPointeeType(CodeGenModule &CGM, QualType PointeeType) {
174 if (PointeeType.isNull())
175 return CGPointerAuthInfo();
176
177 // Function pointers use the function-pointer schema by default.
178 if (PointeeType->isFunctionType())
179 return CGM.getFunctionPointerAuthInfo(T: PointeeType);
180
181 // Normal data pointers never use direct pointer authentication by default.
182 return CGPointerAuthInfo();
183}
184
185CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) {
186 return ::getPointerAuthInfoForPointeeType(CGM&: *this, PointeeType: T);
187}
188
189/// Return the natural pointer authentication for values of the given
190/// pointer type.
191static CGPointerAuthInfo getPointerAuthInfoForType(CodeGenModule &CGM,
192 QualType PointerType) {
193 assert(PointerType->isSignableType(CGM.getContext()));
194
195 // Block pointers are currently not signed.
196 if (PointerType->isBlockPointerType())
197 return CGPointerAuthInfo();
198
199 auto PointeeType = PointerType->getPointeeType();
200
201 if (PointeeType.isNull())
202 return CGPointerAuthInfo();
203
204 return ::getPointerAuthInfoForPointeeType(CGM, PointeeType);
205}
206
207CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) {
208 return ::getPointerAuthInfoForType(CGM&: *this, PointerType: T);
209}
210
211static std::pair<llvm::Value *, CGPointerAuthInfo>
212emitLoadOfOrigPointerRValue(CodeGenFunction &CGF, const LValue &LV,
213 SourceLocation Loc) {
214 llvm::Value *Value = CGF.EmitLoadOfScalar(lvalue: LV, Loc);
215 CGPointerAuthInfo AuthInfo;
216 if (PointerAuthQualifier PtrAuth = LV.getQuals().getPointerAuth())
217 AuthInfo = CGF.EmitPointerAuthInfo(Qual: PtrAuth, StorageAddress: LV.getAddress());
218 else
219 AuthInfo = getPointerAuthInfoForType(CGM&: CGF.CGM, PointerType: LV.getType());
220 return {Value, AuthInfo};
221}
222
223/// Retrieve a pointer rvalue and its ptrauth info. When possible, avoid
224/// needlessly resigning the pointer.
225std::pair<llvm::Value *, CGPointerAuthInfo>
226CodeGenFunction::EmitOrigPointerRValue(const Expr *E) {
227 assert(E->getType()->isSignableType(getContext()));
228
229 E = E->IgnoreParens();
230 if (const auto *Load = dyn_cast<ImplicitCastExpr>(Val: E)) {
231 if (Load->getCastKind() == CK_LValueToRValue) {
232 E = Load->getSubExpr()->IgnoreParens();
233
234 // We're semantically required to not emit loads of certain DREs naively.
235 if (const auto *RefExpr = dyn_cast<DeclRefExpr>(Val: E)) {
236 if (ConstantEmission Result = tryEmitAsConstant(RefExpr)) {
237 // Fold away a use of an intermediate variable.
238 if (!Result.isReference())
239 return {Result.getValue(),
240 getPointerAuthInfoForType(CGM, PointerType: RefExpr->getType())};
241
242 // Fold away a use of an intermediate reference.
243 LValue LV = Result.getReferenceLValue(CGF&: *this, RefExpr);
244 return emitLoadOfOrigPointerRValue(CGF&: *this, LV, Loc: RefExpr->getLocation());
245 }
246 }
247
248 // Otherwise, load and use the pointer
249 LValue LV = EmitCheckedLValue(E, TCK: CodeGenFunction::TCK_Load);
250 return emitLoadOfOrigPointerRValue(CGF&: *this, LV, Loc: E->getExprLoc());
251 }
252 }
253
254 // Fallback: just use the normal rules for the type.
255 llvm::Value *Value = EmitScalarExpr(E);
256 return {Value, getPointerAuthInfoForType(CGM, PointerType: E->getType())};
257}
258
259llvm::Value *
260CodeGenFunction::EmitPointerAuthQualify(PointerAuthQualifier DestQualifier,
261 const Expr *E,
262 Address DestStorageAddress) {
263 assert(DestQualifier);
264 auto [Value, CurAuthInfo] = EmitOrigPointerRValue(E);
265
266 CGPointerAuthInfo DestAuthInfo =
267 EmitPointerAuthInfo(Qual: DestQualifier, StorageAddress: DestStorageAddress);
268 return emitPointerAuthResign(Pointer: Value, PointerType: E->getType(), CurAuthInfo, NewAuthInfo: DestAuthInfo,
269 IsKnownNonNull: isPointerKnownNonNull(E));
270}
271
272llvm::Value *CodeGenFunction::EmitPointerAuthQualify(
273 PointerAuthQualifier DestQualifier, llvm::Value *Value,
274 QualType PointerType, Address DestStorageAddress, bool IsKnownNonNull) {
275 assert(DestQualifier);
276
277 CGPointerAuthInfo CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType);
278 CGPointerAuthInfo DestAuthInfo =
279 EmitPointerAuthInfo(Qual: DestQualifier, StorageAddress: DestStorageAddress);
280 return emitPointerAuthResign(Pointer: Value, PointerType, CurAuthInfo, NewAuthInfo: DestAuthInfo,
281 IsKnownNonNull);
282}
283
284llvm::Value *CodeGenFunction::EmitPointerAuthUnqualify(
285 PointerAuthQualifier CurQualifier, llvm::Value *Value, QualType PointerType,
286 Address CurStorageAddress, bool IsKnownNonNull) {
287 assert(CurQualifier);
288
289 CGPointerAuthInfo CurAuthInfo =
290 EmitPointerAuthInfo(Qual: CurQualifier, StorageAddress: CurStorageAddress);
291 CGPointerAuthInfo DestAuthInfo = getPointerAuthInfoForType(CGM, PointerType);
292 return emitPointerAuthResign(Pointer: Value, PointerType, CurAuthInfo, NewAuthInfo: DestAuthInfo,
293 IsKnownNonNull);
294}
295
296static bool isZeroConstant(const llvm::Value *Value) {
297 if (const auto *CI = dyn_cast<llvm::ConstantInt>(Val: Value))
298 return CI->isZero();
299 return false;
300}
301
302static bool equalAuthPolicies(const CGPointerAuthInfo &Left,
303 const CGPointerAuthInfo &Right) {
304 assert((Left.isSigned() || Right.isSigned()) &&
305 "shouldn't be called if neither is signed");
306 if (Left.isSigned() != Right.isSigned())
307 return false;
308 return Left.getKey() == Right.getKey() &&
309 Left.getAuthenticationMode() == Right.getAuthenticationMode() &&
310 Left.isIsaPointer() == Right.isIsaPointer() &&
311 Left.authenticatesNullValues() == Right.authenticatesNullValues() &&
312 Left.getDiscriminator() == Right.getDiscriminator();
313}
314
315// Return the discriminator or return zero if the discriminator is null.
316static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info,
317 CGBuilderTy &Builder) {
318 llvm::Value *Discriminator = Info.getDiscriminator();
319 return Discriminator ? Discriminator : Builder.getSize(N: 0);
320}
321
322llvm::Value *
323CodeGenFunction::emitPointerAuthResignCall(llvm::Value *Value,
324 const CGPointerAuthInfo &CurAuth,
325 const CGPointerAuthInfo &NewAuth) {
326 assert(CurAuth && NewAuth);
327
328 if (CurAuth.getAuthenticationMode() !=
329 PointerAuthenticationMode::SignAndAuth ||
330 NewAuth.getAuthenticationMode() !=
331 PointerAuthenticationMode::SignAndAuth) {
332 llvm::Value *AuthedValue = EmitPointerAuthAuth(Info: CurAuth, Pointer: Value);
333 return EmitPointerAuthSign(Info: NewAuth, Pointer: AuthedValue);
334 }
335 // Convert the pointer to intptr_t before signing it.
336 auto *OrigType = Value->getType();
337 Value = Builder.CreatePtrToInt(V: Value, DestTy: IntPtrTy);
338
339 auto *CurKey = Builder.getInt32(C: CurAuth.getKey());
340 auto *NewKey = Builder.getInt32(C: NewAuth.getKey());
341
342 llvm::Value *CurDiscriminator = getDiscriminatorOrZero(Info: CurAuth, Builder);
343 llvm::Value *NewDiscriminator = getDiscriminatorOrZero(Info: NewAuth, Builder);
344
345 // call i64 @llvm.ptrauth.resign(i64 %pointer,
346 // i32 %curKey, i64 %curDiscriminator,
347 // i32 %newKey, i64 %newDiscriminator)
348 auto *Intrinsic = CGM.getIntrinsic(IID: llvm::Intrinsic::ptrauth_resign);
349 Value = EmitRuntimeCall(
350 callee: Intrinsic, args: {Value, CurKey, CurDiscriminator, NewKey, NewDiscriminator});
351
352 // Convert back to the original type.
353 Value = Builder.CreateIntToPtr(V: Value, DestTy: OrigType);
354 return Value;
355}
356
357llvm::Value *CodeGenFunction::emitPointerAuthResign(
358 llvm::Value *Value, QualType Type, const CGPointerAuthInfo &CurAuthInfo,
359 const CGPointerAuthInfo &NewAuthInfo, bool IsKnownNonNull) {
360 // Fast path: if neither schema wants a signature, we're done.
361 if (!CurAuthInfo && !NewAuthInfo)
362 return Value;
363
364 llvm::Value *Null = nullptr;
365 // If the value is obviously null, we're done.
366 if (auto *PointerValue = dyn_cast<llvm::PointerType>(Val: Value->getType())) {
367 Null = CGM.getNullPointer(T: PointerValue, QT: Type);
368 } else {
369 assert(Value->getType()->isIntegerTy());
370 Null = llvm::ConstantInt::get(Ty: IntPtrTy, V: 0);
371 }
372 if (Value == Null)
373 return Value;
374
375 // If both schemas sign the same way, we're done.
376 if (equalAuthPolicies(Left: CurAuthInfo, Right: NewAuthInfo)) {
377 const llvm::Value *CurD = CurAuthInfo.getDiscriminator();
378 const llvm::Value *NewD = NewAuthInfo.getDiscriminator();
379 if (CurD == NewD)
380 return Value;
381
382 if ((CurD == nullptr && isZeroConstant(Value: NewD)) ||
383 (NewD == nullptr && isZeroConstant(Value: CurD)))
384 return Value;
385 }
386
387 llvm::BasicBlock *InitBB = Builder.GetInsertBlock();
388 llvm::BasicBlock *ResignBB = nullptr, *ContBB = nullptr;
389
390 // Null pointers have to be mapped to null, and the ptrauth_resign
391 // intrinsic doesn't do that.
392 if (!IsKnownNonNull && !llvm::isKnownNonZero(V: Value, Q: CGM.getDataLayout())) {
393 ContBB = createBasicBlock(name: "resign.cont");
394 ResignBB = createBasicBlock(name: "resign.nonnull");
395
396 auto *IsNonNull = Builder.CreateICmpNE(LHS: Value, RHS: Null);
397 Builder.CreateCondBr(Cond: IsNonNull, True: ResignBB, False: ContBB);
398 EmitBlock(BB: ResignBB);
399 }
400
401 // Perform the auth/sign/resign operation.
402 if (!NewAuthInfo)
403 Value = EmitPointerAuthAuth(Info: CurAuthInfo, Pointer: Value);
404 else if (!CurAuthInfo)
405 Value = EmitPointerAuthSign(Info: NewAuthInfo, Pointer: Value);
406 else
407 Value = emitPointerAuthResignCall(Value, CurAuth: CurAuthInfo, NewAuth: NewAuthInfo);
408
409 // Clean up with a phi if we branched before.
410 if (ContBB) {
411 EmitBlock(BB: ContBB);
412 auto *Phi = Builder.CreatePHI(Ty: Value->getType(), NumReservedValues: 2);
413 Phi->addIncoming(V: Null, BB: InitBB);
414 Phi->addIncoming(V: Value, BB: ResignBB);
415 Value = Phi;
416 }
417
418 return Value;
419}
420
421void CodeGenFunction::EmitPointerAuthCopy(PointerAuthQualifier Qual, QualType T,
422 Address DestAddress,
423 Address SrcAddress) {
424 assert(Qual);
425 llvm::Value *Value = Builder.CreateLoad(Addr: SrcAddress);
426
427 // If we're using address-discrimination, we have to re-sign the value.
428 if (Qual.isAddressDiscriminated()) {
429 CGPointerAuthInfo SrcPtrAuth = EmitPointerAuthInfo(Qual, StorageAddress: SrcAddress);
430 CGPointerAuthInfo DestPtrAuth = EmitPointerAuthInfo(Qual, StorageAddress: DestAddress);
431 Value = emitPointerAuthResign(Value, Type: T, CurAuthInfo: SrcPtrAuth, NewAuthInfo: DestPtrAuth,
432 /*IsKnownNonNull=*/false);
433 }
434
435 Builder.CreateStore(Val: Value, Addr: DestAddress);
436}
437
438llvm::Constant *
439CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
440 llvm::Constant *StorageAddress,
441 llvm::ConstantInt *OtherDiscriminator) {
442 llvm::Constant *AddressDiscriminator;
443 if (StorageAddress) {
444 assert(StorageAddress->getType() == DefaultPtrTy);
445 AddressDiscriminator = StorageAddress;
446 } else {
447 AddressDiscriminator = llvm::Constant::getNullValue(Ty: DefaultPtrTy);
448 }
449
450 llvm::ConstantInt *IntegerDiscriminator;
451 if (OtherDiscriminator) {
452 assert(OtherDiscriminator->getType() == Int64Ty);
453 IntegerDiscriminator = OtherDiscriminator;
454 } else {
455 IntegerDiscriminator = llvm::ConstantInt::get(Ty: Int64Ty, V: 0);
456 }
457
458 return llvm::ConstantPtrAuth::get(
459 Ptr: Pointer, Key: llvm::ConstantInt::get(Ty: Int32Ty, V: Key), Disc: IntegerDiscriminator,
460 AddrDisc: AddressDiscriminator,
461 /*DeactivationSymbol=*/llvm::Constant::getNullValue(Ty: DefaultPtrTy));
462}
463
464/// Does a given PointerAuthScheme require us to sign a value
465bool CodeGenModule::shouldSignPointer(const PointerAuthSchema &Schema) {
466 auto AuthenticationMode = Schema.getAuthenticationMode();
467 return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||
468 AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
469}
470
471/// Sign a constant pointer using the given scheme, producing a constant
472/// with the same IR type.
473llvm::Constant *CodeGenModule::getConstantSignedPointer(
474 llvm::Constant *Pointer, const PointerAuthSchema &Schema,
475 llvm::Constant *StorageAddress, GlobalDecl SchemaDecl,
476 QualType SchemaType) {
477 assert(shouldSignPointer(Schema));
478 llvm::ConstantInt *OtherDiscriminator =
479 getPointerAuthOtherDiscriminator(Schema, Decl: SchemaDecl, Type: SchemaType);
480
481 return getConstantSignedPointer(Pointer, Key: Schema.getKey(), StorageAddress,
482 OtherDiscriminator);
483}
484
485llvm::Constant *
486CodeGen::getConstantSignedPointer(CodeGenModule &CGM, llvm::Constant *Pointer,
487 unsigned Key, llvm::Constant *StorageAddress,
488 llvm::ConstantInt *OtherDiscriminator) {
489 return CGM.getConstantSignedPointer(Pointer, Key, StorageAddress,
490 OtherDiscriminator);
491}
492
493/// If applicable, sign a given constant function pointer with the ABI rules for
494/// functionType.
495llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
496 QualType FunctionType) {
497 assert(FunctionType->isFunctionType() ||
498 FunctionType->isFunctionReferenceType() ||
499 FunctionType->isFunctionPointerType());
500
501 if (auto PointerAuth = getFunctionPointerAuthInfo(T: FunctionType))
502 return getConstantSignedPointer(
503 Pointer, Key: PointerAuth.getKey(), /*StorageAddress=*/nullptr,
504 OtherDiscriminator: cast_or_null<llvm::ConstantInt>(Val: PointerAuth.getDiscriminator()));
505
506 return Pointer;
507}
508
509llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
510 llvm::Type *Ty) {
511 const auto *FD = cast<FunctionDecl>(Val: GD.getDecl());
512 QualType FuncType = FD->getType();
513
514 // Annoyingly, K&R functions have prototypes in the clang AST, but
515 // expressions referring to them are unprototyped.
516 if (!FD->hasPrototype())
517 if (const auto *Proto = FuncType->getAs<FunctionProtoType>())
518 FuncType = Context.getFunctionNoProtoType(ResultTy: Proto->getReturnType(),
519 Info: Proto->getExtInfo());
520
521 return getFunctionPointer(Pointer: getRawFunctionPointer(GD, Ty), FunctionType: FuncType);
522}
523
524CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) {
525 assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected");
526 const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
527 if (!Schema)
528 return CGPointerAuthInfo();
529
530 assert(!Schema.isAddressDiscriminated() &&
531 "function pointers cannot use address-specific discrimination");
532
533 llvm::ConstantInt *Discriminator =
534 getPointerAuthOtherDiscriminator(Schema, Decl: GlobalDecl(), Type: FT);
535 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
536 /* IsIsaPointer */ false,
537 /* AuthenticatesNullValues */ false, Discriminator);
538}
539
540llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer,
541 QualType FT) {
542 if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT))
543 return getConstantSignedPointer(
544 Pointer, Key: PointerAuth.getKey(), StorageAddress: nullptr,
545 OtherDiscriminator: cast_or_null<llvm::ConstantInt>(Val: PointerAuth.getDiscriminator()));
546
547 if (const auto *MFT = dyn_cast<MemberPointerType>(Val: FT.getTypePtr())) {
548 if (MFT->hasPointeeToCFIUncheckedCalleeFunctionType())
549 Pointer = llvm::NoCFIValue::get(GV: cast<llvm::GlobalValue>(Val: Pointer));
550 }
551
552 return Pointer;
553}
554
555llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,
556 llvm::Type *Ty) {
557 QualType FT = FD->getType();
558 FT = getContext().getMemberPointerType(T: FT, /*Qualifier=*/std::nullopt,
559 Cls: cast<CXXMethodDecl>(Val: FD)->getParent());
560 return getMemberFunctionPointer(Pointer: getRawFunctionPointer(GD: FD, Ty), FT);
561}
562
563std::optional<PointerAuthQualifier>
564CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {
565 auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;
566 if (!DefaultAuthentication)
567 return std::nullopt;
568 const CXXRecordDecl *PrimaryBase =
569 Context.baseForVTableAuthentication(ThisClass);
570
571 unsigned Key = DefaultAuthentication.getKey();
572 bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated();
573 auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination();
574 unsigned TypeBasedDiscriminator =
575 Context.getPointerAuthVTablePointerDiscriminator(RD: PrimaryBase);
576 unsigned Discriminator;
577 if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) {
578 Discriminator = TypeBasedDiscriminator;
579 } else if (DefaultDiscrimination ==
580 PointerAuthSchema::Discrimination::Constant) {
581 Discriminator = DefaultAuthentication.getConstantDiscrimination();
582 } else {
583 assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None);
584 Discriminator = 0;
585 }
586 if (auto ExplicitAuthentication =
587 PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) {
588 auto ExplicitAddressDiscrimination =
589 ExplicitAuthentication->getAddressDiscrimination();
590 auto ExplicitDiscriminator =
591 ExplicitAuthentication->getExtraDiscrimination();
592
593 unsigned ExplicitKey = ExplicitAuthentication->getKey();
594 if (ExplicitKey == VTablePointerAuthenticationAttr::NoKey)
595 return std::nullopt;
596
597 if (ExplicitKey != VTablePointerAuthenticationAttr::DefaultKey) {
598 if (ExplicitKey == VTablePointerAuthenticationAttr::ProcessIndependent)
599 Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDA;
600 else {
601 assert(ExplicitKey ==
602 VTablePointerAuthenticationAttr::ProcessDependent);
603 Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDB;
604 }
605 }
606
607 if (ExplicitAddressDiscrimination !=
608 VTablePointerAuthenticationAttr::DefaultAddressDiscrimination)
609 AddressDiscriminated =
610 ExplicitAddressDiscrimination ==
611 VTablePointerAuthenticationAttr::AddressDiscrimination;
612
613 if (ExplicitDiscriminator ==
614 VTablePointerAuthenticationAttr::TypeDiscrimination)
615 Discriminator = TypeBasedDiscriminator;
616 else if (ExplicitDiscriminator ==
617 VTablePointerAuthenticationAttr::CustomDiscrimination)
618 Discriminator = ExplicitAuthentication->getCustomDiscriminationValue();
619 else if (ExplicitDiscriminator ==
620 VTablePointerAuthenticationAttr::NoExtraDiscrimination)
621 Discriminator = 0;
622 }
623 return PointerAuthQualifier::Create(Key, IsAddressDiscriminated: AddressDiscriminated, ExtraDiscriminator: Discriminator,
624 AuthenticationMode: PointerAuthenticationMode::SignAndAuth,
625 /* IsIsaPointer */ false,
626 /* AuthenticatesNullValues */ false);
627}
628
629std::optional<PointerAuthQualifier>
630CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) {
631 if (!Record->getDefinition() || !Record->isPolymorphic())
632 return std::nullopt;
633
634 auto Existing = VTablePtrAuthInfos.find(Val: Record);
635 std::optional<PointerAuthQualifier> Authentication;
636 if (Existing != VTablePtrAuthInfos.end()) {
637 Authentication = Existing->getSecond();
638 } else {
639 Authentication = computeVTPointerAuthentication(ThisClass: Record);
640 VTablePtrAuthInfos.insert(KV: std::make_pair(x&: Record, y&: Authentication));
641 }
642 return Authentication;
643}
644
645std::optional<CGPointerAuthInfo>
646CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF,
647 const CXXRecordDecl *Record,
648 llvm::Value *StorageAddress) {
649 auto Authentication = getVTablePointerAuthentication(Record);
650 if (!Authentication)
651 return std::nullopt;
652
653 llvm::Value *Discriminator = nullptr;
654 if (auto ExtraDiscriminator = Authentication->getExtraDiscriminator())
655 Discriminator = llvm::ConstantInt::get(Ty: IntPtrTy, V: ExtraDiscriminator);
656
657 if (Authentication->isAddressDiscriminated()) {
658 assert(StorageAddress &&
659 "address not provided for address-discriminated schema");
660 if (Discriminator)
661 Discriminator =
662 CGF->EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);
663 else
664 Discriminator = CGF->Builder.CreatePtrToInt(V: StorageAddress, DestTy: IntPtrTy);
665 }
666
667 return CGPointerAuthInfo(Authentication->getKey(),
668 PointerAuthenticationMode::SignAndAuth,
669 /* IsIsaPointer */ false,
670 /* AuthenticatesNullValues */ false, Discriminator);
671}
672
673llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr,
674 QualType SourceType,
675 QualType DestType) {
676 CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
677 if (SourceType->isSignableType(Ctx: getContext()))
678 CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType: SourceType);
679
680 if (DestType->isSignableType(Ctx: getContext()))
681 NewAuthInfo = getPointerAuthInfoForType(CGM, PointerType: DestType);
682
683 if (!CurAuthInfo && !NewAuthInfo)
684 return ResultPtr;
685
686 // If only one side of the cast is a function pointer, then we still need to
687 // resign to handle casts to/from opaque pointers.
688 if (!CurAuthInfo && DestType->isFunctionPointerType())
689 CurAuthInfo = CGM.getFunctionPointerAuthInfo(T: SourceType);
690
691 if (!NewAuthInfo && SourceType->isFunctionPointerType())
692 NewAuthInfo = CGM.getFunctionPointerAuthInfo(T: DestType);
693
694 return emitPointerAuthResign(Value: ResultPtr, Type: DestType, CurAuthInfo, NewAuthInfo,
695 /*IsKnownNonNull=*/false);
696}
697
698Address CodeGenFunction::authPointerToPointerCast(Address Ptr,
699 QualType SourceType,
700 QualType DestType) {
701 CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
702 if (SourceType->isSignableType(Ctx: getContext()))
703 CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType: SourceType);
704
705 if (DestType->isSignableType(Ctx: getContext()))
706 NewAuthInfo = getPointerAuthInfoForType(CGM, PointerType: DestType);
707
708 if (!CurAuthInfo && !NewAuthInfo)
709 return Ptr;
710
711 if (!CurAuthInfo && DestType->isFunctionPointerType()) {
712 // When casting a non-signed pointer to a function pointer, just set the
713 // auth info on Ptr to the assumed schema. The pointer will be resigned to
714 // the effective type when used.
715 Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(T: SourceType));
716 return Ptr;
717 }
718
719 if (!NewAuthInfo && SourceType->isFunctionPointerType()) {
720 NewAuthInfo = CGM.getFunctionPointerAuthInfo(T: DestType);
721 Ptr = Ptr.getResignedAddress(NewInfo: NewAuthInfo, CGF&: *this);
722 Ptr.setPointerAuthInfo(CGPointerAuthInfo());
723 return Ptr;
724 }
725
726 return Ptr;
727}
728
729Address CodeGenFunction::getAsNaturalAddressOf(Address Addr,
730 QualType PointeeTy) {
731 CGPointerAuthInfo Info =
732 PointeeTy.isNull() ? CGPointerAuthInfo()
733 : CGM.getPointerAuthInfoForPointeeType(T: PointeeTy);
734 return Addr.getResignedAddress(NewInfo: Info, CGF&: *this);
735}
736
737Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo,
738 CodeGenFunction &CGF) const {
739 assert(isValid() && "pointer isn't valid");
740 CGPointerAuthInfo CurInfo = getPointerAuthInfo();
741 llvm::Value *Val;
742
743 // Nothing to do if neither the current or the new ptrauth info needs signing.
744 if (!CurInfo.isSigned() && !NewInfo.isSigned())
745 return Address(getBasePointer(), getElementType(), getAlignment(),
746 isKnownNonNull());
747
748 assert(ElementType && "Effective type has to be set");
749 assert(!Offset && "unexpected non-null offset");
750
751 // If the current and the new ptrauth infos are the same and the offset is
752 // null, just cast the base pointer to the effective type.
753 if (CurInfo == NewInfo && !hasOffset())
754 Val = getBasePointer();
755 else
756 Val = CGF.emitPointerAuthResign(Value: getBasePointer(), Type: QualType(), CurAuthInfo: CurInfo,
757 NewAuthInfo: NewInfo, IsKnownNonNull: isKnownNonNull());
758
759 return Address(Val, getElementType(), getAlignment(), NewInfo,
760 /*Offset=*/nullptr, isKnownNonNull());
761}
762
763llvm::Value *Address::emitRawPointerSlow(CodeGenFunction &CGF) const {
764 return CGF.getAsNaturalPointerTo(Addr: *this, PointeeType: QualType());
765}
766
767llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const {
768 assert(isSimple());
769 return emitResignedPointer(PointeeTy: getType(), CGF);
770}
771
772llvm::Value *LValue::emitResignedPointer(QualType PointeeTy,
773 CodeGenFunction &CGF) const {
774 assert(isSimple());
775 return CGF.getAsNaturalAddressOf(Addr: Addr, PointeeTy).getBasePointer();
776}
777
778llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const {
779 assert(isSimple());
780 return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr;
781}
782