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 "CodeGenFunction.h"
15#include "CodeGenModule.h"
16#include "clang/CodeGen/CodeGenABITypes.h"
17#include "clang/CodeGen/ConstantInitBuilder.h"
18#include "llvm/Analysis/ValueTracking.h"
19#include "llvm/Support/SipHash.h"
20
21using namespace clang;
22using namespace CodeGen;
23
24/// Given a pointer-authentication schema, return a concrete "other"
25/// discriminator for it.
26llvm::ConstantInt *CodeGenModule::getPointerAuthOtherDiscriminator(
27 const PointerAuthSchema &Schema, GlobalDecl Decl, QualType Type) {
28 switch (Schema.getOtherDiscrimination()) {
29 case PointerAuthSchema::Discrimination::None:
30 return nullptr;
31
32 case PointerAuthSchema::Discrimination::Type:
33 assert(!Type.isNull() && "type not provided for type-discriminated schema");
34 return llvm::ConstantInt::get(
35 Ty: IntPtrTy, V: getContext().getPointerAuthTypeDiscriminator(T: Type));
36
37 case PointerAuthSchema::Discrimination::Decl:
38 assert(Decl.getDecl() &&
39 "declaration not provided for decl-discriminated schema");
40 return llvm::ConstantInt::get(Ty: IntPtrTy,
41 V: getPointerAuthDeclDiscriminator(GD: Decl));
42
43 case PointerAuthSchema::Discrimination::Constant:
44 return llvm::ConstantInt::get(Ty: IntPtrTy, V: Schema.getConstantDiscrimination());
45 }
46 llvm_unreachable("bad discrimination kind");
47}
48
49uint16_t CodeGen::getPointerAuthTypeDiscriminator(CodeGenModule &CGM,
50 QualType FunctionType) {
51 return CGM.getContext().getPointerAuthTypeDiscriminator(T: FunctionType);
52}
53
54uint16_t CodeGen::getPointerAuthDeclDiscriminator(CodeGenModule &CGM,
55 GlobalDecl Declaration) {
56 return CGM.getPointerAuthDeclDiscriminator(GD: Declaration);
57}
58
59/// Return the "other" decl-specific discriminator for the given decl.
60uint16_t
61CodeGenModule::getPointerAuthDeclDiscriminator(GlobalDecl Declaration) {
62 uint16_t &EntityHash = PtrAuthDiscriminatorHashes[Declaration];
63
64 if (EntityHash == 0) {
65 StringRef Name = getMangledName(GD: Declaration);
66 EntityHash = llvm::getPointerAuthStableSipHash(S: Name);
67 }
68
69 return EntityHash;
70}
71
72/// Return the abstract pointer authentication schema for a pointer to the given
73/// function type.
74CGPointerAuthInfo CodeGenModule::getFunctionPointerAuthInfo(QualType T) {
75 const auto &Schema = getCodeGenOpts().PointerAuth.FunctionPointers;
76 if (!Schema)
77 return CGPointerAuthInfo();
78
79 assert(!Schema.isAddressDiscriminated() &&
80 "function pointers cannot use address-specific discrimination");
81
82 llvm::Constant *Discriminator = nullptr;
83 if (T->isFunctionPointerType() || T->isFunctionReferenceType())
84 T = T->getPointeeType();
85 if (T->isFunctionType())
86 Discriminator = getPointerAuthOtherDiscriminator(Schema, Decl: GlobalDecl(), Type: T);
87
88 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
89 /*IsaPointer=*/false, /*AuthenticatesNull=*/false,
90 Discriminator);
91}
92
93llvm::Value *
94CodeGenFunction::EmitPointerAuthBlendDiscriminator(llvm::Value *StorageAddress,
95 llvm::Value *Discriminator) {
96 StorageAddress = Builder.CreatePtrToInt(V: StorageAddress, DestTy: IntPtrTy);
97 auto Intrinsic = CGM.getIntrinsic(IID: llvm::Intrinsic::ptrauth_blend);
98 return Builder.CreateCall(Callee: Intrinsic, Args: {StorageAddress, Discriminator});
99}
100
101/// Emit the concrete pointer authentication informaton for the
102/// given authentication schema.
103CGPointerAuthInfo CodeGenFunction::EmitPointerAuthInfo(
104 const PointerAuthSchema &Schema, llvm::Value *StorageAddress,
105 GlobalDecl SchemaDecl, QualType SchemaType) {
106 if (!Schema)
107 return CGPointerAuthInfo();
108
109 llvm::Value *Discriminator =
110 CGM.getPointerAuthOtherDiscriminator(Schema, Decl: SchemaDecl, Type: SchemaType);
111
112 if (Schema.isAddressDiscriminated()) {
113 assert(StorageAddress &&
114 "address not provided for address-discriminated schema");
115
116 if (Discriminator)
117 Discriminator =
118 EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);
119 else
120 Discriminator = Builder.CreatePtrToInt(V: StorageAddress, DestTy: IntPtrTy);
121 }
122
123 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
124 Schema.isIsaPointer(),
125 Schema.authenticatesNullValues(), Discriminator);
126}
127
128/// Return the natural pointer authentication for values of the given
129/// pointee type.
130static CGPointerAuthInfo
131getPointerAuthInfoForPointeeType(CodeGenModule &CGM, QualType PointeeType) {
132 if (PointeeType.isNull())
133 return CGPointerAuthInfo();
134
135 // Function pointers use the function-pointer schema by default.
136 if (PointeeType->isFunctionType())
137 return CGM.getFunctionPointerAuthInfo(T: PointeeType);
138
139 // Normal data pointers never use direct pointer authentication by default.
140 return CGPointerAuthInfo();
141}
142
143CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForPointeeType(QualType T) {
144 return ::getPointerAuthInfoForPointeeType(CGM&: *this, PointeeType: T);
145}
146
147/// Return the natural pointer authentication for values of the given
148/// pointer type.
149static CGPointerAuthInfo getPointerAuthInfoForType(CodeGenModule &CGM,
150 QualType PointerType) {
151 assert(PointerType->isSignableType());
152
153 // Block pointers are currently not signed.
154 if (PointerType->isBlockPointerType())
155 return CGPointerAuthInfo();
156
157 auto PointeeType = PointerType->getPointeeType();
158
159 if (PointeeType.isNull())
160 return CGPointerAuthInfo();
161
162 return ::getPointerAuthInfoForPointeeType(CGM, PointeeType);
163}
164
165CGPointerAuthInfo CodeGenModule::getPointerAuthInfoForType(QualType T) {
166 return ::getPointerAuthInfoForType(CGM&: *this, PointerType: T);
167}
168
169static bool isZeroConstant(const llvm::Value *Value) {
170 if (const auto *CI = dyn_cast<llvm::ConstantInt>(Val: Value))
171 return CI->isZero();
172 return false;
173}
174
175static bool equalAuthPolicies(const CGPointerAuthInfo &Left,
176 const CGPointerAuthInfo &Right) {
177 assert((Left.isSigned() || Right.isSigned()) &&
178 "shouldn't be called if neither is signed");
179 if (Left.isSigned() != Right.isSigned())
180 return false;
181 return Left.getKey() == Right.getKey() &&
182 Left.getAuthenticationMode() == Right.getAuthenticationMode();
183}
184
185// Return the discriminator or return zero if the discriminator is null.
186static llvm::Value *getDiscriminatorOrZero(const CGPointerAuthInfo &Info,
187 CGBuilderTy &Builder) {
188 llvm::Value *Discriminator = Info.getDiscriminator();
189 return Discriminator ? Discriminator : Builder.getSize(N: 0);
190}
191
192llvm::Value *
193CodeGenFunction::emitPointerAuthResignCall(llvm::Value *Value,
194 const CGPointerAuthInfo &CurAuth,
195 const CGPointerAuthInfo &NewAuth) {
196 assert(CurAuth && NewAuth);
197
198 if (CurAuth.getAuthenticationMode() !=
199 PointerAuthenticationMode::SignAndAuth ||
200 NewAuth.getAuthenticationMode() !=
201 PointerAuthenticationMode::SignAndAuth) {
202 llvm::Value *AuthedValue = EmitPointerAuthAuth(Info: CurAuth, Pointer: Value);
203 return EmitPointerAuthSign(Info: NewAuth, Pointer: AuthedValue);
204 }
205 // Convert the pointer to intptr_t before signing it.
206 auto *OrigType = Value->getType();
207 Value = Builder.CreatePtrToInt(V: Value, DestTy: IntPtrTy);
208
209 auto *CurKey = Builder.getInt32(C: CurAuth.getKey());
210 auto *NewKey = Builder.getInt32(C: NewAuth.getKey());
211
212 llvm::Value *CurDiscriminator = getDiscriminatorOrZero(Info: CurAuth, Builder);
213 llvm::Value *NewDiscriminator = getDiscriminatorOrZero(Info: NewAuth, Builder);
214
215 // call i64 @llvm.ptrauth.resign(i64 %pointer,
216 // i32 %curKey, i64 %curDiscriminator,
217 // i32 %newKey, i64 %newDiscriminator)
218 auto *Intrinsic = CGM.getIntrinsic(IID: llvm::Intrinsic::ptrauth_resign);
219 Value = EmitRuntimeCall(
220 callee: Intrinsic, args: {Value, CurKey, CurDiscriminator, NewKey, NewDiscriminator});
221
222 // Convert back to the original type.
223 Value = Builder.CreateIntToPtr(V: Value, DestTy: OrigType);
224 return Value;
225}
226
227llvm::Value *CodeGenFunction::emitPointerAuthResign(
228 llvm::Value *Value, QualType Type, const CGPointerAuthInfo &CurAuthInfo,
229 const CGPointerAuthInfo &NewAuthInfo, bool IsKnownNonNull) {
230 // Fast path: if neither schema wants a signature, we're done.
231 if (!CurAuthInfo && !NewAuthInfo)
232 return Value;
233
234 llvm::Value *Null = nullptr;
235 // If the value is obviously null, we're done.
236 if (auto *PointerValue = dyn_cast<llvm::PointerType>(Val: Value->getType())) {
237 Null = CGM.getNullPointer(T: PointerValue, QT: Type);
238 } else {
239 assert(Value->getType()->isIntegerTy());
240 Null = llvm::ConstantInt::get(Ty: IntPtrTy, V: 0);
241 }
242 if (Value == Null)
243 return Value;
244
245 // If both schemas sign the same way, we're done.
246 if (equalAuthPolicies(Left: CurAuthInfo, Right: NewAuthInfo)) {
247 const llvm::Value *CurD = CurAuthInfo.getDiscriminator();
248 const llvm::Value *NewD = NewAuthInfo.getDiscriminator();
249 if (CurD == NewD)
250 return Value;
251
252 if ((CurD == nullptr && isZeroConstant(Value: NewD)) ||
253 (NewD == nullptr && isZeroConstant(Value: CurD)))
254 return Value;
255 }
256
257 llvm::BasicBlock *InitBB = Builder.GetInsertBlock();
258 llvm::BasicBlock *ResignBB = nullptr, *ContBB = nullptr;
259
260 // Null pointers have to be mapped to null, and the ptrauth_resign
261 // intrinsic doesn't do that.
262 if (!IsKnownNonNull && !llvm::isKnownNonZero(V: Value, Q: CGM.getDataLayout())) {
263 ContBB = createBasicBlock(name: "resign.cont");
264 ResignBB = createBasicBlock(name: "resign.nonnull");
265
266 auto *IsNonNull = Builder.CreateICmpNE(LHS: Value, RHS: Null);
267 Builder.CreateCondBr(Cond: IsNonNull, True: ResignBB, False: ContBB);
268 EmitBlock(BB: ResignBB);
269 }
270
271 // Perform the auth/sign/resign operation.
272 if (!NewAuthInfo)
273 Value = EmitPointerAuthAuth(Info: CurAuthInfo, Pointer: Value);
274 else if (!CurAuthInfo)
275 Value = EmitPointerAuthSign(Info: NewAuthInfo, Pointer: Value);
276 else
277 Value = emitPointerAuthResignCall(Value, CurAuth: CurAuthInfo, NewAuth: NewAuthInfo);
278
279 // Clean up with a phi if we branched before.
280 if (ContBB) {
281 EmitBlock(BB: ContBB);
282 auto *Phi = Builder.CreatePHI(Ty: Value->getType(), NumReservedValues: 2);
283 Phi->addIncoming(V: Null, BB: InitBB);
284 Phi->addIncoming(V: Value, BB: ResignBB);
285 Value = Phi;
286 }
287
288 return Value;
289}
290
291llvm::Constant *
292CodeGenModule::getConstantSignedPointer(llvm::Constant *Pointer, unsigned Key,
293 llvm::Constant *StorageAddress,
294 llvm::ConstantInt *OtherDiscriminator) {
295 llvm::Constant *AddressDiscriminator;
296 if (StorageAddress) {
297 assert(StorageAddress->getType() == UnqualPtrTy);
298 AddressDiscriminator = StorageAddress;
299 } else {
300 AddressDiscriminator = llvm::Constant::getNullValue(Ty: UnqualPtrTy);
301 }
302
303 llvm::ConstantInt *IntegerDiscriminator;
304 if (OtherDiscriminator) {
305 assert(OtherDiscriminator->getType() == Int64Ty);
306 IntegerDiscriminator = OtherDiscriminator;
307 } else {
308 IntegerDiscriminator = llvm::ConstantInt::get(Ty: Int64Ty, V: 0);
309 }
310
311 return llvm::ConstantPtrAuth::get(Ptr: Pointer,
312 Key: llvm::ConstantInt::get(Ty: Int32Ty, V: Key),
313 Disc: IntegerDiscriminator, AddrDisc: AddressDiscriminator);
314}
315
316/// Does a given PointerAuthScheme require us to sign a value
317bool CodeGenModule::shouldSignPointer(const PointerAuthSchema &Schema) {
318 auto AuthenticationMode = Schema.getAuthenticationMode();
319 return AuthenticationMode == PointerAuthenticationMode::SignAndStrip ||
320 AuthenticationMode == PointerAuthenticationMode::SignAndAuth;
321}
322
323/// Sign a constant pointer using the given scheme, producing a constant
324/// with the same IR type.
325llvm::Constant *CodeGenModule::getConstantSignedPointer(
326 llvm::Constant *Pointer, const PointerAuthSchema &Schema,
327 llvm::Constant *StorageAddress, GlobalDecl SchemaDecl,
328 QualType SchemaType) {
329 assert(shouldSignPointer(Schema));
330 llvm::ConstantInt *OtherDiscriminator =
331 getPointerAuthOtherDiscriminator(Schema, Decl: SchemaDecl, Type: SchemaType);
332
333 return getConstantSignedPointer(Pointer, Key: Schema.getKey(), StorageAddress,
334 OtherDiscriminator);
335}
336
337/// If applicable, sign a given constant function pointer with the ABI rules for
338/// functionType.
339llvm::Constant *CodeGenModule::getFunctionPointer(llvm::Constant *Pointer,
340 QualType FunctionType) {
341 assert(FunctionType->isFunctionType() ||
342 FunctionType->isFunctionReferenceType() ||
343 FunctionType->isFunctionPointerType());
344
345 if (auto PointerAuth = getFunctionPointerAuthInfo(T: FunctionType))
346 return getConstantSignedPointer(
347 Pointer, Key: PointerAuth.getKey(), /*StorageAddress=*/nullptr,
348 OtherDiscriminator: cast_or_null<llvm::ConstantInt>(Val: PointerAuth.getDiscriminator()));
349
350 return Pointer;
351}
352
353llvm::Constant *CodeGenModule::getFunctionPointer(GlobalDecl GD,
354 llvm::Type *Ty) {
355 const auto *FD = cast<FunctionDecl>(Val: GD.getDecl());
356 QualType FuncType = FD->getType();
357
358 // Annoyingly, K&R functions have prototypes in the clang AST, but
359 // expressions referring to them are unprototyped.
360 if (!FD->hasPrototype())
361 if (const auto *Proto = FuncType->getAs<FunctionProtoType>())
362 FuncType = Context.getFunctionNoProtoType(ResultTy: Proto->getReturnType(),
363 Info: Proto->getExtInfo());
364
365 return getFunctionPointer(Pointer: getRawFunctionPointer(GD, Ty), FunctionType: FuncType);
366}
367
368CGPointerAuthInfo CodeGenModule::getMemberFunctionPointerAuthInfo(QualType FT) {
369 assert(FT->getAs<MemberPointerType>() && "MemberPointerType expected");
370 const auto &Schema = getCodeGenOpts().PointerAuth.CXXMemberFunctionPointers;
371 if (!Schema)
372 return CGPointerAuthInfo();
373
374 assert(!Schema.isAddressDiscriminated() &&
375 "function pointers cannot use address-specific discrimination");
376
377 llvm::ConstantInt *Discriminator =
378 getPointerAuthOtherDiscriminator(Schema, Decl: GlobalDecl(), Type: FT);
379 return CGPointerAuthInfo(Schema.getKey(), Schema.getAuthenticationMode(),
380 /* IsIsaPointer */ false,
381 /* AuthenticatesNullValues */ false, Discriminator);
382}
383
384llvm::Constant *CodeGenModule::getMemberFunctionPointer(llvm::Constant *Pointer,
385 QualType FT) {
386 if (CGPointerAuthInfo PointerAuth = getMemberFunctionPointerAuthInfo(FT))
387 return getConstantSignedPointer(
388 Pointer, Key: PointerAuth.getKey(), StorageAddress: nullptr,
389 OtherDiscriminator: cast_or_null<llvm::ConstantInt>(Val: PointerAuth.getDiscriminator()));
390
391 return Pointer;
392}
393
394llvm::Constant *CodeGenModule::getMemberFunctionPointer(const FunctionDecl *FD,
395 llvm::Type *Ty) {
396 QualType FT = FD->getType();
397 FT = getContext().getMemberPointerType(
398 T: FT, Cls: cast<CXXMethodDecl>(Val: FD)->getParent()->getTypeForDecl());
399 return getMemberFunctionPointer(Pointer: getRawFunctionPointer(GD: FD, Ty), FT);
400}
401
402std::optional<PointerAuthQualifier>
403CodeGenModule::computeVTPointerAuthentication(const CXXRecordDecl *ThisClass) {
404 auto DefaultAuthentication = getCodeGenOpts().PointerAuth.CXXVTablePointers;
405 if (!DefaultAuthentication)
406 return std::nullopt;
407 const CXXRecordDecl *PrimaryBase =
408 Context.baseForVTableAuthentication(ThisClass);
409
410 unsigned Key = DefaultAuthentication.getKey();
411 bool AddressDiscriminated = DefaultAuthentication.isAddressDiscriminated();
412 auto DefaultDiscrimination = DefaultAuthentication.getOtherDiscrimination();
413 unsigned TypeBasedDiscriminator =
414 Context.getPointerAuthVTablePointerDiscriminator(RD: PrimaryBase);
415 unsigned Discriminator;
416 if (DefaultDiscrimination == PointerAuthSchema::Discrimination::Type) {
417 Discriminator = TypeBasedDiscriminator;
418 } else if (DefaultDiscrimination ==
419 PointerAuthSchema::Discrimination::Constant) {
420 Discriminator = DefaultAuthentication.getConstantDiscrimination();
421 } else {
422 assert(DefaultDiscrimination == PointerAuthSchema::Discrimination::None);
423 Discriminator = 0;
424 }
425 if (auto ExplicitAuthentication =
426 PrimaryBase->getAttr<VTablePointerAuthenticationAttr>()) {
427 auto ExplicitAddressDiscrimination =
428 ExplicitAuthentication->getAddressDiscrimination();
429 auto ExplicitDiscriminator =
430 ExplicitAuthentication->getExtraDiscrimination();
431
432 unsigned ExplicitKey = ExplicitAuthentication->getKey();
433 if (ExplicitKey == VTablePointerAuthenticationAttr::NoKey)
434 return std::nullopt;
435
436 if (ExplicitKey != VTablePointerAuthenticationAttr::DefaultKey) {
437 if (ExplicitKey == VTablePointerAuthenticationAttr::ProcessIndependent)
438 Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDA;
439 else {
440 assert(ExplicitKey ==
441 VTablePointerAuthenticationAttr::ProcessDependent);
442 Key = (unsigned)PointerAuthSchema::ARM8_3Key::ASDB;
443 }
444 }
445
446 if (ExplicitAddressDiscrimination !=
447 VTablePointerAuthenticationAttr::DefaultAddressDiscrimination)
448 AddressDiscriminated =
449 ExplicitAddressDiscrimination ==
450 VTablePointerAuthenticationAttr::AddressDiscrimination;
451
452 if (ExplicitDiscriminator ==
453 VTablePointerAuthenticationAttr::TypeDiscrimination)
454 Discriminator = TypeBasedDiscriminator;
455 else if (ExplicitDiscriminator ==
456 VTablePointerAuthenticationAttr::CustomDiscrimination)
457 Discriminator = ExplicitAuthentication->getCustomDiscriminationValue();
458 else if (ExplicitDiscriminator ==
459 VTablePointerAuthenticationAttr::NoExtraDiscrimination)
460 Discriminator = 0;
461 }
462 return PointerAuthQualifier::Create(Key, IsAddressDiscriminated: AddressDiscriminated, ExtraDiscriminator: Discriminator,
463 AuthenticationMode: PointerAuthenticationMode::SignAndAuth,
464 /* IsIsaPointer */ false,
465 /* AuthenticatesNullValues */ false);
466}
467
468std::optional<PointerAuthQualifier>
469CodeGenModule::getVTablePointerAuthentication(const CXXRecordDecl *Record) {
470 if (!Record->getDefinition() || !Record->isPolymorphic())
471 return std::nullopt;
472
473 auto Existing = VTablePtrAuthInfos.find(Val: Record);
474 std::optional<PointerAuthQualifier> Authentication;
475 if (Existing != VTablePtrAuthInfos.end()) {
476 Authentication = Existing->getSecond();
477 } else {
478 Authentication = computeVTPointerAuthentication(ThisClass: Record);
479 VTablePtrAuthInfos.insert(KV: std::make_pair(x&: Record, y&: Authentication));
480 }
481 return Authentication;
482}
483
484std::optional<CGPointerAuthInfo>
485CodeGenModule::getVTablePointerAuthInfo(CodeGenFunction *CGF,
486 const CXXRecordDecl *Record,
487 llvm::Value *StorageAddress) {
488 auto Authentication = getVTablePointerAuthentication(Record);
489 if (!Authentication)
490 return std::nullopt;
491
492 llvm::Value *Discriminator = nullptr;
493 if (auto ExtraDiscriminator = Authentication->getExtraDiscriminator())
494 Discriminator = llvm::ConstantInt::get(Ty: IntPtrTy, V: ExtraDiscriminator);
495
496 if (Authentication->isAddressDiscriminated()) {
497 assert(StorageAddress &&
498 "address not provided for address-discriminated schema");
499 if (Discriminator)
500 Discriminator =
501 CGF->EmitPointerAuthBlendDiscriminator(StorageAddress, Discriminator);
502 else
503 Discriminator = CGF->Builder.CreatePtrToInt(V: StorageAddress, DestTy: IntPtrTy);
504 }
505
506 return CGPointerAuthInfo(Authentication->getKey(),
507 PointerAuthenticationMode::SignAndAuth,
508 /* IsIsaPointer */ false,
509 /* AuthenticatesNullValues */ false, Discriminator);
510}
511
512llvm::Value *CodeGenFunction::authPointerToPointerCast(llvm::Value *ResultPtr,
513 QualType SourceType,
514 QualType DestType) {
515 CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
516 if (SourceType->isSignableType())
517 CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType: SourceType);
518
519 if (DestType->isSignableType())
520 NewAuthInfo = getPointerAuthInfoForType(CGM, PointerType: DestType);
521
522 if (!CurAuthInfo && !NewAuthInfo)
523 return ResultPtr;
524
525 // If only one side of the cast is a function pointer, then we still need to
526 // resign to handle casts to/from opaque pointers.
527 if (!CurAuthInfo && DestType->isFunctionPointerType())
528 CurAuthInfo = CGM.getFunctionPointerAuthInfo(T: SourceType);
529
530 if (!NewAuthInfo && SourceType->isFunctionPointerType())
531 NewAuthInfo = CGM.getFunctionPointerAuthInfo(T: DestType);
532
533 return emitPointerAuthResign(Value: ResultPtr, Type: DestType, CurAuthInfo, NewAuthInfo,
534 /*IsKnownNonNull=*/false);
535}
536
537Address CodeGenFunction::authPointerToPointerCast(Address Ptr,
538 QualType SourceType,
539 QualType DestType) {
540 CGPointerAuthInfo CurAuthInfo, NewAuthInfo;
541 if (SourceType->isSignableType())
542 CurAuthInfo = getPointerAuthInfoForType(CGM, PointerType: SourceType);
543
544 if (DestType->isSignableType())
545 NewAuthInfo = getPointerAuthInfoForType(CGM, PointerType: DestType);
546
547 if (!CurAuthInfo && !NewAuthInfo)
548 return Ptr;
549
550 if (!CurAuthInfo && DestType->isFunctionPointerType()) {
551 // When casting a non-signed pointer to a function pointer, just set the
552 // auth info on Ptr to the assumed schema. The pointer will be resigned to
553 // the effective type when used.
554 Ptr.setPointerAuthInfo(CGM.getFunctionPointerAuthInfo(T: SourceType));
555 return Ptr;
556 }
557
558 if (!NewAuthInfo && SourceType->isFunctionPointerType()) {
559 NewAuthInfo = CGM.getFunctionPointerAuthInfo(T: DestType);
560 Ptr = Ptr.getResignedAddress(NewInfo: NewAuthInfo, CGF&: *this);
561 Ptr.setPointerAuthInfo(CGPointerAuthInfo());
562 return Ptr;
563 }
564
565 return Ptr;
566}
567
568Address CodeGenFunction::getAsNaturalAddressOf(Address Addr,
569 QualType PointeeTy) {
570 CGPointerAuthInfo Info =
571 PointeeTy.isNull() ? CGPointerAuthInfo()
572 : CGM.getPointerAuthInfoForPointeeType(T: PointeeTy);
573 return Addr.getResignedAddress(NewInfo: Info, CGF&: *this);
574}
575
576Address Address::getResignedAddress(const CGPointerAuthInfo &NewInfo,
577 CodeGenFunction &CGF) const {
578 assert(isValid() && "pointer isn't valid");
579 CGPointerAuthInfo CurInfo = getPointerAuthInfo();
580 llvm::Value *Val;
581
582 // Nothing to do if neither the current or the new ptrauth info needs signing.
583 if (!CurInfo.isSigned() && !NewInfo.isSigned())
584 return Address(getBasePointer(), getElementType(), getAlignment(),
585 isKnownNonNull());
586
587 assert(ElementType && "Effective type has to be set");
588 assert(!Offset && "unexpected non-null offset");
589
590 // If the current and the new ptrauth infos are the same and the offset is
591 // null, just cast the base pointer to the effective type.
592 if (CurInfo == NewInfo && !hasOffset())
593 Val = getBasePointer();
594 else
595 Val = CGF.emitPointerAuthResign(Value: getBasePointer(), Type: QualType(), CurAuthInfo: CurInfo,
596 NewAuthInfo: NewInfo, IsKnownNonNull: isKnownNonNull());
597
598 Val = CGF.Builder.CreateBitCast(V: Val, DestTy: getType());
599 return Address(Val, getElementType(), getAlignment(), NewInfo,
600 /*Offset=*/nullptr, isKnownNonNull());
601}
602
603llvm::Value *Address::emitRawPointerSlow(CodeGenFunction &CGF) const {
604 return CGF.getAsNaturalPointerTo(Addr: *this, PointeeType: QualType());
605}
606
607llvm::Value *LValue::getPointer(CodeGenFunction &CGF) const {
608 assert(isSimple());
609 return emitResignedPointer(PointeeTy: getType(), CGF);
610}
611
612llvm::Value *LValue::emitResignedPointer(QualType PointeeTy,
613 CodeGenFunction &CGF) const {
614 assert(isSimple());
615 return CGF.getAsNaturalAddressOf(Addr: Addr, PointeeTy).getBasePointer();
616}
617
618llvm::Value *LValue::emitRawPointer(CodeGenFunction &CGF) const {
619 assert(isSimple());
620 return Addr.isValid() ? Addr.emitRawPointer(CGF) : nullptr;
621}
622