简体   繁体   English

NSInvocation getArgument NSString/CFString 会导致访问错误

[英]NSInvocation getArgument NSString/CFString will lead to bad access

I had a requirement, to use NSInvocation's我有一个要求,使用 NSInvocation 的

  • (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx; (void)getArgument:(void *)argumentLocation atIndex:(NSInteger)idx;

to get the argument.得到论点。 The argument is primarily NSString, So, in my function:参数主要是NSString,所以,在我的function中:

- (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]];
   ...
}

However I met a double free crash.但是我遇到了双重免费崩溃。 After debugging, I found the issue is that,经过调试,我发现问题是,

because invocation is actually holding a __CFString object, which is malloced on heap, and the length is >= 10, eg '1234567890', so when I call [invocation getArgument:&statKey atIndex:3];因为调用实际上是持有一个__CFString object,它被分配在堆上,并且长度> = 10,例如'1234567890',所以当我调用[invocation getArgument:&statKey atIndex:3]; , the statKey is written with the pointer to 1234567890: , statKey 用指向 1234567890 的指针写入:

for example,例如,

(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  ................

So the newly NSString *statKey is actually is a pointer.所以新的 NSString *statKey 实际上是一个指针。

When the invocation is finished, I will met a crash, like a double free, because they both point to 0x21a1d8bee901当调用完成时,我会遇到崩溃,就像双释放一样,因为它们都指向0x21a1d8bee901

if the string is like [[NSMutableString alloc] initWithString:@'123456789'] , even though this is a CFString, but when calling [invocation getArgument:&statKey atIndex:3] , it will be如果字符串类似于[[NSMutableString alloc] initWithString:@'123456789'] ,即使这是一个 CFString,但在调用[invocation getArgument:&statKey atIndex:3]时,它将是

NSTaggedPointerString * @"123456789" 0x9c98d935e3d914c6.

So I assuem length of 10 of the string is the boundary.所以我假设字符串的长度为 10 是边界。

So I want to ask, how do I fix this?所以我想问,我该如何解决这个问题? I tried [statKey copy], or [invocation retainArguments];, not working.我试过 [statKey copy] 或 [invocation retainArguments];,不工作。 Thanks!谢谢!

It's most likely very similar problem to NSInvocation returns value but makes app crash with EXC_BAD_ACCESS but for [invocation getArgument:...] and not a return value.这很可能与NSInvocation 返回值非常相似,但由于 EXC_BAD_ACCESS 导致应用程序崩溃,但对于[invocation getArgument:...]而不是返回值。
What happens is NSInvocation method is unaware of the value-fit-in-pointer optimised underlying type ( NSTaggedPointerString * ) and as a result ARC attempts to release it.发生的情况是NSInvocation方法不知道值适合指针优化的底层类型( NSTaggedPointerString * ),因此 ARC 试图释放它。

Fix should be:修复应该是:

NSString __unsafe_unretained *statKey;
[invocation getArgument:&statKey atIndex:3];

or:或者:

void *statKey;
[invocation getArgument:&statKey atIndex:3];

Similar problem also described here: https://stackoverflow.com/a/56604328/5329717此处也描述了类似的问题: https://stackoverflow.com/a/56604328/5329717

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM