Open madsolar8582 opened 6 years ago
Turning on Guard Malloc also found some issues. In the OCMockObjectClassMethodMockingTests
, the testStopMockingDisposesMetaClass
and testSecondClassMockDisposesFirstMetaClass
throw memory access errors after the stopMocking calls since the backing const char* storage for the sublcass name(s) were deallocated. I was able to fix this by copying the subclass name(s):
- (void)testStopMockingDisposesMetaClass
{
id mock = [[OCClassMockObject alloc] initWithClass:[TestClassWithClassMethods class]];
NSString *createdSubclassName = @(object_getClassName([TestClassWithClassMethods class]));
XCTAssertNotNil(objc_lookUpClass(createdSubclassName.UTF8String));
[mock stopMocking];
XCTAssertNil(objc_lookUpClass(createdSubclassName.UTF8String));
}
- (void)testSecondClassMockDisposesFirstMetaClass
{
id mock1 = [[OCClassMockObject alloc] initWithClass:[TestClassWithClassMethods class]];
NSString *createdSubclassName1 = @(object_getClassName([TestClassWithClassMethods class]));
XCTAssertNotNil(objc_lookUpClass(createdSubclassName1.UTF8String));
id mock2 = [[OCClassMockObject alloc] initWithClass:[TestClassWithClassMethods class]];
NSString *createdSubclassName2 = @(object_getClassName([TestClassWithClassMethods class]));
XCTAssertNotNil(objc_lookUpClass(createdSubclassName2.UTF8String));
[mock1 stopMocking];
[mock2 stopMocking];
XCTAssertNil(objc_lookUpClass(createdSubclassName1.UTF8String));
XCTAssertNil(objc_lookUpClass(createdSubclassName2.UTF8String));
}
Unfortunately, I think I've hit my debugging with LLDB knowledge limit as I can't figure out what object the retain is crashing on:
(lldb) down
frame #0: 0x00000001042c5fa7 libobjc.A.dylib`objc_retain + 7
libobjc.A.dylib`objc_retain:
-> 0x1042c5fa7 <+7>: movq (%rdi), %rax ; Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
0x1042c5faa <+10>: testb $0x4, 0x20(%rax)
0x1042c5fae <+14>: jne 0x1042c6ac2 ; objc_object::sidetable_retain()
0x1042c5fb4 <+20>: leaq 0x8f5eb5(%rip), %rax ; SEL_retain
(lldb) di -f
libobjc.A.dylib`objc_retain:
0x1042c5fa0 <+0>: testq %rdi, %rdi
0x1042c5fa3 <+3>: je 0x1042c5fc3 ; <+35>
0x1042c5fa5 <+5>: js 0x1042c5fc5 ; <+37>
-> 0x1042c5fa7 <+7>: movq (%rdi), %rax
0x1042c5faa <+10>: testb $0x4, 0x20(%rax)
0x1042c5fae <+14>: jne 0x1042c6ac2 ; objc_object::sidetable_retain()
0x1042c5fb4 <+20>: leaq 0x8f5eb5(%rip), %rax ; SEL_retain
0x1042c5fbb <+27>: movq (%rax), %rsi
0x1042c5fbe <+30>: jmp 0x1042c8d80 ; objc_msgSend
0x1042c5fc3 <+35>: xorl %edi, %edi
0x1042c5fc5 <+37>: movq %rdi, %rax
0x1042c5fc8 <+40>: retq
(lldb) register read --all
General Purpose Registers:
rax = 0x0000000000000000
rbx = 0x00007b540000c6c0
rcx = 0x000000000000010c
rdx = 0x0000000107261380 libsystem_pthread.dylib`_thread
rdi = 0x4000000000000000
rsi = 0x0000000000000000
rbp = 0x00007ffeed6c63b0
rsp = 0x00007ffeed6c61c8
r8 = 0x0000000000000001
r9 = 0x0000000000000001
r10 = 0x0000000000000000
r11 = 0x0000000000000000
r12 = 0x00007b1000051d80
r13 = 0x00007b540000c580
r14 = 0x00007b1000051d88
r15 = 0x00007b080001dea0
rip = 0x00000001042c5fa7 libobjc.A.dylib`objc_retain + 7
rflags = 0x0000000000000206
cs = 0x000000000000002b
fs = 0x0000000000000000
gs = 0x0000000000000000
eax = 0x00000000
ebx = 0x0000c6c0
ecx = 0x0000010c
edx = 0x07261380
edi = 0x00000000
esi = 0x00000000
ebp = 0xed6c63b0
esp = 0xed6c61c8
r8d = 0x00000001
r9d = 0x00000001
r10d = 0x00000000
r11d = 0x00000000
r12d = 0x00051d80
r13d = 0x0000c580
r14d = 0x00051d88
r15d = 0x0001dea0
ax = 0x0000
bx = 0xc6c0
cx = 0x010c
dx = 0x1380
di = 0x0000
si = 0x0000
bp = 0x63b0
sp = 0x61c8
r8w = 0x0001
r9w = 0x0001
r10w = 0x0000
r11w = 0x0000
r12w = 0x1d80
r13w = 0xc580
r14w = 0x1d88
r15w = 0xdea0
ah = 0x00
bh = 0xc6
ch = 0x01
dh = 0x13
al = 0x00
bl = 0xc0
cl = 0x0c
dl = 0x80
dil = 0x00
sil = 0x00
bpl = 0xb0
spl = 0xc8
r8l = 0x01
r9l = 0x01
r10l = 0x00
r11l = 0x00
r12l = 0x80
r13l = 0x80
r14l = 0x88
r15l = 0xa0
Floating Point Registers:
fctrl = 0x037f
fstat = 0x0000
ftag = 0x0000
fop = 0x0000
fioff = 0x00000000
fiseg = 0x0000
fooff = 0x00000000
foseg = 0x0000
mxcsr = 0x00001fa0
mxcsrmask = 0x0000ffff
stmm0 = {0x37 0xcd 0x02 0x00 0x00 0x00 0x00 0x00 0xff 0xff}
stmm1 = {0xef 0x1b 0x35 0xed 0xff 0xff 0x01 0x00 0xff 0xff}
stmm2 = {0xff 0xff 0x01 0x00 0x00 0x00 0x00 0x00 0xff 0xff}
stmm3 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
stmm4 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
stmm5 = {0x94 0xff 0x73 0xff 0x00 0x00 0x00 0x00 0xff 0xff}
stmm6 = {0x18 0xf8 0x8e 0x01 0x00 0x00 0x00 0x00 0xff 0xff}
stmm7 = {0x00 0x00 0x70 0xff 0x00 0x00 0x00 0x00 0xff 0xff}
ymm0 = {0x00 0x00 0x00 0x00 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm1 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm2 = {0xe0 0x7a 0x17 0x00 0xe0 0x7a 0x17 0x00 0xe0 0x7a 0x17 0x00 0xe0 0x7a 0x17 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm3 = {0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm4 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm5 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm6 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm7 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm8 = {0x31 0xba 0x00 0x68 0x47 0xe2 0xa6 0x49 0xcc 0xfa 0xdd 0x46 0x02 0xa8 0x39 0xf4 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm9 = {0xe8 0xa8 0xbf 0x1f 0xaf 0x4a 0x19 0x56 0x63 0xb0 0xc4 0x10 0x61 0x18 0xfd 0xe4 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm10 = {0xa7 0x84 0xc5 0x98 0x88 0x28 0x0e 0x5c 0x5a 0xef 0xdd 0x0d 0x58 0x89 0x9e 0xdc 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm11 = {0x08 0x8f 0x43 0xf2 0x80 0xa7 0x4d 0xae 0xda 0x48 0x90 0xa3 0x82 0xc1 0x0e 0x7f 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm12 = {0x60 0x24 0x91 0xe1 0xe0 0x83 0xdc 0x4f 0x3a 0xcb 0x4c 0xec 0xb8 0x0a 0x42 0x93 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm13 = {0x27 0x08 0x4d 0x8d 0xc7 0x8b 0x91 0xc2 0xfd 0x40 0xdd 0x2e 0x45 0x4a 0x9f 0xbd 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm14 = {0xb1 0xd3 0x37 0xe3 0x76 0x58 0xa6 0x21 0x8b 0x18 0x7b 0x0f 0xce 0x52 0xe4 0xb2 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
ymm15 = {0xde 0xa4 0xbc 0x66 0xa9 0xac 0x68 0x20 0xa1 0xee 0x26 0x60 0xa6 0x02 0xdb 0xbd 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
xmm0 = {0x00 0x00 0x00 0x00 0xff 0xff 0xff 0xff 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
xmm1 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
xmm2 = {0xe0 0x7a 0x17 0x00 0xe0 0x7a 0x17 0x00 0xe0 0x7a 0x17 0x00 0xe0 0x7a 0x17 0x00}
xmm3 = {0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff 0xff}
xmm4 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
xmm5 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
xmm6 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
xmm7 = {0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00}
xmm8 = {0x31 0xba 0x00 0x68 0x47 0xe2 0xa6 0x49 0xcc 0xfa 0xdd 0x46 0x02 0xa8 0x39 0xf4}
xmm9 = {0xe8 0xa8 0xbf 0x1f 0xaf 0x4a 0x19 0x56 0x63 0xb0 0xc4 0x10 0x61 0x18 0xfd 0xe4}
xmm10 = {0xa7 0x84 0xc5 0x98 0x88 0x28 0x0e 0x5c 0x5a 0xef 0xdd 0x0d 0x58 0x89 0x9e 0xdc}
xmm11 = {0x08 0x8f 0x43 0xf2 0x80 0xa7 0x4d 0xae 0xda 0x48 0x90 0xa3 0x82 0xc1 0x0e 0x7f}
xmm12 = {0x60 0x24 0x91 0xe1 0xe0 0x83 0xdc 0x4f 0x3a 0xcb 0x4c 0xec 0xb8 0x0a 0x42 0x93}
xmm13 = {0x27 0x08 0x4d 0x8d 0xc7 0x8b 0x91 0xc2 0xfd 0x40 0xdd 0x2e 0x45 0x4a 0x9f 0xbd}
xmm14 = {0xb1 0xd3 0x37 0xe3 0x76 0x58 0xa6 0x21 0x8b 0x18 0x7b 0x0f 0xce 0x52 0xe4 0xb2}
xmm15 = {0xde 0xa4 0xbc 0x66 0xa9 0xac 0x68 0x20 0xa1 0xee 0x26 0x60 0xa6 0x02 0xdb 0xbd}
Exception State Registers:
trapno = 0x00000003
err = 0x00000000
faultvaddr = 0x0000000101ba8000
(lldb) x/16x `$rax`
error: memory read failed for 0x0
(lldb) register read rax
rax = 0x0000000000000000
I'm attaching the .xcresult file for the test run as it contains the crashes: TestResults.xcresult.zip
To look at the crashes, unzip and then right-click the TestResults.xcresults file and select Show Package Contents. The crashes are in the Attachments folder.
@carllindberg Sorry for summoning you out of the blue, but you are one of the few people that I know that might be able to help me figure this out.
The issue identified by guard malloc was resolved in 662bbeb0fa408d3d6eaeba7b9721caef8be4de9e. The issue identified by UBSan was partially addressed by d00d8f37a97e415c65617edf8521568dc41cb263. Since class_addMethod
still uses the originalIMP, it must not be null:
To ignore this, the test causing this can be annotated with __attribute__((no_sanitize("nullability-arg")))
to skip the check.
Hi Erik, I'm working on a branch of OCMock to add additional quality checks to the project (ASan, TSan, & UBSan). While working on implementing these additional checks when running the unit tests, they uncovered some issues.
TSan Issues
The thread sanitizer found 5 tests involving notification mock objects that all failed with the same error: when verify is called on the mock, you end up with a
Thread 1: EXC_BAD_ACCESS (code=EXC_I386_GPFLT)
. TSan is indicating that there is a memory read error, so I'm wondering if the notification mock is either in the process of being released or is already released sinceOCObserverMockObject
has theautoRemoveFromCenter:
concept.UBSan Issue
The undefined behavior sanitizer found 1 test that exposed a nullability issue in
setupForwarderForSelector:
inOCPartialMockObject
. ThetestStubsMethodImplementation
test inOCMockForwardingTargetTests
indicates that when the forwarder is being setup, theoriginalMethod
is nil, so when you pass that tomethod_getImplementation
, that is not allowed since the method parameter is marked explicitly as nonnull. I'm wondering if you need to return early there or do something similar to a few lines below where you are checking if the type encoding is null.I'd be happy to fix these on my branch where I'm adding these checks in, but I'm unsure of the correct solution.