-
Notifications
You must be signed in to change notification settings - Fork 495
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
Fix crashes when using Aspects, jsPatch or waxPatch… #27
base: master
Are you sure you want to change the base?
Conversation
…Patch whom hook functions with forwardInvocation:.
Have you deployed this in development, and tried it with instances that has been isa-swizzled e.g. KVO? Would you mind to write a reduced test case for this? I am not quite sure if the implementation is correct, since |
Yup, I know the KVO logic that also created a dynamic subclass on the fly. Okay, I will commit a new test case to show you the issue later. |
In my opinion, I will double check with it later. |
I checked The logic exists in RACSwizzleMethodSignatureForSelector() already. Unless |
…function only if successfully fetched the original class
@andersio Test case committed. Protection logic also committed. |
Oh yeah, just checked again the RAC implementation - |
Got another question though. AFAIU this solves the clash in swizzled |
AFAIK, ObjC IMP swizzling was handled by objc-runtime directly. All hot-patch SDKs can take care of it very well. The main purpose of this PR fix the app crash when we re-implement an IMP function after rac_signalForSelector: is called. (similar to the newly created test case) In practice, I have tested PR in our app project (with waxPatch, jsPatch and KVO logic applied). (locally tested, not yet submitted to AppStore) Hot-patch is used to fix small(really/) issues without re-submit the app. It overrides the OC function by a script function. (jsPatch using javascript, or waxPatch using lua) It's a little bit tricky:
After all, each re-routed native IMP function send to the object will be mapping to the script function. There is the main process of hot-patch~ |
@andersio |
[object rac_signalForSelector:@selector(lifeIsGood:)]; | ||
|
||
// Simulator of hotpatch: | ||
SEL selectorPatched = @selector(methodHotpatch); |
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.
Mind to replicate the test case for the case where the intercepted selector by rac_signalForSelector
, i.e. lifeIsGood:
, is also the one being hot-patched?
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.
Oops, I missed it.
The short answer is NO, currently.
Hot-patch implements forwardInvocation:
on original class. But the calling process of lifeIsGood:
will be intercepted by RACForwardInvocation
on dynamic subclass
:
BOOL matched = RACForwardInvocation(self, invocation);
if (matched) return;
Good news is, it can be identified by checking (aliasSelector on dynamic subclass
!= originalSelector on original class
) to know whether it has been hot-patched (same situation with method swizzle) or not.
One more step forward, we can just checking (originalSelector on original class
== _objc_msgForward
) to know it. But I don't recommend it.
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.
It's done.
@andersio IMP-swizzling supported. CI reported a build error... what's going on? Looks like a bug of CI, the xcodebuild did not started on arch x86_64~ |
@andersio CI Rebuilt finished. ... no code changed |
Thank you for all the information and the test cases, which do help as I am interested in searching for a potentially cleaner approach. /cc @ReactiveCocoa/reactiveobjc |
Thanks for your advice and time :) |
Just found that it had been brought up before, and had been well explained why it wasn't addressed. With all the attempts I've done so far, I don't feel the situation has changed. I would let others determine if this should be fixed. Meanwhile, the advice is either avoiding @mdiep @ReactiveCocoa/reactivecocoa |
I am definitely not a swizzling expert. I think fixing it is great if we can, but we should be confident that we haven't broken anything. |
Sure, maybe few days later? |
Sure, thanks! |
Apple sent us a warning mail about hot-patch More discusse in other repo The patch logic testing is meaningless since it is disallowed by Apple. But I will test if this logic working with Aspects |
Well perhaps it still worths a test in terms of interoperability. That's said I do not expect it to be sufficient with work only on RAC's end. |
…t-tabs ReactiveObjC: convert tabs to spaces.
…whom hook functions with forwardInvocation:.
Forwarded PR
In common case, it's efficiently if we preserving the implementation of forwardInvocation: in rac_signalForSelector: and using it later.
But the preserved IMP should be updated if it has been replaced after calling rac_signalForSelector:.
Holding and invoke the old implementation may leads to an unexpected situation if an function added with jsPatch or waxPatch. (infinite loops, or crashes)
Library such as Aspects, jsPatch or waxPatch will swizzle forwardInvocation: at any time during the app running, probably.
P.S. This is an issue reported at jsPatch's issue list
And I decided to make this PR to RAC after reviewed all related codes between RAC and jsPatch.