https://github.com/ahatanak created 
https://github.com/llvm/llvm-project/pull/191091

154d2267b897 added support for emitting ObjC number, array, and dictionary 
literals as constants, but did not sign the class pointer fields in 
NSConstantIntegerNumber, NSConstantFloatNumber, NSConstantDoubleNumber, 
NSConstantArray, and NSConstantDictionary structs with the ObjCIsaPointers 
ptrauth schema on arm64e. Fix this by using addSignedPointer instead of add 
when emitting those fields.

Also improves and adds comments to the GenerateConstantNS* functions in 
CGObjCMac.cpp.

rdar://174359070

>From 432c8c57a5ed4f06c97b18e1627b3991cf436d34 Mon Sep 17 00:00:00 2001
From: Akira Hatanaka <[email protected]>
Date: Wed, 8 Apr 2026 16:28:46 -0700
Subject: [PATCH] [ObjC] Fix missing ptrauth signing of isa in constant ObjC
 literals

154d2267b897 added support for emitting ObjC number, array, and
dictionary literals as constants, but did not sign the class pointer
fields in NSConstantIntegerNumber, NSConstantFloatNumber,
NSConstantDoubleNumber, NSConstantArray, and NSConstantDictionary
structs with the ObjCIsaPointers ptrauth schema on arm64e. Fix this
by using addSignedPointer instead of add when emitting those fields.

Also improves and adds comments to the GenerateConstantNS* functions in
CGObjCMac.cpp.

rdar://174359070
---
 clang/lib/CodeGen/CGObjCMac.cpp               | 62 ++++++++++++-------
 .../objc2-constant-literals-ptrauth.m         | 32 ++++++++++
 2 files changed, 71 insertions(+), 23 deletions(-)
 create mode 100644 clang/test/CodeGenObjC/objc2-constant-literals-ptrauth.m

diff --git a/clang/lib/CodeGen/CGObjCMac.cpp b/clang/lib/CodeGen/CGObjCMac.cpp
index eeb61a6b12eb1..2a822a4132726 100644
--- a/clang/lib/CodeGen/CGObjCMac.cpp
+++ b/clang/lib/CodeGen/CGObjCMac.cpp
@@ -2285,7 +2285,7 @@ CGObjCCommonMac::GenerateConstantNSString(const 
StringLiteral *Literal) {
   // String length.
   Fields.addInt(CGM.IntTy, StringLength);
 
-  // The struct.
+  // The struct
   CharUnits Alignment = CGM.getPointerAlign();
   GV = Fields.finishAndCreateGlobal("_unnamed_nsstring_", Alignment,
                                     /*constant*/ true,
@@ -2302,7 +2302,7 @@ CGObjCCommonMac::GenerateConstantNSString(const 
StringLiteral *Literal) {
   return ConstantAddress(GV, GV->getValueType(), Alignment);
 }
 
-/// Emit the boolean singletons for BOOL literals @YES @NO
+/// Emit the boolean singletons for BOOL literals @YES and @NO.
 ConstantAddress CGObjCCommonMac::GenerateConstantNSNumber(const bool Value,
                                                           const QualType &Ty) {
   llvm::GlobalVariable *Val =
@@ -2310,7 +2310,8 @@ ConstantAddress 
CGObjCCommonMac::GenerateConstantNSNumber(const bool Value,
   return ConstantAddress(Val, Val->getValueType(), CGM.getPointerAlign());
 }
 
-/// Generate a constant NSConstantIntegerNumber from an ObjC integer literal
+/// Generate a constant NSConstantIntegerNumber from an ObjC integer literal 
e.x
+/// @2.
 /*
   struct __builtin_NSConstantIntegerNumber {
     struct._class_t *isa; // point to _NSConstantIntegerNumberClassReference
@@ -2323,14 +2324,14 @@ CGObjCCommonMac::GenerateConstantNSNumber(const 
llvm::APSInt &Value,
                                           const QualType &Ty) {
   CharUnits Alignment = CGM.getPointerAlign();
 
-  // check if we've already emitted, if so emit a reference to it
+  // Check if we've already emitted, if so emit a reference to it.
   llvm::GlobalVariable *&Entry =
       NSConstantNumberMap[{CGM.getContext().getCanonicalType(Ty), Value}];
   if (Entry) {
     return ConstantAddress(Entry, Entry->getValueType(), Alignment);
   }
 
-  // The encoding type
+  // The encoding type.
   std::string ObjCEncodingType;
   CodeGenFunction(CGM).getContext().getObjCEncodingForType(Ty,
                                                            ObjCEncodingType);
@@ -2351,9 +2352,11 @@ CGObjCCommonMac::GenerateConstantNSNumber(const 
llvm::APSInt &Value,
   auto Fields = Builder.beginStruct(NSConstantIntegerNumberType);
 
   // Class pointer.
-  Fields.add(Class);
+  Fields.addSignedPointer(Class,
+                          CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
+                          GlobalDecl(), QualType());
 
-  // add the @encode
+  // add the @encode.
   Fields.add(CGM.GetAddrOfConstantCString(ObjCEncodingType).getPointer());
 
   // add the value stored.
@@ -2376,14 +2379,16 @@ CGObjCCommonMac::GenerateConstantNSNumber(const 
llvm::APSInt &Value,
 }
 
 /// Generate either a constant NSConstantFloatNumber or NSConstantDoubleNumber
+/// from an ObjC literal based on it's encoding. @(2.2f) would be
+/// NSConstantFloatNumber. @(2.222) would be NSConstantDoubleNumber.
 /*
   struct __builtin_NSConstantFloatNumber {
-    struct._class_t *isa;
+    struct._class_t *isa; // point to _NSConstantFloatNumberClassReference
     float const _value;
   };
 
   struct __builtin_NSConstantDoubleNumber {
-    struct._class_t *isa;
+    struct._class_t *isa; // point to _NSConstantDoubleNumberClassReference
     double const _value;
   };
 */
@@ -2392,14 +2397,14 @@ CGObjCCommonMac::GenerateConstantNSNumber(const 
llvm::APFloat &Value,
                                           const QualType &Ty) {
   CharUnits Alignment = CGM.getPointerAlign();
 
-  // check if we've already emitted, if so emit a reference to it
+  // Check if we've already emitted, if so emit a reference to it.
   llvm::GlobalVariable *&Entry =
       NSConstantNumberMap[{CGM.getContext().getCanonicalType(Ty), Value}];
   if (Entry) {
     return ConstantAddress(Entry, Entry->getValueType(), Alignment);
   }
 
-  // @encode type used to pick which class type to use
+  // @encode type used to pick which class type to use.
   std::string ObjCEncodingType;
   CodeGenFunction(CGM).getContext().getObjCEncodingForType(Ty,
                                                            ObjCEncodingType);
@@ -2410,7 +2415,7 @@ CGObjCCommonMac::GenerateConstantNSNumber(const 
llvm::APFloat &Value,
   llvm::GlobalValue::LinkageTypes Linkage =
       llvm::GlobalVariable::PrivateLinkage;
 
-  // Handle floats
+  // Handle floats.
   if (ObjCEncodingType == "f") {
     llvm::Constant *const Class = getNSConstantFloatNumberClassRef();
 
@@ -2427,7 +2432,9 @@ CGObjCCommonMac::GenerateConstantNSNumber(const 
llvm::APFloat &Value,
     auto Fields = Builder.beginStruct(NSConstantFloatNumberType);
 
     // Class pointer.
-    Fields.add(Class);
+    Fields.addSignedPointer(Class,
+                            CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
+                            GlobalDecl(), QualType());
 
     // add the value stored.
     llvm::Constant *FV = llvm::ConstantFP::get(CGM.FloatTy, Value);
@@ -2448,7 +2455,7 @@ CGObjCCommonMac::GenerateConstantNSNumber(const 
llvm::APFloat &Value,
 
   llvm::Constant *const Class = getNSConstantDoubleNumberClassRef();
   if (!NSConstantDoubleNumberType) {
-    // NOTE: this will be padded on some 32-bit targets and is expected
+    // NOTE: this will be padded on some 32-bit targets and is expected.
     NSConstantDoubleNumberType = llvm::StructType::create(
         {
             CGM.DefaultPtrTy, // isa
@@ -2461,7 +2468,9 @@ CGObjCCommonMac::GenerateConstantNSNumber(const 
llvm::APFloat &Value,
   auto Fields = Builder.beginStruct(NSConstantDoubleNumberType);
 
   // Class pointer.
-  Fields.add(Class);
+  Fields.addSignedPointer(Class,
+                          CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
+                          GlobalDecl(), QualType());
 
   // add the value stored.
   llvm::Constant *DV = llvm::ConstantFP::get(CGM.DoubleTy, Value);
@@ -2481,7 +2490,7 @@ CGObjCCommonMac::GenerateConstantNSNumber(const 
llvm::APFloat &Value,
 }
 
 /// Shared private method to emit the id array storage for constant NSArray and
-/// NSDictionary literals
+/// NSDictionary literals as they share the same sections and behavior.
 llvm::GlobalVariable *
 CGObjCCommonMac::EmitNSConstantCollectionLiteralArrayStorage(
     const ArrayRef<llvm::Constant *> &Elements) {
@@ -2500,10 +2509,11 @@ 
CGObjCCommonMac::EmitNSConstantCollectionLiteralArrayStorage(
   return ObjectsGV;
 }
 
-/// Generate a constant NSConstantArray from an ObjC array literal
+/// Generate a constant NSConstantArray from an ObjC array literal,
+/// e.x @[ @2 ] or the singleton for an empty `__NSArray0__struct`.
 /*
   struct __builtin_NSArray {
-    struct._class_t *isa;
+    struct._class_t *isa; // points to _NSConstantArrayClassReference
     NSUInteger const _count;
     id const *const _objects;
   };
@@ -2537,7 +2547,9 @@ ConstantAddress CGObjCCommonMac::GenerateConstantNSArray(
   auto Fields = Builder.beginStruct(NSConstantArrayType);
 
   // Class pointer.
-  Fields.add(Class);
+  Fields.addSignedPointer(Class,
+                          CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
+                          GlobalDecl(), QualType());
 
   // count
   uint64_t ObjectCount = Objects.size();
@@ -2561,9 +2573,11 @@ ConstantAddress CGObjCCommonMac::GenerateConstantNSArray(
 }
 
 /// Generate a constant NSConstantDictionary from an ObjC dictionary literal
+/// with string keys, e.x @{ @"someNum" : @2 } or the singleton for an empty
+/// `__NSDictionary0__struct`.
 /*
   struct __builtin_NSDictionary {
-    struct._class_t *isa;
+    struct._class_t *isa; // point to _NSConstantDictionaryClassReference
     NSUInteger const _hashOptions;
     NSUInteger const _count;
     id const *const _keys;
@@ -2603,13 +2617,15 @@ ConstantAddress 
CGObjCCommonMac::GenerateConstantNSDictionary(
   auto Fields = Builder.beginStruct(NSConstantDictionaryType);
 
   // Class pointer.
-  Fields.add(Class);
+  Fields.addSignedPointer(Class,
+                          CGM.getCodeGenOpts().PointerAuth.ObjCIsaPointers,
+                          GlobalDecl(), QualType());
 
-  // Use the hashing helper to manage the keys and sorting
+  // Use the hashing helper to manage the keys and sorting.
   auto HashOpts(NSDictionaryBuilder::Options::Sorted);
   NSDictionaryBuilder DictBuilder(E, KeysAndObjects, HashOpts);
 
-  // Ask `HashBuilder` for the fully sorted keys / values and the count
+  // Ask `HashBuilder` for the fully sorted keys / values and the count.
   uint64_t const NumElements = DictBuilder.getNumElements();
 
   llvm::Constant *OptionsConstant = llvm::ConstantInt::get(
diff --git a/clang/test/CodeGenObjC/objc2-constant-literals-ptrauth.m 
b/clang/test/CodeGenObjC/objc2-constant-literals-ptrauth.m
new file mode 100644
index 0000000000000..b62416a4e1112
--- /dev/null
+++ b/clang/test/CodeGenObjC/objc2-constant-literals-ptrauth.m
@@ -0,0 +1,32 @@
+// RUN: %clang_cc1 -triple arm64e-apple-macosx26.0.0 
-fobjc-runtime=macosx-26.0.0 -fobjc-constant-literals 
-fconstant-nsnumber-literals -fconstant-nsarray-literals 
-fconstant-nsdictionary-literals -fptrauth-intrinsics -fptrauth-calls 
-fptrauth-objc-isa -I %S/Inputs -emit-llvm -o - %s | FileCheck %s
+// rdar://174359070
+
+#include "constant-literal-support.h"
+
+#if __has_feature(objc_bool)
+#define YES __objc_yes
+#define NO __objc_no
+#else
+#define YES ((BOOL)1)
+#define NO ((BOOL)0)
+#endif
+
+// Check that isa pointers in all ObjC constant literal structs are signed with
+// ptrauth (key 2, discriminator 0x6AE1 = 27361, address-discriminated).
+
+// CHECK: @_unnamed_nsconstantintegernumber_ = private constant 
%struct.__builtin_NSConstantIntegerNumber { ptr ptrauth (ptr 
@"OBJC_CLASS_$_NSConstantIntegerNumber", i32 2, i64 27361, ptr 
@_unnamed_nsconstantintegernumber_), ptr @.str, i64 42 }
+// CHECK: @_unnamed_nsconstantfloatnumber_ = private constant 
%struct.__builtin_NSConstantFloatNumber { ptr ptrauth (ptr 
@"OBJC_CLASS_$_NSConstantFloatNumber", i32 2, i64 27361, ptr 
@_unnamed_nsconstantfloatnumber_)
+// CHECK: @_unnamed_nsconstantdoublenumber_ = private constant 
%struct.__builtin_NSConstantDoubleNumber { ptr ptrauth (ptr 
@"OBJC_CLASS_$_NSConstantDoubleNumber", i32 2, i64 27361, ptr 
@_unnamed_nsconstantdoublenumber_)
+// CHECK: @_unnamed_cfstring_ = private global %struct.__NSConstantString_tag 
{ ptr ptrauth (ptr @__CFConstantStringClassReference, i32 2, i64 27361, ptr 
@_unnamed_cfstring_)
+// CHECK: @_unnamed_nsarray_ = private constant %struct.__builtin_NSArray { 
ptr ptrauth (ptr @"OBJC_CLASS_$_NSConstantArray", i32 2, i64 27361, ptr 
@_unnamed_nsarray_)
+// CHECK: @_unnamed_nsdictionary_ = private constant 
%struct.__builtin_NSDictionary { ptr ptrauth (ptr 
@"OBJC_CLASS_$_NSConstantDictionary", i32 2, i64 27361, ptr 
@_unnamed_nsdictionary_)
+
+int main() {
+  NSNumber *n = @42;
+  NSNumber *f = @3.14f;
+  NSNumber *d = @3.14;
+  NSNumber *b = @YES;
+  NSArray *a = @[ @"foo" ];
+  NSDictionary *dict = @{ @"a" : @1, @"b" : @2 };
+  return 0;
+}

_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to