[llvm-branch-commits] [clang] [Clang] Add pointer field protection feature. (PR #172119)

Peter Collingbourne via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Jan 15 18:58:17 PST 2026


================
@@ -1310,21 +1310,92 @@ static llvm::Value *CoerceIntOrPtrToIntOrPtr(llvm::Value *Val, llvm::Type *Ty,
   return Val;
 }
 
+static std::vector<PFPField> findPFPCoercedFields(CodeGenFunction &CGF,
+                                                  QualType SrcFETy) {
+  // Coercion directly through memory does not work if the structure has pointer
+  // field protection because the struct in registers has a different bit
+  // pattern to the struct in memory, so we must read the elements one by one
+  // and use them to form the coerced structure.
+  std::vector<PFPField> PFPFields;
+  CGF.getContext().findPFPFields(SrcFETy, CharUnits::Zero(), PFPFields,
+                                 /*IncludeVBases=*/true);
+
+  // Because we don't know which union member is selected, we don't modify the
+  // in-memory representation when passing a pointer that is part of a union
+  // field. This requires the union member to be trivially copyable;
+  // non-trivially-copyable unions cannot be directly passed by value.
+  llvm::erase_if(PFPFields, [](PFPField F) { return F.isWithinUnion; });
+  return PFPFields;
+}
+
+static llvm::Value *CreatePFPCoercedLoad(Address Src, QualType SrcFETy,
+                                         llvm::Type *Ty, CodeGenFunction &CGF) {
+  std::vector<PFPField> PFPFields = findPFPCoercedFields(CGF, SrcFETy);
+  if (PFPFields.empty())
+    return nullptr;
+
+  auto LoadCoercedField = [&](CharUnits Offset,
+                              llvm::Type *FieldType) -> llvm::Value * {
+    if (!PFPFields.empty() && PFPFields[0].offset == Offset) {
+      auto fieldAddr = CGF.EmitAddressOfPFPField(Src, PFPFields[0]);
+      llvm::Value *FieldVal = CGF.Builder.CreateLoad(fieldAddr);
+      if (isa<llvm::IntegerType>(FieldType))
+        FieldVal = CGF.Builder.CreatePtrToInt(FieldVal, FieldType);
+      PFPFields.erase(PFPFields.begin());
+      return FieldVal;
+    }
+    auto FieldAddr =
+        CGF.Builder
+            .CreateConstInBoundsByteGEP(Src.withElementType(CGF.Int8Ty), Offset)
+            .withElementType(FieldType);
+    return CGF.Builder.CreateLoad(FieldAddr);
+  };
+  if (isa<llvm::IntegerType>(Ty) || isa<llvm::PointerType>(Ty)) {
+    auto Addr = CGF.EmitAddressOfPFPField(Src, PFPFields[0]);
+    llvm::Value *Val = CGF.Builder.CreateLoad(Addr);
+    if (isa<llvm::IntegerType>(Ty))
+      Val = CGF.Builder.CreatePtrToInt(Val, Ty);
+    return Val;
+  }
+  if (auto *AT = dyn_cast<llvm::ArrayType>(Ty)) {
+    auto *ET = AT->getElementType();
+    CharUnits wordSize = CGF.getContext().toCharUnitsFromBits(
+        CGF.CGM.getDataLayout().getTypeSizeInBits(ET));
+    CharUnits Offset = CharUnits::Zero();
+    llvm::Value *Val = llvm::PoisonValue::get(AT);
+    for (unsigned i = 0; i != AT->getNumElements(); ++i, Offset += wordSize)
+      Val = CGF.Builder.CreateInsertValue(Val, LoadCoercedField(Offset, ET), i);
+    return Val;
+  }
+  auto *ST = cast<llvm::StructType>(Ty);
+  llvm::Value *Val = llvm::PoisonValue::get(ST);
+  auto *SL = CGF.CGM.getDataLayout().getStructLayout(ST);
+  for (unsigned i = 0; i != ST->getNumElements(); ++i) {
----------------
pcc wrote:

Done (for the `ArrayType` case, because `StructType` was deleted)

https://github.com/llvm/llvm-project/pull/172119


More information about the llvm-branch-commits mailing list