Fix a bug where we were trying to reconstruct ivars of ObjC types from the runtime in "expression parser mode"

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
This commit is contained in:
Enrico Granata 2015-06-25 19:17:04 +00:00
parent 1f93e86768
commit 2d061e20f6
6 changed files with 117 additions and 1 deletions

View 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);

View File

@ -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

View File

@ -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()

View File

@ -0,0 +1,6 @@
#import <Foundation/Foundation.h>
@interface MyClass : NSObject
{}
- (id)init;
@end

View File

@ -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

View File

@ -0,0 +1,7 @@
#import <Foundation/Foundation.h>
#import "MyClass.h"
int main() {
id object = [MyClass new];
return 0; // break here
}