1、野指针问题
【exc_bad_access (sigsegv) / kern_invalid_address]
possible zombie in call: function: objc_releaseparam 1: 0x157f2a740 originated at or in a subcall of unknown, cannot find symb
如有以下崩溃栈可以怀疑是在dealloc中直接或间接使用了@try{} @catch{}
2、崩溃栈
libobjc.a.dylib _objc_release() corefoundation -[__nsdictionaryi dealloc]() corefoundation -[nsexception dealloc]() libobjc.a.dylib autoreleasepoolpage::releaseuntil(objc_object**)() libobjc.a.dylib _objc_autoreleasepoolpop() ...... ......

3、场景复现代码
#import "viewcontroller.h"
@interface testexpectionobj : nsobject
@end
@implementation testexpectionobj
- (void)dealloc {
@try {
[self setvalue:@"test" forkey:@"testkey"];
} @catch (nsexception *exception) {
nslog(@"%@", exception);
}
}
@end
@implementation viewcontroller
- (void)viewdidload {
[super viewdidload];
// do any additional setup after loading the view.
[testexpectionobj new];
}
@end
4、问题分析
在dealloc使用try-catch并触发catch时,会生成nsexception对象,exception结构如下
exception : nsexception {
userinfo: nsdictionary {
nstargetobjectuserinfokey = "<testexpectionobj: 0x6000038ac3e0>";
}
}
故exception会强引用testexpectionobj对象,并且exception一般都是类方法生成会自动加入到autoreleasepool,所以dealloc执行完后testexpectionobj对象已经释放(因为在dealloc方法中在强引用当前对象没法终止当前对象的释放,引用计数增加与否已无意义),所以exception.userinfo中的testexpectionobj对变成野对象。
当autoreleasepool到达周期释放时就对调用release exception & userinfo,字典userinfo释放时会也会相应的释放key/value,故nstargetobjectuserinfokey = "<testexpectionobj: 0x6000038ac3e0>"又调用一次release,因为之前已经dealloc完毕,所以这次就会触发重复释放崩溃引起野指针问题,
但如果exception在testexpectionobj对象的dealloc方法执行完之前释放就不会出现问题。
5、上报可能引起野指针崩溃栈
#import <jrswizzle/jrswizzle.h>
@implementation nsexception (exceptiontestsunztobj)
+ (void)load {
static dispatch_once_t oncetoken;
dispatch_once(&oncetoken, ^{
[self jr_swizzlemethod:nsselectorfromstring(@"dealloc")
withmethod:@selector(intercept_dealloc)
error:nil];
});
}
- (void)intercept_dealloc {
bool iscontaindealloc = no;
nsmutablestring *symblos = [nsmutablestring string];
for (nsstring *sym in self.callstacksymbols) {
[symblos appendformat:@"%@\n", sym];
if ([sym containsstring:@" dealloc]"]) {
iscontaindealloc = yes;
}
}
// 把 symblos上报给自己的apm平台
[apm report:@"ttreportexceptioncallstacksymbols" withvalue:symblos];
[apm report:@"ttreportexceptionreason" withvalue:self.reason?:@"null"];
if (iscontaindealloc) {
// 本地log打印,需符号化
ttlocallog("nsexception:throws:dealloc:ttreport", {
@"name": self.name?:@"",
@"reason": self.reason?:@"",
@"callstacksymbols": symblos
});
// 延迟保证数据写完在释放
__unsafe_unretained nsexception *demoself = self;
dispatch_after(dispatch_time(dispatch_time_now, (int64_t)(1.0 * nsec_per_sec)), dispatch_get_main_queue(), ^{
[demoself intercept_dealloc];
});
return;
}
[self intercept_dealloc];
}
@end
注:在dealloc中使用@try{} @catch{}可能会引起难以排查的野指针崩溃
使用@try-@catch后
[<testexpectionobj 0x600000714220> setvalue:forundefinedkey:]: this class is not key value coding-compliant for the key testkey. ( 0 corefoundation 0x0000000102a93604 __exceptionpreprocess + 242 1 libobjc.a.dylib 0x0000000102943a45 objc_exception_throw + 48 2 corefoundation 0x0000000102a9329c -[nsexception init] + 0 3 foundation 0x00000001034f2354 -[nsobject(nskeyvaluecoding) setvalue:forkey:] + 315 4 expectiondemo 0x00000001023cae52 -[testexpectionobj dealloc] + 50 5 libobjc.a.dylib 0x00000001029417b7 _zn11objc_object17sidetable_releaseebb + 177 6 expectiondemo 0x00000001023caf58 -[viewcontroller viewdidload] + 72 7 uikitcore 0x000000010f3ce3bc -[uiviewcontroller _sendviewdidloadwithappearanceproxyobjecttaggingenabled] + 88 8 uikitcore 0x000000010f3d2dbf -[uiviewcontroller loadviewifrequired] + 1193 9 uikitcore 0x000000010f3d319a -[uiviewcontroller view] + 27 10 uikitcore 0x000000010fbdb00a -[uiwindow addrootviewcontrollerviewifpossible] + 305 11 uikitcore 0x000000010fbda6fe -[uiwindow _updatelayerorderingandsetlayerhidden:actionblock:] + 230 12 uikitcore 0x000000010fbdb6d6 -[uiwindow _sethidden:forced:] + 409 13 uikitcore 0x000000010fbee204 -[uiwindow _mainqueue_makekeyandvisible] + 47 14 uikitcore 0x000000010fe605f6 -[uiwindowscene _makekeyandvisibleifneeded] + 202 15 uikitcore 0x000000010ef0fb8f +[uiscene _sceneforfbsscene:create:withsession:connectionoptions:] + 1591 16 uikitcore 0x000000010fb98fbd -[uiapplication _connectuiscenefromfbsscene:transitioncontext:] + 1299 17 uikitcore 0x000000010fb99471 -[uiapplication workspace:didcreatescene:withtransitioncontext:completion:] + 301 18 uikitcore 0x000000010f613afe -[uiapplicationsceneclientagent scene:didinitializewithevent:completion:] + 355 19 frontboardservices 0x0000000107090cdd -[fbsscene _calloutqueue_agent_didcreatewithtransitioncontext:completion:] + 415 20 frontboardservices 0x00000001070bd216 __94-[fbsworkspacescenesclient createwithsceneid:groupid:parameters:transitioncontext:completion:]_block_invoke.180 + 102 21 frontboardservices 0x000000010709f0ef -[fbsworkspace _calloutqueue_executecalloutfromsource:withblock:] + 209 22 frontboardservices 0x00000001070bcdf5 __94-[fbsworkspacescenesclient createwithsceneid:groupid:parameters:transitioncontext:completion:]_block_invoke + 352 23 libdispatch.dylib 0x0000000103c0ba5b _dispatch_client_callout + 8 24 libdispatch.dylib 0x0000000103c0e93b _dispatch_block_invoke_direct + 295 25 frontboardservices 0x00000001070e3da3 __fbsserialqueue_is_calling_out_to_a_block__ + 30 26 frontboardservices 0x00000001070e3c99 -[fbsserialqueue _targetqueue_performnextifpossible] + 174 27 frontboardservices 0x00000001070e3dcb -[fbsserialqueue _performnextfromrunloopsource] + 19 28 corefoundation 0x0000000102a004a7 __cfrunloop_is_calling_out_to_a_source0_perform_function__ + 17 29 corefoundation 0x0000000102a0039f __cfrunloopdosource0 + 180 30 corefoundation 0x00000001029ff8ce __cfrunloopdosources0 + 340 31 corefoundation 0x00000001029f9f68 __cfrunlooprun + 871 32 corefoundation 0x00000001029f9704 cfrunlooprunspecific + 562 33 graphicsservices 0x00000001071e3c8e gseventrunmodal + 139 34 uikitcore 0x000000010fb9765a -[uiapplication _run] + 928 35 uikitcore 0x000000010fb9c2b5 uiapplicationmain + 101 36 expectiondemo 0x00000001023cb1be main + 110 37 dyld 0x00000001025e6f21 start_sim + 10 38 ??? 0x00000001091ce4fe 0x0 + 4447855870 )
这种崩溃信息使用nssetuncaughtexceptionhandler()是抓不到的
以上就是ios开发 try-catch引起的野指针问题排查的详细内容,更多关于ios开发try-catch野指针的资料请关注代码网其它相关文章!
发表评论