AWS analytics for iOS app crash in AFNetworking by kcharwood · Pull Request #2743 · AFNetworking/AFNetworking · GitHub
Skip to content
This repository was archived by the owner on Jan 17, 2023. It is now read-only.

AWS analytics for iOS app crash in AFNetworking#2743

Merged
kcharwood merged 1 commit into
masterfrom
2743
Oct 13, 2015
Merged

AWS analytics for iOS app crash in AFNetworking#2743
kcharwood merged 1 commit into
masterfrom
2743

Conversation

@kcharwood

Copy link
Copy Markdown
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
Copy Markdown
Contributor

@care2achieve

Copy link
Copy Markdown
Author

iOS - 8.3
self is AFURLSessionTaskSwizzling

@kcharwood

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor

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

@kcharwood

Copy link
Copy Markdown
Contributor

Any more news on this @care2achieve?

@kcharwood

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown
Contributor

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

@kcharwood

Copy link
Copy Markdown
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
Copy Markdown
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
Copy Markdown
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
Copy Markdown

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
Copy Markdown
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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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

@rotemdoron

Copy link
Copy Markdown

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
Copy Markdown
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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

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
Copy Markdown

@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
Copy Markdown

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
Copy Markdown

@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
Copy Markdown

@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
Copy Markdown

@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
Copy Markdown

Exception here...
image

Next level in...
image

Next-next level in...
image

@mattmassicotte

Copy link
Copy Markdown

@bixbarton Fabric does not use AFNetworking

@bixbarton

Copy link
Copy Markdown

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

@bixbarton

Copy link
Copy Markdown

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

@kcharwood

Copy link
Copy Markdown
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
Copy Markdown

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

@kcharwood

Copy link
Copy Markdown
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
Copy Markdown

@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
Copy Markdown

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
Copy Markdown
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
Copy Markdown
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
Copy Markdown

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
Copy Markdown
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 kcharwood added this to the 2.6.1 milestone Oct 13, 2015
kcharwood added a commit that referenced this pull request Oct 13, 2015
@kcharwood

Copy link
Copy Markdown
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
Copy Markdown
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

waynett commented Aug 4, 2016

Copy link
Copy Markdown

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.