[clang] [ObjC]: Make type encoding safe in symbol names (PR #77797)

Frederik Carlier via cfe-commits cfe-commits at lists.llvm.org
Thu Jan 11 12:02:44 PST 2024


https://github.com/qmfrederik updated https://github.com/llvm/llvm-project/pull/77797

>From 34933c7dbba8168f9d0e568ef1d5c49ce22511fe Mon Sep 17 00:00:00 2001
From: Frederik Carlier <frederik.carlier at keysight.com>
Date: Wed, 10 Jan 2024 16:51:18 +0000
Subject: [PATCH] [ObjC]: Make type encoding safe in symbol names

Type encodings are part of symbol names in the Objective C ABI.  Replace
characters which are reseved in symbol names:

- ELF: avoid including '@' characters in type encodings
- Windows: avoid including '=' characters in type encodings
---
 clang/lib/CodeGen/CGObjCGNU.cpp        | 30 ++++++++++--------
 clang/test/CodeGenObjC/dllstorage.m    | 18 +++++------
 clang/test/CodeGenObjC/encode-test-6.m | 42 ++++++++++++++++++++------
 3 files changed, 59 insertions(+), 31 deletions(-)

diff --git a/clang/lib/CodeGen/CGObjCGNU.cpp b/clang/lib/CodeGen/CGObjCGNU.cpp
index cd1a0b6a130ff0..9cc7f32815f7e9 100644
--- a/clang/lib/CodeGen/CGObjCGNU.cpp
+++ b/clang/lib/CodeGen/CGObjCGNU.cpp
@@ -1431,12 +1431,24 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
                                 const std::string &TypeEncoding) override {
     return GetConstantSelector(Sel, TypeEncoding);
   }
+  std::string GetSymbolNameForTypeEncoding(const std::string &TypeEncoding) {
+    std::string MangledTypes = std::string(TypeEncoding);
+    // @ is used as a special character in ELF symbol names (used for symbol
+    // versioning), so mangle the name to not include it.  Replace it with a
+    // character that is not a valid type encoding character (and, being
+    // non-printable, never will be!)
+    if (CGM.getTriple().isOSBinFormatELF())
+      std::replace(MangledTypes.begin(), MangledTypes.end(), '@', '\1');
+    // = in dll exported names causes lld to fail when linking on Windows.
+    if (CGM.getTriple().isOSWindows())
+      std::replace(MangledTypes.begin(), MangledTypes.end(), '=', '\2');
+    return MangledTypes;
+  }
   llvm::Constant  *GetTypeString(llvm::StringRef TypeEncoding) {
     if (TypeEncoding.empty())
       return NULLPtr;
-    std::string MangledTypes = std::string(TypeEncoding);
-    std::replace(MangledTypes.begin(), MangledTypes.end(),
-      '@', '\1');
+    std::string MangledTypes =
+        GetSymbolNameForTypeEncoding(std::string(TypeEncoding));
     std::string TypesVarName = ".objc_sel_types_" + MangledTypes;
     auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName);
     if (!TypesGlobal) {
@@ -1453,13 +1465,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
   }
   llvm::Constant *GetConstantSelector(Selector Sel,
                                       const std::string &TypeEncoding) override {
-    // @ is used as a special character in symbol names (used for symbol
-    // versioning), so mangle the name to not include it.  Replace it with a
-    // character that is not a valid type encoding character (and, being
-    // non-printable, never will be!)
-    std::string MangledTypes = TypeEncoding;
-    std::replace(MangledTypes.begin(), MangledTypes.end(),
-      '@', '\1');
+    std::string MangledTypes = GetSymbolNameForTypeEncoding(TypeEncoding);
     auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" +
       MangledTypes).str();
     if (auto *GV = TheModule.getNamedGlobal(SelVarName))
@@ -1671,9 +1677,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
                                         const ObjCIvarDecl *Ivar) override {
     std::string TypeEncoding;
     CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding);
-    // Prevent the @ from being interpreted as a symbol version.
-    std::replace(TypeEncoding.begin(), TypeEncoding.end(),
-      '@', '\1');
+    TypeEncoding = GetSymbolNameForTypeEncoding(TypeEncoding);
     const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
       + '.' + Ivar->getNameAsString() + '.' + TypeEncoding;
     return Name;
diff --git a/clang/test/CodeGenObjC/dllstorage.m b/clang/test/CodeGenObjC/dllstorage.m
index 0dbf1881caa9c0..f45eb7bb6aee78 100644
--- a/clang/test/CodeGenObjC/dllstorage.m
+++ b/clang/test/CodeGenObjC/dllstorage.m
@@ -35,7 +35,7 @@ @implementation J {
 
 // CHECK-IR-DAG: @"OBJC_IVAR_$_J._ivar" = global i32
 
-// CHECK-NF-DAG: @"__objc_ivar_offset_J._ivar.\01" = hidden global i32
+// CHECK-NF-DAG: @"__objc_ivar_offset_J._ivar.@" = hidden global i32
 
 @interface K : J
 @end
@@ -56,7 +56,7 @@ @implementation K {
 
 // CHECK-IR-DAG: @"OBJC_IVAR_$_K._ivar" = global i32
 
-// CHECK-NF-DAG: @"__objc_ivar_offset_K._ivar.\01" = hidden global i32
+// CHECK-NF-DAG: @"__objc_ivar_offset_K._ivar.@" = hidden global i32
 
 __declspec(dllexport)
 @interface L : K
@@ -94,11 +94,11 @@ @implementation L {
 // CHECK-IR-DAG: @"OBJC_IVAR_$_L._package" = global i32
 // CHECK-IR-DAG: @"OBJC_IVAR_$_L._private" = global i32
 
-// CHECK-NF-DAG: @"__objc_ivar_offset_L._none.\01" = hidden global i32
-// CHECK-NF-DAG: @"__objc_ivar_offset_L._public.\01" = dso_local dllexport global i32
-// CHECK-NF-DAG: @"__objc_ivar_offset_L._protected.\01" = dso_local dllexport global i32
-// CHECK-NF-DAG: @"__objc_ivar_offset_L._package.\01" = hidden global i32
-// CHECK-NF-DAG: @"__objc_ivar_offset_L._private.\01" = hidden global i32
+// CHECK-NF-DAG: @"__objc_ivar_offset_L._none.@" = hidden global i32
+// CHECK-NF-DAG: @"__objc_ivar_offset_L._public.@" = dso_local dllexport global i32
+// CHECK-NF-DAG: @"__objc_ivar_offset_L._protected.@" = dso_local dllexport global i32
+// CHECK-NF-DAG: @"__objc_ivar_offset_L._package.@" = hidden global i32
+// CHECK-NF-DAG: @"__objc_ivar_offset_L._private.@" = hidden global i32
 
 __declspec(dllimport)
 @interface M : I {
@@ -112,7 +112,7 @@ @interface M : I {
 // CHECK-IR-DAG: @"OBJC_IVAR_$_M._ivar" = external dllimport global i32
 
 // CHECK-NF-DAG: @"$_OBJC_REF_CLASS_M" = external dllimport global ptr
-// CHECK-NF-DAG: @"__objc_ivar_offset_M._ivar.\01" = external global i32
+// CHECK-NF-DAG: @"__objc_ivar_offset_M._ivar.@" = external global i32
 
 __declspec(dllexport)
 __attribute__((__objc_exception__))
@@ -151,7 +151,7 @@ id f(Q *q) {
 
 // CHECK-IR-DAG: @"OBJC_IVAR_$_M._ivar" = external dllimport global i32
 
-// CHECK-NF-DAG: @"__objc_ivar_offset_M._ivar.\01" = external global i32
+// CHECK-NF-DAG: @"__objc_ivar_offset_M._ivar.@" = external global i32
 
 int g(void) {
   @autoreleasepool {
diff --git a/clang/test/CodeGenObjC/encode-test-6.m b/clang/test/CodeGenObjC/encode-test-6.m
index 261eb7fb3368b2..c32f8f24c00097 100644
--- a/clang/test/CodeGenObjC/encode-test-6.m
+++ b/clang/test/CodeGenObjC/encode-test-6.m
@@ -1,5 +1,10 @@
-// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o %t %s
-// RUN: FileCheck < %t %s
+// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix CHECK-DWARF %s
+
+// RUN: %clang_cc1 -triple x86_64-w64-windows-gnu -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck -check-prefix CHECK-MINGW %s
+
+// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck -check-prefix CHECK-MSVC %s
+
+// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck -check-prefix CHECK-ELF %s
 
 typedef struct {} Z;
 
@@ -13,8 +18,17 @@ -(void)bar:(Z)a {}
 -(void)foo:(Z)a: (char*)b : (Z)c : (double) d {}
 @end
 
-// CHECK: private unnamed_addr constant [14 x i8] c"v16 at 0:8{?=}16
-// CHECK: private unnamed_addr constant [26 x i8] c"v32 at 0:8{?=}16*16{?=}24d24
+// CHECK-DWARF: private unnamed_addr constant [14 x i8] c"v16 at 0:8{?=}16
+// CHECK-DWARF: private unnamed_addr constant [26 x i8] c"v32 at 0:8{?=}16*16{?=}24d24
+
+// CHECK-MINGW: @".objc_sel_types_v16 at 0:8{?\02}16" = linkonce_odr hidden constant [14 x i8] c"v16 at 0:8{?=}16\00"
+// CHECK-MINGW: @".objc_sel_types_v32 at 0:8{?\02}16*16{?\02}24d24" = linkonce_odr hidden constant [26 x i8] c"v32 at 0:8{?=}16*16{?=}24d24\00"
+
+// CHECK-MSVC: @".objc_sel_types_v20 at 0:8{?\02}16" = linkonce_odr hidden constant [14 x i8] c"v20 at 0:8{?=}16\00"
+// CHECK-MSVC: @".objc_sel_types_v40 at 0:8{?\02}16*20{?\02}28d32" = linkonce_odr hidden constant [26 x i8] c"v40 at 0:8{?=}16*20{?=}28d32\00"
+
+// CHECK-ELF: @".objc_sel_types_v16\010:8{?=}16" = linkonce_odr hidden constant [14 x i8] c"v16 at 0:8{?=}16\00"
+// CHECK-ELF: @".objc_sel_types_v32\010:8{?=}16*16{?=}24d24" = linkonce_odr hidden constant [26 x i8] c"v32 at 0:8{?=}16*16{?=}24d24\00"
 
 @interface NSObject @end
 
@@ -31,7 +45,10 @@ @implementation BABugExample
 @synthesize property = _property;
 @end
 
-// CHECK: private unnamed_addr constant [8 x i8] c"@16
+// CHECK-DWARF: private unnamed_addr constant [8 x i8] c"@16
+// CHECK-MINGW: @".objc_sel_types_ at 16@0:8" = linkonce_odr hidden constant [8 x i8] c"@16 at 0:8\00"
+// CHECK-MSVC: @".objc_sel_types_ at 16@0:8" = linkonce_odr hidden constant [8 x i8] c"@16 at 0:8\00"
+// CHECK-ELF @".objc_sel_types_\0116\010:8" = linkonce_odr hidden constant [8 x i8] c"@16 at 0:8\00"
 
 @class SCNCamera;
 typedef SCNCamera C3DCamera;
@@ -48,7 +65,10 @@ @implementation SCNCamera
     C3DCameraStorage _storage;
 }
 @end
-// CHECK: private unnamed_addr constant [39 x i8] c"{?=\22presentationInstance\22@\22SCNCamera\22}\00"
+// CHECK-DWARF: private unnamed_addr constant [39 x i8] c"{?=\22presentationInstance\22@\22SCNCamera\22}\00"
+// CHECK-MINGW: @"__objc_ivar_offset_SCNCamera._storage.{?\02@}"
+// CHECK-MSVC: @"__objc_ivar_offset_SCNCamera._storage.{?\02@}"
+// CHECK-ELF: @"__objc_ivar_offset_SCNCamera._storage.{?=\01}"
 
 int i;
 typeof(@encode(typeof(i))) e = @encode(typeof(i));
@@ -56,6 +76,10 @@ @implementation SCNCamera
 {
     return e;
 }
-// CHECK: @e ={{.*}} global [2 x i8] c"i\00", align 1
-// CHECK: define{{.*}} ptr @Test()
-// CHECK: ret ptr @e
+// CHECK-DWARF: @e ={{.*}} global [2 x i8] c"i\00", align 1
+// CHECK-DWARF: define{{.*}} ptr @Test()
+// CHECK-DWARF: ret ptr @e
+
+// CHECK-MSVC: @e = dso_local global [2 x i8] c"i\00", align 1
+// CHECK-MINGW: @e = dso_local global [2 x i8] c"i\00", align 1
+// CHECK-ELF: @e = global [2 x i8] c"i\00", align 1



More information about the cfe-commits mailing list