我有一个要求,使用 NSInitation 的
- (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx;
得到论证。参数主要是 NSString,所以,在我的函数中:
- (void)forwardInvocation:(NSInvocation *)invocation {
[invocation retainArguments];
NSString *biz;
[invocation getArgument:&biz atIndex:2];
NSString *statKey;
[invocation getArgument:&statKey atIndex:3];
getOriginalSelectorName:rawSelName blockArgCount:blockArgCount];
allowed = [self allowPerformSensitiveSelector:rawSelector biz:[biz copy] statKey:[statKey copy]];
...
}
然而我遇到了双重免费崩溃。经过调试,我发现问题是,
因为调用实际上持有一个 __CFString 对象,该对象在堆上分配,并且长度 >= 10,例如'1234567890',所以当我调用
[invocation getArgument:&statKey atIndex:3];
时,statKey会被写入指向1234567890的指针:
例如,
(lldb) p statKey // set by `getArgument:&statKey`
(__NSCFString *) $0 = 0x00000002839492e0 @"1234567890"
(lldb) mem read 0x00000002839492e0
0x2839492e0: 01 e9 be d8 a1 21 00 00 8c 07 00 00 04 00 00 00 .....!..........
0x2839492f0: 0a 31 32 33 34 35 36 37 38 39 30 00 00 00 00 00 .1234567890.....
(lldb) p statKey // outer one, passed from method parameters, resided in invocation
(__NSCFString *) $1 = 0x000000028372f780 @"1234567890"
(lldb) mem read 0x000000028372f780
0x28372f780: 01 e9 be d8 a1 21 00 00 ad 07 00 00 04 00 00 00 .....!..........
0x28372f790: e0 fd 97 83 02 00 00 00 0a 00 00 00 00 00 00 00 ................
所以新的 NSString *statKey 实际上是一个指针。
当调用完成后,我会遇到崩溃,就像双重释放一样,因为它们都指向
0x21a1d8bee901
如果字符串是
[[NSMutableString alloc] initWithString:@'123456789']
,即使这是一个CFString,但是当调用[invocation getArgument:&statKey atIndex:3]
时,它会是
NSTaggedPointerString * @"123456789" 0x9c98d935e3d914c6.
所以我假设字符串的长度 10 是边界。
所以我想问一下,如何解决这个问题?我尝试了 [statKey copy] 或 [involution keepArguments];,但不起作用。谢谢!
这很可能与 NSInvocation 返回值非常相似,但会导致应用程序因 EXC_BAD_ACCESS 崩溃,但对于
[invocation getArgument:...]
而不是返回值。NSInvocation
方法不知道值适合指针优化的底层类型 (NSTaggedPointerString *
),因此 ARC 尝试释放它。
修复应该是:
NSString __unsafe_unretained *statKey;
[invocation getArgument:&statKey atIndex:3];
或:
void *statKey;
[invocation getArgument:&statKey atIndex:3];
此处也描述了类似的问题:https://stackoverflow.com/a/56604328/5329717
[更新] 我知道这是一个很晚的回复,但苹果最近也回复我说,他们已经修复了有关此主题的文档(修复该文档需要一年时间,是的,苹果干得好)
引用:
文档已更新,请在此验证: https://developer.apple.com/documentation/foundation/nsin Vocation/1437832-getreturnvalue https://developer.apple.com/documentation/foundation/nsin Vocation/1437830-getargument
我可以看到最近的 Xcode 及其文档已经更新,因此我们知道我们需要自己处理所有权。有一个重要警告,您不能轻易错过。