Fix a bug where we were trying to reconstruct ivars of ObjC types from the runtime...
authorEnrico Granata <egranata@apple.com>
Thu, 25 Jun 2015 19:17:04 +0000 (19:17 +0000)
committerEnrico Granata <egranata@apple.com>
Thu, 25 Jun 2015 19:17:04 +0000 (19:17 +0000)
The expression parser mode allows UnknownAnyTy to make it all the way through, but that is bad for ivars because it means type layout fails horribly (as in, clang crashes)

This patch fixes the issue by using the "variables view mode", which masks UnknownAnyTy as empty-type, and pointer-to UnknownAnyTy as void*

This, in turn, allows LLDB to properly reconstruct ivars of IMP type in ObjC type - as per accompanying test case

Fixes rdar://21471326

llvm-svn: 240677

lldb/source/Plugins/LanguageRuntime/ObjC/AppleObjCRuntime/AppleObjCDeclVendor.cpp
lldb/test/lang/objc/ivar-IMP/Makefile [new file with mode: 0644]
lldb/test/lang/objc/ivar-IMP/TestObjCiVarIMP.py [new file with mode: 0644]
lldb/test/lang/objc/ivar-IMP/myclass.h [new file with mode: 0644]
lldb/test/lang/objc/ivar-IMP/myclass.m [new file with mode: 0644]
lldb/test/lang/objc/ivar-IMP/repro.m [new file with mode: 0644]

index 76ac690..2c4ecf4 100644 (file)
@@ -496,7 +496,7 @@ AppleObjCDeclVendor::FinishDecl(clang::ObjCInterfaceDecl *interface_decl)
         if (!name || !type)
             return false;
         
-        const bool for_expression = true;
+        const bool for_expression = false;
         
         if (log)
             log->Printf("[  AOTV::FD] Instance variable [%s] [%s], offset at %" PRIx64, name, type, offset_ptr);
diff --git a/lldb/test/lang/objc/ivar-IMP/Makefile b/lldb/test/lang/objc/ivar-IMP/Makefile
new file mode 100644 (file)
index 0000000..329ceab
--- /dev/null
@@ -0,0 +1,12 @@
+LEVEL = ../../../make
+
+myclass.o: myclass.h myclass.m
+       $(CC) myclass.m -c -o myclass.o
+
+repro: myclass.o repro.m
+       $(CC) -g -O0 myclass.o repro.m -framework Foundation
+
+cleanup:
+       rm -r myclass.o
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/lang/objc/ivar-IMP/TestObjCiVarIMP.py b/lldb/test/lang/objc/ivar-IMP/TestObjCiVarIMP.py
new file mode 100644 (file)
index 0000000..d908449
--- /dev/null
@@ -0,0 +1,75 @@
+"""
+Test that dynamically discovered ivars of type IMP do not crash LLDB
+"""
+
+import os, time
+import re
+import unittest2
+import lldb, lldbutil
+from lldbtest import *
+import commands
+
+def execute_command (command):
+    # print '%% %s' % (command)
+    (exit_status, output) = commands.getstatusoutput (command)
+    # if output:
+    #     print output
+    # print 'status = %u' % (exit_status)
+    return exit_status
+
+class ObjCiVarIMPTestCase(TestBase):
+
+    mydir = TestBase.compute_mydir(__file__)
+
+    @skipUnlessDarwin
+    def test_imp_ivar_type(self):
+        """Test that dynamically discovered ivars of type IMP do not crash LLDB"""
+        if self.getArchitecture() == 'i386':
+            # rdar://problem/9946499
+            self.skipTest("Dynamic types for ObjC V1 runtime not implemented")
+        self.buildReproCase()
+        self.runTheTest()
+
+    def setUp(self):
+        # Call super's setUp().                                                                                                           
+        TestBase.setUp(self)
+
+    def buildReproCase (self):
+        execute_command("make repro")
+
+    def runTheTest(self):
+        """MakeTest that dynamically discovered ivars of type IMP do not crash LLDB"""
+        def cleanup():
+            execute_command("make cleanup")
+        self.addTearDownHook(cleanup)
+
+        exe = os.path.join(os.getcwd(), "a.out")
+
+        # Create a target from the debugger.
+
+        target = self.dbg.CreateTarget (exe)
+        self.assertTrue(target, VALID_TARGET)
+
+        # Set up our breakpoint
+
+        bkpt = lldbutil.run_break_set_by_source_regexp (self, "break here")
+
+        # Now launch the process, and do not stop at the entry point.
+        process = target.LaunchSimple (None, None, self.get_process_working_directory())
+
+        self.assertTrue(process.GetState() == lldb.eStateStopped,
+                        PROCESS_STOPPED)
+
+        self.expect('frame variable --ptr-depth=1 --show-types -d run -- object', substrs=[
+            '(MyClass *) object = 0x',
+            '(void *) myImp = 0x'
+        ])
+        self.expect('disassemble --start-address `((MyClass*)object)->myImp`', substrs=[
+            '-[MyClass init]'
+        ])
+
+if __name__ == '__main__':
+    import atexit
+    lldb.SBDebugger.Initialize()
+    atexit.register(lambda: lldb.SBDebugger.Terminate())
+    unittest2.main()
diff --git a/lldb/test/lang/objc/ivar-IMP/myclass.h b/lldb/test/lang/objc/ivar-IMP/myclass.h
new file mode 100644 (file)
index 0000000..da28d1e
--- /dev/null
@@ -0,0 +1,6 @@
+#import <Foundation/Foundation.h>
+
+@interface MyClass : NSObject
+{}
+- (id)init;
+@end
diff --git a/lldb/test/lang/objc/ivar-IMP/myclass.m b/lldb/test/lang/objc/ivar-IMP/myclass.m
new file mode 100644 (file)
index 0000000..3ff2ac7
--- /dev/null
@@ -0,0 +1,16 @@
+#import <Foundation/Foundation.h>
+#import "MyClass.h"
+
+@implementation MyClass
+{
+  IMP myImp;
+}
+- (id)init {
+  if (self = [super init])
+  {
+    SEL theSelector = @selector(init);
+    self->myImp = [self methodForSelector:theSelector]; 
+  }
+  return self;
+}
+@end
diff --git a/lldb/test/lang/objc/ivar-IMP/repro.m b/lldb/test/lang/objc/ivar-IMP/repro.m
new file mode 100644 (file)
index 0000000..dc522b2
--- /dev/null
@@ -0,0 +1,7 @@
+#import <Foundation/Foundation.h>
+#import "MyClass.h"
+
+int main() {
+  id object = [MyClass new];
+  return 0; // break here
+}