[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