-
Notifications
You must be signed in to change notification settings - Fork 49
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Hook individual objects #15
Conversation
Class clazz = object_getClass(obj); | ||
Class superclazz = class_getSuperclass(clazz); | ||
do { | ||
let superclassMethod = class_getInstanceMethod(superclazz, _cmd); | ||
let sameMethods = class_getInstanceMethod(clazz, _cmd) == superclassMethod; | ||
if (!sameMethods && !ITKMethodIsSuperTrampoline(superclassMethod)) { | ||
break; | ||
} | ||
clazz = superclazz; | ||
superclazz = class_getSuperclass(clazz); | ||
}while (1); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is not going to work. Let's consider the same situation as in the description above, but now Level3
and Level4
classes override the -sayHello
method.
Also, there is no way to determine if Method uses our trampoline or not, since Method can contain user-defined IMP which can call our trampoline IMP.
Seems like the only correct and efficient way to implement this is to use vm_remap() and PC-relative addressing in the same way as this does original imp_implementationWithBlock
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You're right - this is not a situation the current logic supports. It would be a fun challenge to try how complex a solution with real trampolines work. Happy to take PRs! I add this limitation to the readme for now.
This enables hooking on a per-object instance base, similar to https://github.com/steipete/Aspects.
The strategy here is:
This can be made fully reversible, we can unregister the dynamically created subclass; potentially also reuse. Since we - unlike Aspects - don't use
_objc_msgForward
, no boxing happens, and this approach is fast + safe.I ran into a few Swift compiler crashers:
TODO:
_objc_msgSendSuper2_stret
for non-arm64