Giter Site home page Giter Site logo

bigbang's Issues

double release导致崩溃 和 内存泄露

double release:
从 -forwardInvocation: 里的 NSInvocation 对象取参数值时,若参数值是id类型,我们会这样取:

id arg;
[invocation getArgument:&arg atIndex:i];
但这样的写法会导致 crash,这是因为 id arg 在ARC下相当于 __strong id arg,若这时在代码显式为 arg 赋值,根据 ARC 的机制,会自动插入一条 retain 语句,然后在退出作用域时插入 release 语句:

  • (void)method {
    id arg = [SomeClass getSomething];
    // [arg retain]
    ...
    // [arg release] 退出作用域前release
    }
    但我们这里不是显式对 arg 进行赋值,而是传入 -getArgument:atIndex: 方法,在这里面赋值后 ARC 没有自动给这个变量插入 retain 语句,但退出作用域时还是自动插入了 release 语句,导致这个变量多释放了一次,导致 crash。解决方法是把 arg 变量设成 __unsafe_unretained 或 __weak,让 ARC 不在它退出作用域时插入 release 语句即可:

__unsafe_unretained id arg;
[invocation getReturnValue:&arg];
还可以通过 __bridge 转换让局部变量持有返回对象,这样做也是没问题的:

id returnValue;
void *result;
[invocation getReturnValue:&result];
returnValue = (__bridge id)result;

内存泄露:
当 NSInvocation 调用的是 alloc 时,返回的对象并不会释放,造成内存泄露,只有把返回对象的内存管理权移交出来,让外部对象帮它释放才行:

id returnValue;
void *result;
[invocation getReturnValue:&result];
if ([selectorName isEqualToString:@"alloc"] || [selectorName isEqualToString:@"new"] || [selectorName isEqualToString:@"copy"] || [selectorName isEqualToString:@"mutableCopy"]) {
returnValue = (__bridge_transfer id)result;
} else {
returnValue = (__bridge id)result;
}
这是因为 ARC 对方法名有约定,当方法名开头是 alloc / new / copy / mutableCopy 时,返回的对象是 retainCount = 1 的,除此之外,方法返回的对象都是 autorelease 的,按上一节的说法,对于普通方法返回值,ARC 会在赋给 strong 变量时自动插入 retain 语句,但对于 alloc 等这些方法,不会再自动插入 retain 语句:

id obj = [SomeObject alloc];
//alloc 方法返回的对象 retainCount 已 +1,这里不需要retain

id obj2 = [SomeObj someMethod];
//方法返回的对象是 autorelease,ARC 会再这里自动插入 [obj2 retain] 语句
而 ARC 并没有处理非显式调用时的情况,这里动态调用这些方法时,ARC 都不会自动插入 retain,这种情况下,alloc / new 等这类方法返回值的 retainCount 是会比其他方法返回值多1的,所以需要特殊处理这类方法。

具体怎么用?

在didFinishLaunchingWithOptions里调用了[BigBang hookClass:@"BaseMsgContentViewController"];

但是进入微信聊天界面没有出现任何log呢?

It would be better to use class_replaceMethod

class_addMethod(hookClass, @selector(forwardInvocation:), forwardInvocationImpl, "v@:@");

If the class has overridden the -[WhateverClass forwardInvocation:] method, then calling the class_addMethod function will lead to fatal error. However, class_replaceMethod will act like class_addMethod if there isn't such -[WhateverClass forwardInvocation:] method, or replace the method as expected if there is one.

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.