erik.pilkington created this revision.
erik.pilkington added reviewers: rjmccall, ahatanak, jfb.
Herald added a subscriber: dexonsmith.

Some ObjC users declare a `extern` variable named `OBJC_CLASS_$_Foo`, then use 
it's address as a `Class`. I.e., one could define `isInstanceOfF`:

  BOOL isInstanceOfF(id c) {
    extern void OBJC_CLASS_$_F;
    return [c class] == (Class)&OBJC_CLASS_$_F;
  }

This leads to asserts in clang CodeGen if there is an `@implementation` of `F` 
in the same TU as an instance of this pattern, because CodeGen assumes that a 
variable named OBJC_CLASS_$_* has the right type. This patch fixes the problem 
by RAUWing the old (incorrectly typed) global with a new global, then removing 
the old global.

I know almost nothing about Objective-C runtime stuff, so take this patch with 
a grain of salt!

Fixes rdar://45077269


Repository:
  rC Clang

https://reviews.llvm.org/D53154

Files:
  clang/lib/CodeGen/CGObjCMac.cpp
  clang/test/CodeGenObjC/extern-void-class-decl.m


Index: clang/test/CodeGenObjC/extern-void-class-decl.m
===================================================================
--- /dev/null
+++ clang/test/CodeGenObjC/extern-void-class-decl.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -emit-llvm -o - | 
FileCheck %s
+
+// rdar://45077269
+
+extern void OBJC_CLASS_$_f;
+Class c = (Class)&OBJC_CLASS_$_f;
+
+@implementation f @end
+
+// Check that we override the initializer for c, and that OBJC_CLASS_$_f gets
+// the right definition.
+
+// CHECK: @c = global i8* bitcast (%struct._class_t* @"OBJC_CLASS_$_f" to i8*)
+// CHECK: @"OBJC_CLASS_$_f" = global %struct._class_t
Index: clang/lib/CodeGen/CGObjCMac.cpp
===================================================================
--- clang/lib/CodeGen/CGObjCMac.cpp
+++ clang/lib/CodeGen/CGObjCMac.cpp
@@ -7188,15 +7188,21 @@
       Weak ? llvm::GlobalValue::ExternalWeakLinkage
            : llvm::GlobalValue::ExternalLinkage;
 
-
-
   llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
-  if (!GV) {
-    GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
-                                  false, L, nullptr, Name);
+  if (!GV || GV->getType() != ObjCTypes.ClassnfABITy->getPointerTo()) {
+    auto *NewGV = new llvm::GlobalVariable(ObjCTypes.ClassnfABITy, false, L,
+                                           nullptr, Name);
 
     if (DLLImport)
-      GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+      NewGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+
+    if (GV) {
+      GV->replaceAllUsesWith(
+          llvm::ConstantExpr::getBitCast(NewGV, GV->getType()));
+      GV->eraseFromParent();
+    }
+    GV = NewGV;
+    CGM.getModule().getGlobalList().push_back(GV);
   }
 
   assert(GV->getLinkage() == L);


Index: clang/test/CodeGenObjC/extern-void-class-decl.m
===================================================================
--- /dev/null
+++ clang/test/CodeGenObjC/extern-void-class-decl.m
@@ -0,0 +1,14 @@
+// RUN: %clang_cc1 -triple x86_64-apple-macosx10.14.0 %s -emit-llvm -o - | FileCheck %s
+
+// rdar://45077269
+
+extern void OBJC_CLASS_$_f;
+Class c = (Class)&OBJC_CLASS_$_f;
+
+@implementation f @end
+
+// Check that we override the initializer for c, and that OBJC_CLASS_$_f gets
+// the right definition.
+
+// CHECK: @c = global i8* bitcast (%struct._class_t* @"OBJC_CLASS_$_f" to i8*)
+// CHECK: @"OBJC_CLASS_$_f" = global %struct._class_t
Index: clang/lib/CodeGen/CGObjCMac.cpp
===================================================================
--- clang/lib/CodeGen/CGObjCMac.cpp
+++ clang/lib/CodeGen/CGObjCMac.cpp
@@ -7188,15 +7188,21 @@
       Weak ? llvm::GlobalValue::ExternalWeakLinkage
            : llvm::GlobalValue::ExternalLinkage;
 
-
-
   llvm::GlobalVariable *GV = CGM.getModule().getGlobalVariable(Name);
-  if (!GV) {
-    GV = new llvm::GlobalVariable(CGM.getModule(), ObjCTypes.ClassnfABITy,
-                                  false, L, nullptr, Name);
+  if (!GV || GV->getType() != ObjCTypes.ClassnfABITy->getPointerTo()) {
+    auto *NewGV = new llvm::GlobalVariable(ObjCTypes.ClassnfABITy, false, L,
+                                           nullptr, Name);
 
     if (DLLImport)
-      GV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+      NewGV->setDLLStorageClass(llvm::GlobalValue::DLLImportStorageClass);
+
+    if (GV) {
+      GV->replaceAllUsesWith(
+          llvm::ConstantExpr::getBitCast(NewGV, GV->getType()));
+      GV->eraseFromParent();
+    }
+    GV = NewGV;
+    CGM.getModule().getGlobalList().push_back(GV);
   }
 
   assert(GV->getLinkage() == L);
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
http://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to