当前位置: 代码网 > it编程>App开发>苹果IOS > ios开发 try-catch引起的野指针问题排查

ios开发 try-catch引起的野指针问题排查

2024年05月19日 苹果IOS 我要评论
1、野指针问题【exc_bad_access (sigsegv) / kern_invalid_address]possible zombie in call: function: objc_rele

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完毕,所以这次就会触发重复释放崩溃引起野指针问题,

但如果exceptiontestexpectionobj对象的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野指针的资料请关注代码网其它相关文章!

(0)

相关文章:

版权声明:本文内容由互联网用户贡献,该文观点仅代表作者本人。本站仅提供信息存储服务,不拥有所有权,不承担相关法律责任。 如发现本站有涉嫌抄袭侵权/违法违规的内容, 请发送邮件至 2386932994@qq.com 举报,一经查实将立刻删除。

发表评论

验证码:
Copyright © 2017-2025  代码网 保留所有权利. 粤ICP备2024248653号
站长QQ:2386932994 | 联系邮箱:2386932994@qq.com