[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
This commit is contained in:
Frederik Carlier 2024-01-12 01:03:37 -08:00 committed by GitHub
parent 0a8e3dd432
commit 3168192de5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 59 additions and 31 deletions

View File

@ -1431,12 +1431,24 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
const std::string &TypeEncoding) override { const std::string &TypeEncoding) override {
return GetConstantSelector(Sel, TypeEncoding); 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) { llvm::Constant *GetTypeString(llvm::StringRef TypeEncoding) {
if (TypeEncoding.empty()) if (TypeEncoding.empty())
return NULLPtr; return NULLPtr;
std::string MangledTypes = std::string(TypeEncoding); std::string MangledTypes =
std::replace(MangledTypes.begin(), MangledTypes.end(), GetSymbolNameForTypeEncoding(std::string(TypeEncoding));
'@', '\1');
std::string TypesVarName = ".objc_sel_types_" + MangledTypes; std::string TypesVarName = ".objc_sel_types_" + MangledTypes;
auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName); auto *TypesGlobal = TheModule.getGlobalVariable(TypesVarName);
if (!TypesGlobal) { if (!TypesGlobal) {
@ -1453,13 +1465,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
} }
llvm::Constant *GetConstantSelector(Selector Sel, llvm::Constant *GetConstantSelector(Selector Sel,
const std::string &TypeEncoding) override { const std::string &TypeEncoding) override {
// @ is used as a special character in symbol names (used for symbol std::string MangledTypes = GetSymbolNameForTypeEncoding(TypeEncoding);
// 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');
auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" + auto SelVarName = (StringRef(".objc_selector_") + Sel.getAsString() + "_" +
MangledTypes).str(); MangledTypes).str();
if (auto *GV = TheModule.getNamedGlobal(SelVarName)) if (auto *GV = TheModule.getNamedGlobal(SelVarName))
@ -1671,9 +1677,7 @@ class CGObjCGNUstep2 : public CGObjCGNUstep {
const ObjCIvarDecl *Ivar) override { const ObjCIvarDecl *Ivar) override {
std::string TypeEncoding; std::string TypeEncoding;
CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding); CGM.getContext().getObjCEncodingForType(Ivar->getType(), TypeEncoding);
// Prevent the @ from being interpreted as a symbol version. TypeEncoding = GetSymbolNameForTypeEncoding(TypeEncoding);
std::replace(TypeEncoding.begin(), TypeEncoding.end(),
'@', '\1');
const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString() const std::string Name = "__objc_ivar_offset_" + ID->getNameAsString()
+ '.' + Ivar->getNameAsString() + '.' + TypeEncoding; + '.' + Ivar->getNameAsString() + '.' + TypeEncoding;
return Name; return Name;

View File

@ -35,7 +35,7 @@ __declspec(dllexport)
// CHECK-IR-DAG: @"OBJC_IVAR_$_J._ivar" = global i32 // 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 @interface K : J
@end @end
@ -56,7 +56,7 @@ __declspec(dllexport)
// CHECK-IR-DAG: @"OBJC_IVAR_$_K._ivar" = global i32 // 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) __declspec(dllexport)
@interface L : K @interface L : K
@ -94,11 +94,11 @@ __declspec(dllexport)
// CHECK-IR-DAG: @"OBJC_IVAR_$_L._package" = global i32 // CHECK-IR-DAG: @"OBJC_IVAR_$_L._package" = global i32
// CHECK-IR-DAG: @"OBJC_IVAR_$_L._private" = 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._none.@" = hidden global i32
// CHECK-NF-DAG: @"__objc_ivar_offset_L._public.\01" = dso_local dllexport global i32 // CHECK-NF-DAG: @"__objc_ivar_offset_L._public.@" = 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._protected.@" = dso_local dllexport global i32
// CHECK-NF-DAG: @"__objc_ivar_offset_L._package.\01" = hidden global i32 // CHECK-NF-DAG: @"__objc_ivar_offset_L._package.@" = hidden global i32
// CHECK-NF-DAG: @"__objc_ivar_offset_L._private.\01" = hidden global i32 // CHECK-NF-DAG: @"__objc_ivar_offset_L._private.@" = hidden global i32
__declspec(dllimport) __declspec(dllimport)
@interface M : I { @interface M : I {
@ -112,7 +112,7 @@ __declspec(dllimport)
// CHECK-IR-DAG: @"OBJC_IVAR_$_M._ivar" = external dllimport global i32 // 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_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) __declspec(dllexport)
__attribute__((__objc_exception__)) __attribute__((__objc_exception__))
@ -151,7 +151,7 @@ id f(Q *q) {
// CHECK-IR-DAG: @"OBJC_IVAR_$_M._ivar" = external dllimport global i32 // 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) { int g(void) {
@autoreleasepool { @autoreleasepool {

View File

@ -1,5 +1,10 @@
// RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o %t %s // RUN: %clang_cc1 -triple x86_64-apple-darwin -emit-llvm -o - %s | FileCheck -check-prefix CHECK-DWARF %s
// RUN: FileCheck < %t %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; typedef struct {} Z;
@ -13,8 +18,17 @@ typedef struct {} Z;
-(void)foo:(Z)a: (char*)b : (Z)c : (double) d {} -(void)foo:(Z)a: (char*)b : (Z)c : (double) d {}
@end @end
// CHECK: private unnamed_addr constant [14 x i8] c"v16@0:8{?=}16 // CHECK-DWARF: private unnamed_addr constant [14 x i8] c"v16@0:8{?=}16
// CHECK: private unnamed_addr constant [26 x i8] c"v32@0:8{?=}16*16{?=}24d24 // CHECK-DWARF: private unnamed_addr constant [26 x i8] c"v32@0:8{?=}16*16{?=}24d24
// CHECK-MINGW: @".objc_sel_types_v16@0:8{?\02}16" = linkonce_odr hidden constant [14 x i8] c"v16@0:8{?=}16\00"
// 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"
// CHECK-MSVC: @".objc_sel_types_v20@0:8{?\02}16" = linkonce_odr hidden constant [14 x i8] c"v20@0:8{?=}16\00"
// 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"
// CHECK-ELF: @".objc_sel_types_v16\010:8{?=}16" = linkonce_odr hidden constant [14 x i8] c"v16@0:8{?=}16\00"
// 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"
@interface NSObject @end @interface NSObject @end
@ -31,7 +45,10 @@ typedef BABugExample BABugExampleRedefinition;
@synthesize property = _property; @synthesize property = _property;
@end @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_@16@0:8" = linkonce_odr hidden constant [8 x i8] c"@16@0:8\00"
// CHECK-MSVC: @".objc_sel_types_@16@0:8" = linkonce_odr hidden constant [8 x i8] c"@16@0:8\00"
// CHECK-ELF @".objc_sel_types_\0116\010:8" = linkonce_odr hidden constant [8 x i8] c"@16@0:8\00"
@class SCNCamera; @class SCNCamera;
typedef SCNCamera C3DCamera; typedef SCNCamera C3DCamera;
@ -48,7 +65,10 @@ typedef struct
C3DCameraStorage _storage; C3DCameraStorage _storage;
} }
@end @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; int i;
typeof(@encode(typeof(i))) e = @encode(typeof(i)); typeof(@encode(typeof(i))) e = @encode(typeof(i));
@ -56,6 +76,10 @@ const char * Test(void)
{ {
return e; return e;
} }
// CHECK: @e ={{.*}} global [2 x i8] c"i\00", align 1 // CHECK-DWARF: @e ={{.*}} global [2 x i8] c"i\00", align 1
// CHECK: define{{.*}} ptr @Test() // CHECK-DWARF: define{{.*}} ptr @Test()
// CHECK: ret ptr @e // 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