Skip to content

Commit 3168192

Browse files
authored
[ObjC]: Make type encoding safe in symbol names (#77797)
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
1 parent 0a8e3dd commit 3168192

File tree

3 files changed

+59
-31
lines changed

3 files changed

+59
-31
lines changed

clang/lib/CodeGen/CGObjCGNU.cpp

Lines changed: 17 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1431,12 +1431,24 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
14311431
const std::string &TypeEncoding) override {
14321432
return GetConstantSelector(Sel, TypeEncoding);
14331433
}
1434+
std::string GetSymbolNameForTypeEncoding(const std::string &TypeEncoding) {
1435+
std::string MangledTypes = std::string(TypeEncoding);
1436+
// @ is used as a special character in ELF symbol names (used for symbol
1437+
// versioning), so mangle the name to not include it. Replace it with a
1438+
// character that is not a valid type encoding character (and, being
1439+
// non-printable, never will be!)
1440+
if (CGM.getTriple().isOSBinFormatELF())
1441+
std::replace(MangledTypes.begin(), MangledTypes.end(), '@', '\1');
1442+
// = in dll exported names causes lld to fail when linking on Windows.
1443+
if (CGM.getTriple().isOSWindows())
1444+
std::replace(MangledTypes.begin(), MangledTypes.end(), '=', '\2');
1445+
return MangledTypes;
1446+
}
14341447
llvm::Constant *GetTypeString(llvm::StringRef TypeEncoding) {
14351448
if (TypeEncoding.empty())
14361449
return NULLPtr;
1437-
std::string MangledTypes = std::string(TypeEncoding);
1438-
std::replace(MangledTypes.begin(), MangledTypes.end(),
1439-
'@', '\1');
1450+
std::string MangledTypes =
1451+
GetSymbolNameForTypeEncoding(std::string(TypeEncoding));
14401452
std::string TypesVarName = ".objc_sel_types_" + MangledTypes;
14411453
auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName);
14421454
if (!TypesGlobal) {
@@ -1453,13 +1465,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
14531465
}
14541466
llvm::Constant *GetConstantSelector(Selector Sel,
14551467
const std::string &TypeEncoding) override {
1456-
// @ is used as a special character in symbol names (used for symbol
1457-
// versioning), so mangle the name to not include it. Replace it with a
1458-
// character that is not a valid type encoding character (and, being
1459-
// non-printable, never will be!)
1460-
std::string MangledTypes = TypeEncoding;
1461-
std::replace(MangledTypes.begin(), MangledTypes.end(),
1462-
'@', '\1');
1468+
std::string MangledTypes = GetSymbolNameForTypeEncoding(TypeEncoding);
14631469
auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" +
14641470
MangledTypes).str();
14651471
if (auto *GV = TheModule.getNamedGlobal(SelVarName))
@@ -1671,9 +1677,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
16711677
const ObjCIvarDecl *Ivar) override {
16721678
std::string TypeEncoding;
16731679
CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding);
1674-
// Prevent the @ from being interpreted as a symbol version.
1675-
std::replace(TypeEncoding.begin(), TypeEncoding.end(),
1676-
'@', '\1');
1680+
TypeEncoding = GetSymbolNameForTypeEncoding(TypeEncoding);
16771681
const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
16781682
+ '.' + Ivar->getNameAsString() + '.' + TypeEncoding;
16791683
return Name;

clang/test/CodeGenObjC/dllstorage.m

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,7 @@ @implementation J {
3535

3636
// CHECK-IR-DAG: @"OBJC_IVAR_$_J._ivar" = global i32
3737

38-
// CHECK-NF-DAG: @"__objc_ivar_offset_J._ivar.\01" = hidden global i32
38+
// CHECK-NF-DAG: @"__objc_ivar_offset_J._ivar.@" = hidden global i32
3939

4040
@interface K : J
4141
@end
@@ -56,7 +56,7 @@ @implementation K {
5656

5757
// CHECK-IR-DAG: @"OBJC_IVAR_$_K._ivar" = global i32
5858

59-
// CHECK-NF-DAG: @"__objc_ivar_offset_K._ivar.\01" = hidden global i32
59+
// CHECK-NF-DAG: @"__objc_ivar_offset_K._ivar.@" = hidden global i32
6060

6161
__declspec(dllexport)
6262
@interface L : K
@@ -94,11 +94,11 @@ @implementation L {
9494
// CHECK-IR-DAG: @"OBJC_IVAR_$_L._package" = global i32
9595
// CHECK-IR-DAG: @"OBJC_IVAR_$_L._private" = global i32
9696

97-
// CHECK-NF-DAG: @"__objc_ivar_offset_L._none.\01" = hidden global i32
98-
// CHECK-NF-DAG: @"__objc_ivar_offset_L._public.\01" = dso_local dllexport global i32
99-
// CHECK-NF-DAG: @"__objc_ivar_offset_L._protected.\01" = dso_local dllexport global i32
100-
// CHECK-NF-DAG: @"__objc_ivar_offset_L._package.\01" = hidden global i32
101-
// CHECK-NF-DAG: @"__objc_ivar_offset_L._private.\01" = hidden global i32
97+
// CHECK-NF-DAG: @"__objc_ivar_offset_L._none.@" = hidden global i32
98+
// CHECK-NF-DAG: @"__objc_ivar_offset_L._public.@" = dso_local dllexport global i32
99+
// CHECK-NF-DAG: @"__objc_ivar_offset_L._protected.@" = dso_local dllexport global i32
100+
// CHECK-NF-DAG: @"__objc_ivar_offset_L._package.@" = hidden global i32
101+
// CHECK-NF-DAG: @"__objc_ivar_offset_L._private.@" = hidden global i32
102102

103103
__declspec(dllimport)
104104
@interface M : I {
@@ -112,7 +112,7 @@ @interface M : I {
112112
// CHECK-IR-DAG: @"OBJC_IVAR_$_M._ivar" = external dllimport global i32
113113

114114
// CHECK-NF-DAG: @"$_OBJC_REF_CLASS_M" = external dllimport global ptr
115-
// CHECK-NF-DAG: @"__objc_ivar_offset_M._ivar.\01" = external global i32
115+
// CHECK-NF-DAG: @"__objc_ivar_offset_M._ivar.@" = external global i32
116116

117117
__declspec(dllexport)
118118
__attribute__((__objc_exception__))
@@ -151,7 +151,7 @@ id f(Q *q) {
151151

152152
// CHECK-IR-DAG: @"OBJC_IVAR_$_M._ivar" = external dllimport global i32
153153

154-
// CHECK-NF-DAG: @"__objc_ivar_offset_M._ivar.\01" = external global i32
154+
// CHECK-NF-DAG: @"__objc_ivar_offset_M._ivar.@" = external global i32
155155

156156
int g(void) {
157157
@autoreleasepool {

clang/test/CodeGenObjC/encode-test-6.m

Lines changed: 33 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,10 @@
1-
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o %t %s
2-
// RUN: FileCheck < %t %s
1+
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix CHECK-DWARF %s
2+
3+
// RUN: %clang_cc1 -triple x86_64-w64-windows-gnu -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck -check-prefix CHECK-MINGW %s
4+
5+
// RUN: %clang_cc1 -triple x86_64-windows-msvc -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck -check-prefix CHECK-MSVC %s
6+
7+
// RUN: %clang_cc1 -triple x86_64-linux-gnu -emit-llvm -fobjc-runtime=gnustep-2.0 -o - %s | FileCheck -check-prefix CHECK-ELF %s
38

49
typedef struct {} Z;
510

@@ -13,8 +18,17 @@ -(void)bar:(Z)a {}
1318
-(void)foo:(Z)a: (char*)b : (Z)c : (double) d {}
1419
@end
1520

16-
// CHECK: private unnamed_addr constant [14 x i8] c"v16@0:8{?=}16
17-
// CHECK: private unnamed_addr constant [26 x i8] c"v32@0:8{?=}16*16{?=}24d24
21+
// CHECK-DWARF: private unnamed_addr constant [14 x i8] c"v16@0:8{?=}16
22+
// CHECK-DWARF: private unnamed_addr constant [26 x i8] c"v32@0:8{?=}16*16{?=}24d24
23+
24+
// CHECK-MINGW: @".objc_sel_types_v16@0:8{?\02}16" = linkonce_odr hidden constant [14 x i8] c"v16@0:8{?=}16\00"
25+
// CHECK-MINGW: @".objc_sel_types_v32@0:8{?\02}16*16{?\02}24d24" = linkonce_odr hidden constant [26 x i8] c"v32@0:8{?=}16*16{?=}24d24\00"
26+
27+
// CHECK-MSVC: @".objc_sel_types_v20@0:8{?\02}16" = linkonce_odr hidden constant [14 x i8] c"v20@0:8{?=}16\00"
28+
// CHECK-MSVC: @".objc_sel_types_v40@0:8{?\02}16*20{?\02}28d32" = linkonce_odr hidden constant [26 x i8] c"v40@0:8{?=}16*20{?=}28d32\00"
29+
30+
// CHECK-ELF: @".objc_sel_types_v16\010:8{?=}16" = linkonce_odr hidden constant [14 x i8] c"v16@0:8{?=}16\00"
31+
// CHECK-ELF: @".objc_sel_types_v32\010:8{?=}16*16{?=}24d24" = linkonce_odr hidden constant [26 x i8] c"v32@0:8{?=}16*16{?=}24d24\00"
1832

1933
@interface NSObject @end
2034

@@ -31,7 +45,10 @@ @implementation BABugExample
3145
@synthesize property = _property;
3246
@end
3347

34-
// CHECK: private unnamed_addr constant [8 x i8] c"@16
48+
// CHECK-DWARF: private unnamed_addr constant [8 x i8] c"@16
49+
// CHECK-MINGW: @".objc_sel_types_@16@0:8" = linkonce_odr hidden constant [8 x i8] c"@16@0:8\00"
50+
// CHECK-MSVC: @".objc_sel_types_@16@0:8" = linkonce_odr hidden constant [8 x i8] c"@16@0:8\00"
51+
// CHECK-ELF @".objc_sel_types_\0116\010:8" = linkonce_odr hidden constant [8 x i8] c"@16@0:8\00"
3552

3653
@class SCNCamera;
3754
typedef SCNCamera C3DCamera;
@@ -48,14 +65,21 @@ @implementation SCNCamera
4865
C3DCameraStorage _storage;
4966
}
5067
@end
51-
// CHECK: private unnamed_addr constant [39 x i8] c"{?=\22presentationInstance\22@\22SCNCamera\22}\00"
68+
// CHECK-DWARF: private unnamed_addr constant [39 x i8] c"{?=\22presentationInstance\22@\22SCNCamera\22}\00"
69+
// CHECK-MINGW: @"__objc_ivar_offset_SCNCamera._storage.{?\02@}"
70+
// CHECK-MSVC: @"__objc_ivar_offset_SCNCamera._storage.{?\02@}"
71+
// CHECK-ELF: @"__objc_ivar_offset_SCNCamera._storage.{?=\01}"
5272

5373
int i;
5474
typeof(@encode(typeof(i))) e = @encode(typeof(i));
5575
const char * Test(void)
5676
{
5777
return e;
5878
}
59-
// CHECK: @e ={{.*}} global [2 x i8] c"i\00", align 1
60-
// CHECK: define{{.*}} ptr @Test()
61-
// CHECK: ret ptr @e
79+
// CHECK-DWARF: @e ={{.*}} global [2 x i8] c"i\00", align 1
80+
// CHECK-DWARF: define{{.*}} ptr @Test()
81+
// CHECK-DWARF: ret ptr @e
82+
83+
// CHECK-MSVC: @e = dso_local global [2 x i8] c"i\00", align 1
84+
// CHECK-MINGW: @e = dso_local global [2 x i8] c"i\00", align 1
85+
// CHECK-ELF: @e = global [2 x i8] c"i\00", align 1

0 commit comments

Comments
 (0)