@@ -420,6 +420,222 @@ void CodeGenFunction::EmitPointerAuthCopy(PointerAuthQualifier Qual, QualType T,
420420 Builder.CreateStore (Value, DestAddress);
421421}
422422
423+ static const ConstantArrayType *tryGetTypeAsConstantArrayType (QualType T) {
424+ if (!T->isConstantArrayType ())
425+ return nullptr ;
426+ return cast<ConstantArrayType>(T->castAsArrayTypeUnsafe ());
427+ }
428+
429+ using FixupErrorTy = std::pair<const CXXRecordDecl *, CXXBaseSpecifier>;
430+ class CodeGenFunction ::FixupFinder {
431+ public:
432+ using FixupVectorTy = CodeGenFunction::FixupVectorTy;
433+ static FixupVectorTy findFixups (CodeGenFunction &CGF, QualType T) {
434+ FixupFinder Finder (CGF);
435+ FixupVectorTy Result;
436+ Finder.findFixups (Result, T, CharUnits::Zero ());
437+ std::sort (Result.begin (), Result.end (),
438+ [](const auto &L, const auto &R) { return L.Offset < R.Offset ; });
439+ return Result;
440+ }
441+
442+ private:
443+ explicit FixupFinder (CodeGenFunction &CGF)
444+ : CGF(CGF), Context(CGF.getContext()) {}
445+
446+ void findVTablePointerFixups (FixupVectorTy &Output, CXXRecordDecl *RD,
447+ CharUnits Offset) {
448+ CodeGenFunction::VPtrsVector VPtrs = CGF.getVTablePointers (RD);
449+ for (auto VPtr : VPtrs) {
450+ std::optional<PointerAuthQualifier> PointerAuth =
451+ CGF.CGM .getVTablePointerAuthentication (VPtr.Base .getBase ());
452+ if (PointerAuth && PointerAuth->isAddressDiscriminated ())
453+ Output.push_back (
454+ {Offset + VPtr.Base .getBaseOffset (), KnownNonNull, *PointerAuth});
455+ }
456+ }
457+ void findObjectFixups (FixupVectorTy &Output, CXXRecordDecl *RD,
458+ CharUnits Offset) {
459+ if (RD->isPolymorphic ())
460+ findVTablePointerFixups (Output, RD, Offset);
461+ findFixups (Output, RD, Offset, /* SubobjectIsBase=*/ true );
462+ }
463+
464+ void findFixups (FixupVectorTy &Output, CXXRecordDecl *RD,
465+ CharUnits SubobjectOffset, bool SubobjectIsBase) {
466+ // If we've found a union it by definition cannot contain
467+ // address discriminated fields.
468+ if (RD->isUnion ())
469+ return ;
470+ const ASTRecordLayout &Layout = Context.getASTRecordLayout (RD);
471+ if (Layout.hasOwnVFPtr () && RD == Layout.getPrimaryBase ())
472+ findVTablePointerFixups (Output, RD, SubobjectOffset);
473+
474+ for (auto Base : RD->bases ()) {
475+ CXXRecordDecl *BaseDecl =
476+ Base.getType ()->getAsCXXRecordDecl ()->getDefinition ();
477+ assert (!Base.isVirtual ());
478+ CharUnits BaseOffset = Layout.getBaseClassOffset (BaseDecl);
479+ findFixups (Output, BaseDecl, SubobjectOffset + BaseOffset,
480+ /* SubobjectIsBase=*/ true );
481+ }
482+
483+ for (const FieldDecl *Field : RD->fields ()) {
484+ if (Field->isBitField ())
485+ continue ;
486+ unsigned FieldBitOffset = Layout.getFieldOffset (Field->getFieldIndex ());
487+ CharUnits FieldOffset = Context.toCharUnitsFromBits (FieldBitOffset);
488+ findFixups (Output, Field->getType (), SubobjectOffset + FieldOffset);
489+ }
490+ }
491+ void findFixups (FixupVectorTy &Output, QualType T, CharUnits Offset) {
492+ T = T.getCanonicalType ();
493+ if (!Context.containsAddressDiscriminatedPointerAuth (T))
494+ return ;
495+
496+ if (const ConstantArrayType *CAT = tryGetTypeAsConstantArrayType (T)) {
497+ if (CAT->getSize () == 0 )
498+ return ;
499+ Output.push_back ({Offset, CAT});
500+ return ;
501+ }
502+
503+ if (PointerAuthQualifier Q = T.getPointerAuth ();
504+ Q && Q.isAddressDiscriminated ()) {
505+ // FIXME: Would it be reasonable to consider nullability?
506+ Output.push_back ({Offset, NotKnownNonNull, Q});
507+ return ;
508+ }
509+
510+ CXXRecordDecl *RD = T->getAsCXXRecordDecl ();
511+ if (!RD)
512+ return ;
513+ findObjectFixups (Output, RD, Offset);
514+ }
515+ CodeGenFunction &CGF;
516+ ASTContext &Context;
517+ };
518+
519+ void CodeGenFunction::EmitSingleObjectPointerAuthRelocationFixup (
520+ const FixupVectorTy &Fixups, QualType ElementType, Address Dst,
521+ Address Src) {
522+ auto GetFixupAddress = [&](Address BaseAddress, CharUnits Offset,
523+ KnownNonNull_t IsKnownNonNull,
524+ const char *Reason) {
525+ llvm::Value *BasePtr = BaseAddress.emitRawPointer (*this );
526+ llvm::Value *OffsetValue =
527+ llvm::ConstantInt::get (PtrDiffTy, Offset.getQuantity ());
528+ llvm::Value *FixupAddress =
529+ Builder.CreateInBoundsGEP (Int8Ty, BasePtr, OffsetValue, Reason);
530+ return Address (FixupAddress, VoidPtrPtrTy,
531+ BaseAddress.getAlignment ().alignmentAtOffset (Offset),
532+ IsKnownNonNull);
533+ };
534+ for (auto &Fixup : Fixups) {
535+ if (const ConstantArrayType *CAT = Fixup.getAsConstantArrayType ()) {
536+ llvm::Value *CountValue = llvm::ConstantInt::get (SizeTy, 1 );
537+ EmitArrayPointerAuthRelocationFixup (QualType (CAT, 0 ), Dst, Src,
538+ CountValue);
539+ continue ;
540+ }
541+ auto [IsKnownNonNull, Qualifier] = Fixup.getValueFixup ();
542+
543+ // We don't use the existing copy helpers as we'll be resigning a
544+ // value in place assuming the old address for the read.
545+ Address FixupDst = GetFixupAddress (Dst, Fixup.Offset , IsKnownNonNull,
546+ " fixup.dst.with.offset" );
547+ CGPointerAuthInfo DstPtrAuth = EmitPointerAuthInfo (Qualifier, FixupDst);
548+
549+ Address FixupSrc = GetFixupAddress (Src, Fixup.Offset , IsKnownNonNull,
550+ " fixup.src.with.offset" );
551+ CGPointerAuthInfo SrcPtrAuth = EmitPointerAuthInfo (Qualifier, FixupSrc);
552+
553+ // We're loading from the destination here as we've already performed the
554+ // copy from src to dst, and as relocation has memmove semantics, the src
555+ // address may have been overwritten.
556+ llvm::Value *Value = Builder.CreateLoad (FixupDst);
557+ Value = emitPointerAuthResign (Value, QualType (), SrcPtrAuth, DstPtrAuth,
558+ IsKnownNonNull);
559+ Builder.CreateStore (Value, FixupDst);
560+ }
561+ }
562+
563+ llvm::Instruction *CodeGenFunction::EmitArrayPointerAuthRelocationFixup (
564+ QualType ElementType, Address Dst, Address Src, llvm::Value *Count) {
565+ // Preemptively flatten array types so we don't end up with multiple levels
566+ // of loops unnecessarily
567+ if (const ConstantArrayType *CAT =
568+ tryGetTypeAsConstantArrayType (ElementType)) {
569+ uint64_t ElementCount = getContext ().getConstantArrayElementCount (CAT);
570+ llvm::Value *ElementCountValue =
571+ llvm::ConstantInt::get (SizeTy, ElementCount);
572+ Count = Builder.CreateMul (Count, ElementCountValue);
573+ ElementType = getContext ().getBaseElementType (QualType (CAT, 0 ));
574+ }
575+
576+ FixupVectorTy *Fixups;
577+ if (const auto Existing = FixupLists.find (ElementType);
578+ Existing != FixupLists.end ())
579+ Fixups = Existing->second .get ();
580+ else {
581+ auto FoundFixups = FixupFinder::findFixups (*this , ElementType);
582+ auto [EntryPoint, Inserted] = FixupLists.try_emplace (
583+ ElementType, std::make_unique<FixupVectorTy>(std::move (FoundFixups)));
584+ (void )Inserted;
585+ Fixups = EntryPoint->second .get ();
586+ }
587+
588+ CharUnits ElementSize = getContext ().getTypeSizeInChars (ElementType);
589+ CharUnits ElementAlign =
590+ Src.getAlignment ().alignmentOfArrayElement (ElementSize);
591+ llvm::Type *LLVMElemType = ConvertTypeForMem (ElementType);
592+
593+ llvm::BasicBlock *RelocationFixupEntry = Builder.GetInsertBlock ();
594+ llvm::BasicBlock *RelocationFixupBody =
595+ createBasicBlock (" relocation_ptrauth_fixup.body" );
596+ EmitBlock (RelocationFixupBody);
597+ llvm::Value *Zero = llvm::ConstantInt::get (SizeTy, 0 );
598+ llvm::PHINode *Index =
599+ Builder.CreatePHI (SizeTy, 2 , " relocation_ptrauth_fixup.index" );
600+ Index->addIncoming (Zero, RelocationFixupEntry);
601+ llvm::Value *DstElement =
602+ Builder.CreateInBoundsGEP (LLVMElemType, Dst.emitRawPointer (*this ), Index,
603+ " relocation_ptrauth_fixup.dstobject" );
604+ Address DstElementAddress = Address (DstElement, LLVMElemType, ElementAlign);
605+ llvm::Value *SrcElement =
606+ Builder.CreateInBoundsGEP (LLVMElemType, Src.emitRawPointer (*this ), Index,
607+ " relocation_ptrauth_fixup.srcobject" );
608+ Address SrcElementAddress = Address (SrcElement, LLVMElemType, ElementAlign);
609+
610+ // Do the fixup
611+ EmitSingleObjectPointerAuthRelocationFixup (
612+ *Fixups, ElementType, DstElementAddress, SrcElementAddress);
613+
614+ llvm::Value *NextIndex =
615+ Builder.CreateNUWAdd (Index, llvm::ConstantInt::get (Index->getType (), 1 ),
616+ " relocation_ptrauth_fixup.next_index" );
617+ Index->addIncoming (NextIndex, Builder.GetInsertBlock ());
618+ llvm::Value *IsComplete = Builder.CreateICmpEQ (
619+ NextIndex, Count, " relocation_ptrauth_fixup.is_complete" );
620+ llvm::BasicBlock *RelocationFixupFinished =
621+ createBasicBlock (" relocation_ptrauth_fixup.end" );
622+ Builder.CreateCondBr (IsComplete, RelocationFixupFinished,
623+ RelocationFixupBody);
624+ EmitBlock (RelocationFixupFinished);
625+ return RelocationFixupFinished->getTerminator ();
626+ }
627+
628+ llvm::Instruction *CodeGenFunction::EmitPointerAuthRelocationFixup (
629+ QualType ElementType, Address Dst, Address Src, llvm::Value *Count) {
630+ size_t ElementSize =
631+ getContext ().getTypeSizeInChars (ElementType).getQuantity ();
632+ llvm::Value *ElementSizeValue =
633+ llvm::ConstantInt::get (Count->getType (), ElementSize);
634+ llvm::Value *Size = Builder.CreateMul (Count, ElementSizeValue);
635+ Builder.CreateMemMove (Dst, Src, Size, false );
636+ return EmitArrayPointerAuthRelocationFixup (ElementType, Dst, Src, Count);
637+ }
638+
423639llvm::Constant *
424640CodeGenModule::getConstantSignedPointer (llvm::Constant *Pointer, unsigned Key,
425641 llvm::Constant *StorageAddress,
0 commit comments