jezzmemo / JJException

Protect the objective-c application(保护App不闪退)
MIT License
1.63k stars 268 forks source link

NSObject+KVOCrash:EXC_BAD_ACCESS KERN_INVALID_ADDRESS #83

Open LuckyCat7848 opened 4 years ago

LuckyCat7848 commented 4 years ago

Describe the bug NSObject+KVOCrash.m line 200-[JJObserverContainer cleanObservers] + 200 NSObject+SwizzleHook.m line 151__jj_swizzleDeallocIfNeeded_block_invoke_3 + 151

To Reproduce Steps to reproduce the behavior: 未复现。但是刚集成,后台收集到太多如上崩溃信息。辛苦早点解决

Please complete the following information

LuckyCat7848 commented 4 years ago

除上面地方的崩溃外,还有: NSObject+KVOCrash.m line200 NSObject+KVOCrash.m line247 NSObject+KVOCrash.m line244 NSObject+KVOCrash.m line91 NSObject+KVOCrash.m line90 NSObject+KVOCrash.m line89 NSObject+KVOCrash.m line110 @jezzmemo

jezzmemo commented 4 years ago

@LuckyCat7848 建议先关掉KVO的的异常处理

LuckyCat7848 commented 4 years ago

@jezzmemo line 200 行 可复现,whichObject的设计问题。

  1. 一个观察者 A 对应两个被观察者对象时 whichObject 只设置了第一次,为第一个被观察者对象 B;
  2. 第一个被观察者对象 B 释放了;
  3. 观察者 A 要 cleanObserves 的时候,去 remove 第二个被观察者对象 C,self.whichObject 崩溃(因为 whichObject 其实是 B 已经释放了)。

其他行数还未确定是否是 whichObject 的原因。

jezzmemo commented 4 years ago

@LuckyCat7848 收到,我稍后将尽快处理

jezzmemo commented 4 years ago

@LuckyCat7848 麻烦能否到fix/kvoBug81这个分支下,帮我确认下有没问题,没问题我再发到主分支和版本

LuckyCat7848 commented 4 years ago

@jezzmemo 已确定问题还未解决,测试代码和详细描述通过 pull request到fix/kvoBug81分支,可参考,辛苦解决💪

jezzmemo commented 4 years ago

@LuckyCat7848 麻烦合并下最新的fix/kvoBug81分支,你当前的crash解决了!

LuckyCat7848 commented 4 years ago

@jezzmemo 不行的哦,先销毁第二个对象的话还是会Crash,可以参考下我的测试代码哦

https://github.com/LuckyCat7848/JJException/tree/fix/kvoBug81

[self presentViewController:push animated:YES completion:^{ self.kvoObject2 = nil; }];

jezzmemo commented 4 years ago

麻烦再merge fix/kvoBug81分支,帮我检查下,谢谢

LuckyCat7848 commented 4 years ago

@jezzmemo 该情况已解决,无论先释放kvoObject或kvoObject2都没有问题了!👏👏

测试了还有一种情况会Crash:两个对象的KeyPath一样,先释放第一个,会Crash,没看懂原因。 测试代码请参考 https://github.com/LuckyCat7848/JJException/tree/fix/kvoBug81。 复现步骤:点击Start Guard——>点击Test KVO——>点击dismiss,如果不崩溃,重复“点击Test KVO——>点击dismiss”。 辛苦了!🙏

LuckyCat7848 commented 4 years ago

@jezzmemo 我觉得observer和whichObject的属性应该是weak,改成weak后上面的Crash可以解决,你可以改下试试。辛苦看下没有问题的话可以重新打个版本哦

jezzmemo commented 4 years ago

@LuckyCat7848 我明白你的意思,我最近在整体重新看看,如果我调整好了,麻烦你帮我再次确认下谢谢。

jezzmemo commented 4 years ago

@LuckyCat7848 这里解释下,当初没有选weak方案,是因为在我在hook dealloc后,如果weak后,到达dealloc方法时,对象已经被置空了,所以为了保证JJException能顺利删除kvo,用了assign来手动控制,所以有了现在的问题,我已经修复了,麻烦再帮我确认下,谢谢,fix/kvoBug81

LuckyCat7848 commented 4 years ago

@jezzmemo 谢谢解答,这几天我也尝试改动,参考了一些文章有了如下分支的改动。https://github.com/LuckyCat7848/JJException/tree/fix/kvoBug81

  1. 主要把JJObserverContainer简化掉,只保留了KVOObjectContainer。如果有空的话可以看下请多指教哦;
  2. 其他问题已解决,还有一个额外发现,可以hook下observeValueForKeyPath:ofObject:change:context:方法,解决观察者没有实现观察方法的问题。(也是参考了其他文章和Demo看到的,觉得可以是个优化。)

解决完后打个新release包哦,辛苦作者了!

jezzmemo commented 4 years ago

好的,我来review,看看是否合适,如果效果不错,我将merge进来

jezzmemo commented 4 years ago

@LuckyCat7848 代码我review过了,总体没什么问题,我就把几处代码规范调整了下,然后把注释调整成英文的了,已经发布到0.2.8,由于你没有发PR,所以我在Release note里专门提到你了,帮我优化了这部分代码,https://github.com/jezzmemo/JJException/releases/tag/0.2.8

LuckyCat7848 commented 4 years ago

@jezzmemo 谢谢作者,我的改动已经放在项目里两天了,虽然数据好多了,但是还是从后台看到一些崩溃数据,而且多数和AVFoundation有关。暂时没有固定复现,我会尝试复现和修复,希望大神有空能帮忙彻底解决掉问题呀😭 还有一点就是,可以考虑能不能和NSArray等一样加入拦截到问题的上报,才能看到KVOCrash的作用数据呢,否则虽然有用也只看到Crash了😭😭😭😭😭😭

本次Crash情况如下(行数以JJException当前master代码为准): NSObject+KVOCrash.m line206 // 多数崩溃集中在这里 NSObject+KVOCrash.m line140 NSObject+KVOCrash.m line214 NSObject+KVOCrash.m line112 NSObject+KVOCrash.m line53 NSObject+KVOCrash.m line60

部分日志: com.apple.avfoundation.playerlayer.configuration

0 libdispatch.dylib _dispatch_semaphore_dispose$VARIANT$armv81.cold.1 + 40 1 libdispatch.dylib _dispatch_semaphore_signal_slow$VARIANT$armv81 + 62 2 libdispatch.dylib _dispatch_dispose$VARIANT$armv81 + 116 3 CamScanner_Lite NSObject+KVOCrash.m - 第 140 行 -[KVOObjectContainer dealloc] + 140 4 libobjc.A.dylib _base_objc_setAssociatedObject(objc_object, void const, objc_object*, objc_AssociationPolicy) + 980 5 CamScanner_Lite NSObject+KVOCrash.m - 第 206 行 -[NSObject(KVOCrash) hookAddObserver:forKeyPath:options:context:] + 206 6 AVFoundation -[AVPlayerItem addObserver:forKeyPath:options:context:] + 284

jezzmemo commented 4 years ago

我解释下为什么KVO不能上报异常信息,因为JJException是在dealloc之前清理了KVO信息,所以当前不知道这个信息是多余的,因为有可能开发者后面会自己清理,所以导致不能准确的上报KVO异常,我刚刚本地播放MP4,并没有异常,你的业务里是不是有AV相关的功能,是不是可以重点试试?

gyyxiaogao commented 4 years ago

图片