Navigation Menu

Skip to content
This repository has been archived by the owner on Jan 17, 2023. It is now read-only.

AWS analytics for iOS app crash in AFNetworking #2743

Merged
merged 1 commit into from Oct 13, 2015
Merged

AWS analytics for iOS app crash in AFNetworking #2743

merged 1 commit into from Oct 13, 2015

Conversation

kcharwood
Copy link
Contributor

I have integrated AWS analytics(2.1.1), Facebook SDK(4.1.0) and AFNetworking(2.5.4) in one application. but app is crashing while launching itself

tried many ways to resolve this

  1. commented line number 357 in screen shot its working fine
  2. downgrade to AFNetworking 2.4.0 working fine.

screen shot 2015-05-22 at 4 55 13 pm

@kcharwood
Copy link
Contributor

What version of iOS is this showing up on? And can you breakpoint there and print out self to show what class that is?

Thanks!

@care2achieve
Copy link
Author

iOS - 8.3
self is AFURLSessionTaskSwizzling

@kcharwood
Copy link
Contributor

Well thats interesting. _AFURLSessionTaskSwizzling is just a shell class and is never actually be alloc/inited and used anywhere. It also should have a leading underscore if you po it from the console. Those methods implementations are extracted at runtime and added to the NSURLSessionTask subclasses, which do respond to state.

Can you print out the console results of po'ing self? There is no code path in AFNetworking that would have _AFURLSessionTaskSwizzling alloc/init'ed running that instance method.

@care2achieve
Copy link
Author

please check screen shot for po result, and class name on mouse hover, meanwhile i will try to get crash log.
screen shot 2015-05-25 at 10 22 17 am

@kcharwood
Copy link
Contributor

Do you have an example project you should push up demonstrating this problem?

@kcharwood
Copy link
Contributor

Any more news on this @care2achieve?

@kcharwood
Copy link
Contributor

@care2achieve feel free to reopen this if you can provide any more reproducible evidence.

Cheers!

@kcharwood kcharwood closed this Jun 4, 2015
@care2achieve
Copy link
Author

Sorry i could not get a chance to work on this, please check the code at following link.
https://drive.google.com/file/d/0B8-L06_qfTBGWlJmR2liQ3BBZ0U/view?usp=sharing

@kcharwood
Copy link
Contributor

Have you isolated this to AWS? I'm wondering if it is related to Fabric. It's possible both libraries are swizzling resume, but I don't have source access to Fabric.

@kcharwood kcharwood reopened this Jun 5, 2015
@kcharwood
Copy link
Contributor

screen shot 2015-06-05 at 8 58 28 am

@kcharwood
Copy link
Contributor

So I've confirmed that sometime between AFNetworking setting up the swizzle map, and the first task actually running, someone else is also mucking with the swizzle stack. My current suspicion is Fabric.

@care2achieve
Copy link
Author

Just played with sample code sent you, if i comment Roximity Init method its working fine, it might be causing this issue,

@kcharwood
Copy link
Contributor

@care2achieve if I comment out everything in the app delegate except Fabric, the problem persists. We need a cleaner example that starts to isolate some of these things. Not sure I'll have time to look further into this until after WWDC.

@mattmassicotte
Copy link

Fabric and Crashlytics will use NSURLSession for all networking on OSes where it is available. Fabric does no swizzling of any kind. Crashlytics does no swizzling on iOS, but does swizzle one method on NSApplication on OS X (it has nothing to do with networking). Fabric does no load-time initialization (+initialize, +load, or C++ static initializers), Crashlytics has one static initializer, but again, it has nothing to do with networking.

Let me know if I can help any more.

@kcharwood
Copy link
Contributor

Thanks for confirmed this Matt. I assume if Fabric or Crashlytics were causing the collision, we would have heard it about by now.

I'll keep on carving up this example project when I get time, and if i see anything that looks weird on your front I'll keep you posted.

Hope to see you next week 🍻

@soleares
Copy link

We're seeing the same crash #2796 on iOS 8.1-8.3. We use Fabric/Crashlytics and AWS 2.1.2 along with a number of other dependencies. It looks like Fabric/Crashlytics is already absolved.

I looked through all of our dependencies and found swizzling in AWS and Bolts (an AWS dependency) but only in test classes. We only use the AWSCore and AWSS3 frameworks but have the other frameworks added to our project.

Here are my searches:

AWS SDK

AWS SDK Dependencies (w/ swizzling)

AWS SDK Dependencies (no swizzling)

@com314159
Copy link

I have also integrated fabric, and many other SDK:
image

image

that all is our sdks , some is not open sources sdk.

@rotemdoron
Copy link

any news on this? cant get our app running after installing AFNetworking 2.5.4, same collision with Fabric

@rotemdoron
Copy link

so the only thing i mangaed to do to solve this, is by downgrading AFNetworking pod to 2.5.3, if it helps anyone.

@zhigang1992
Copy link

diff --git a/AFNetworking/AFURLSessionManager.m b/AFNetworking/AFURLSessionManager.m
index 11e8d38..2eae784 100644
--- a/AFNetworking/AFURLSessionManager.m
+++ b/AFNetworking/AFURLSessionManager.m
@@ -318,7 +318,7 @@ static NSString * const AFNSURLSessionTaskDidSuspendNotification = @"com.alamofi
          */
 #pragma GCC diagnostic push
 #pragma GCC diagnostic ignored "-Wnonnull"
-        NSURLSessionDataTask *localDataTask = [[NSURLSession sessionWithConfiguration:nil] dataTaskWithURL:nil];
+        NSURLSessionDataTask *localDataTask = [[NSURLSession sessionWithConfiguration:nil] uploadTaskWithStreamedRequest:nil];
 #pragma clang diagnostic pop
         IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([_AFURLSessionTaskSwizzling class], @selector(af_resume)));
         Class currentClass = [localDataTask class];

This seems to fix it, but I'm not sure why...

@neildaniels
Copy link

I am having this issue as well, but we don't use any AWS dependency. However, we do have a dependency that build its own version of AFNetworking. It's still using an old version of AFNetworking though and has the following in its AFURLSessionManager.m (which you should notice is very different than what this file currently has):

@implementation NSURLSessionDataTask (_AFStateObserving)

+ (void)load {
    static dispatch_once_t onceToken;
    dispatch_once(&onceToken, ^{
        NSURLSessionDataTask *dataTask = [[NSURLSession sessionWithConfiguration:nil] dataTaskWithURL:nil];
        Class taskClass = [dataTask superclass];

        af_addMethod(taskClass, @selector(af_resume),  class_getInstanceMethod(self, @selector(af_resume)));
        af_addMethod(taskClass, @selector(af_suspend), class_getInstanceMethod(self, @selector(af_suspend)));
        af_swizzleSelector(taskClass, @selector(resume), @selector(af_resume));
        af_swizzleSelector(taskClass, @selector(suspend), @selector(af_suspend));

        [dataTask cancel];
    });
}

At compile-time, the dependency actually renames AFNetworking classes/symbols and prefixes them to avoid conflicts. That's "safe enough" for now, but now with two different versions of AFNetworking sort of stepping on each other, this crash happens.

I suspect one your dependencies has a pre-compiled version of AFNetworking that's conflicting with your version.

@redfearnk
Copy link

I'm getting a EXC_BAD_ACCESS crash on _AFURLSessionTaskSwizzling's load method on line 329:

#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnonnull"
        NSURLSessionDataTask *localDataTask = [[NSURLSession sessionWithConfiguration:nil] dataTaskWithURL:nil];
#pragma clang diagnostic pop
        IMP originalAFResumeIMP = method_getImplementation(class_getInstanceMethod([_AFURLSessionTaskSwizzling class], @selector(af_resume)));
        Class currentClass = [localDataTask class];

Anyone also seeing this?

@stefanfisk
Copy link

I am also seeing this in an iOS project which is using AFNetworking 2.6, and which amongst other suspects includes Fabric.

@mattmassicotte
Copy link

@stefanfisk Fabric is just simple user of NSURLSession. There's nothing tricky going on internally. What are you seeing that makes you think it could be related?

@stefanfisk
Copy link

Yeah, so I might have skimmed through the middle of this long thread where ya'll absolved them from any and all blame...

@mattmassicotte
Copy link

@stefanfisk just to be clear - I'm on the Fabric team. I don't think it has been proven Fabric is just a victim. Even though we're pretty sure it is unrelated, our team would really like to see evidence that it could be a cause. And, if we can help out some other way (such as enumerating the NSURLSession APIs being used), we'd be happy to do so.

@neildaniels
Copy link

@kcharwood We ended up updating our dependency’s version of AFNetworking to be the same as our main project’s and this issue went away.

My theory also (seemingly) explains why @zhigang1992 workaround works for him. It switched away from using a “data task” which is what was being swizzled by the old version of AFNetworking.

@bixbarton
Copy link

@mattmassicotte which version of AFNetworking does Fabric run with? Is it 2.6.0? This is bizarre, if I build with Xcode 6.4 this problem doesn't appear, it only happens when building with Xcode 7. And yes, I have NsAppTransportSecurity in the plist.

@bixbarton
Copy link

Exception here...
image

Next level in...
image

Next-next level in...
image

@mattmassicotte
Copy link

@bixbarton Fabric does not use AFNetworking

@bixbarton
Copy link

Well that's a nail in the coffin to that line of investigation! Thanks matt!

@bixbarton
Copy link

Also - I only get this problem when doing a Test. Run is fine.

@kcharwood
Copy link
Contributor

Ya I haven't believed there was a conflict with Fabric for a while now.

@bixbarton Do you get any warnings in your console when running tests about AFNetworking being included in the target more than once?

@bixbarton
Copy link

@kcharwood - yes! It does warn that, why?

@kcharwood
Copy link
Contributor

In this case AFNetworking is being added twice to your target (most likely through a cocoapods library and maybe having the source added directly?)

Regardless, thats the problem. Both classes get loaded, so the swizzling happens twice, resulting in the error. I've put a little thought into how to guard against that, but dont have it flushed out yet.

@bixbarton
Copy link

@kcharwood I am using Cocoapods. It looks all the pods are being added twice. Trying to figure out why. Doesn't do this in Xcode 6.4, only Xcode 7

@bixbarton
Copy link

objc[50967]: Class AFURLSessionManager is implemented in both /Users/bixbarton/Library/Developer/CoreSimulator/Devices/2434614A-41B8-4638-B6F4-0F3F50BB15E4/data/Containers/Bundle/Application/E0F5186C-47FB-4458-AAC3-C0F4A681EC93/Dennis.app/Dennis and /Users/bixbarton/Library/Developer/Xcode/DerivedData/DennisMobile-eoemdjabqkxovmfnwptgjfgahfhv/Build/Products/CodeCoverage-iphonesimulator/DennisMobile Tests.xctest/DennisMobile Tests. One of the two will be used. Which one is undefined.

@kcharwood
Copy link
Contributor

So reviewing my code again, I think I found an issue that might help here.

Currently, we have the following:

if (classResumeIMP != superclassResumeIMP &&
    originalAFResumeIMP != classResumeIMP) {
    [self swizzleResumeAndSuspendMethodForClass:currentClass];
}
+ (void)swizzleResumeAndSuspendMethodForClass:(Class)class {
    Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
    Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));

    af_addMethod(class, @selector(af_resume), afResumeMethod);
    af_addMethod(class, @selector(af_suspend), afSuspendMethod);

    af_swizzleSelector(class, @selector(resume), @selector(af_resume));
    af_swizzleSelector(class, @selector(suspend), @selector(af_suspend));
}

Technically, the first code block should prevent the infinite recursion from happening, specifically the originalAFResumeIMP != classResumeIMP check. But that makes the assumption that there is only one _AFURLSessionTaskSwizzling class loaded. If that class gets loaded twice, that assumption is out the window (a dispatch_once wouldn't even work there).

af_addMethod returns a Boolean indicating whether or not the method was added to the class. Currently, we aren't checking that. In this case where AFNetworking gets loaded more than once (most likely do to some sort of compiled dependency), that method would return NO the second time we attempt to add the selector to the NSURLSessionTask classes, but we still do the swizzle anyway. If that happens, we end up in the infinite loop.

If were just to use the result of that af_addMethod call as an additional guard to do the swizzle, I think that would prevent this problem.

We would end up with something like this:

+ (void)swizzleResumeAndSuspendMethodForClass:(Class)class {
    Method afResumeMethod = class_getInstanceMethod(self, @selector(af_resume));
    Method afSuspendMethod = class_getInstanceMethod(self, @selector(af_suspend));

    if (af_addMethod(class, @selector(af_resume), afResumeMethod)) {
        af_swizzleSelector(class, @selector(resume), @selector(af_resume));
    }

    if (af_addMethod(class, @selector(af_suspend), afSuspendMethod)) {
        af_swizzleSelector(class, @selector(suspend), @selector(af_suspend));
    }
}

I'm trying to think of a reliable way to test that at the moment and confirm it fixes the problem.

kcharwood added a commit that referenced this pull request Oct 12, 2015
@kcharwood
Copy link
Contributor

Take a look at this branch and let me know if that at least prevents the failure in your current dupe setup @bixbarton

@bixbarton
Copy link

Thanks Kevin. I will try it out ASAP. I just wish I knew why the pods are
being compiled twice and why this is only an issue with Xcode 7.

On Monday, 12 October 2015, Kevin Harwood notifications@github.com wrote:

Take a look at this branch
https://github.com/AFNetworking/AFNetworking/tree/2743 and let me know
if that at least prevents the failure in your current dupe setup
@bixbarton https://github.com/bixbarton


Reply to this email directly or view it on GitHub
#2743 (comment)
.

@kcharwood
Copy link
Contributor

Also note if you have a second AF dependency lurking somewhere, this fix would only work if runs second. If it runs before the other duped' dependency is loaded, the error would still occur.

@kcharwood
Copy link
Contributor

I'm going to merge this in now. As mentioned this won't solve the problem if someone has precomiled an older version of AFN into a library, and that code runs after this patch. However, if that code runs first, this code should safely skip swizzling.

kcharwood added a commit that referenced this pull request Oct 13, 2015
AWS analytics for iOS app crash in AFNetworking
@kcharwood kcharwood merged commit 6d18d1a into master Oct 13, 2015
kcharwood added a commit that referenced this pull request Oct 13, 2015
@kcharwood
Copy link
Contributor

Added to 3_0_0 with ee853ff

@kcharwood kcharwood deleted the 2743 branch October 13, 2015 17:51
sergiou87 pushed a commit to plexinc/AFNetworking that referenced this pull request Dec 12, 2015
@waynett
Copy link

waynett commented Aug 4, 2016

I find libUMSocial_Sdk_5.2 use old version afnetworking that lead the crash! @com314159. you can see whether use umeng sdk!

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet