liveservices / LiveSDK-for-iOS

LiveSDK library for integrating with Live Connect
MIT License
138 stars 84 forks source link

building from xcode6 crashes the app after authenticated with liveSDK (caused by self.liveClient) #53

Closed DomenicoTanzarella closed 9 years ago

DomenicoTanzarella commented 9 years ago

I have an app in the store that use LiveSDK API to log the user into OneDrive. The last release was pushed before iOS8 came out, but it works without problem with iOS8

Now I want to push an update (unrelated to OneDrive features) and I am using xcode 6.1.1 but testing the app I noticed that every time the user is authenticated into OneDrive the app will crash as soon as return from a segue or flipside view to the Main View.

I was able to isolate the issue to this line added in viewDidLoad:

self.liveClient = [[LiveConnectClient alloc] initWithClientId:APP_CLIENT_ID delegate:self userState:@"initialize"]; and I really followed the basic instructions on how to login that can be found here:

http://msdn.microsoft.com/en-us/library/dn631822.aspx#sign_the_user_in

The steps to reproduce the issue (on both thee device and the simulator) are the following:

a) app starts b) click to the cloud service login button that will trigger a flipsideviewcontroller c) log into OneDrive with the code provided by MS d) go back to the main controller e) CRASH!

The trace is the following:

* First throw call stack: ( 0 CoreFoundation 0x028dd1e4 exceptionPreprocess + 180 1 libobjc.A.dylib 0x026598e5 objc_exception_throw + 44 2 CoreFoundation 0x0297a243 -[NSObject(NSObject) doesNotRecognizeSelector:] + 275 3 CoreFoundation 0x028cd50b _forwarding_** + 1019 4 CoreFoundation 0x028cd0ee _CF_forwarding_prep_0 + 14 5 CloudFella 0x0015c867 -[LiveConnectClientCore dealloc] + 48 6 libobjc.A.dylib 0x0266a692 _ZN11objc_object17sidetable_releaseEb + 268 7 libobjc.A.dylib 0x0266baeb -[NSObject release] + 25 8 CloudFella 0x00158af1 -[LiveConnectClient dealloc] + 44 9 libobjc.A.dylib 0x0266a692 _ZN11objc_object17sidetable_releaseEb + 268 10 libobjc.A.dylib 0x02669e81 objc_release + 49 11 libobjc.A.dylib 0x02669e3e objc_storeStrong + 39 12 CloudFella 0x00157b9d -[CFFlipsideViewController .cxx_destruct] + 249 13 libobjc.A.dylib 0x026582d4 _ZL27object_cxxDestructFromClassP11objc_objectP10objc_class + 128 14 libobjc.A.dylib 0x0265824f object_cxxDestruct + 20 15 libobjc.A.dylib 0x0266327a objc_destructInstance + 48 16 libobjc.A.dylib 0x026632ab object_dispose + 20 17 UIKit 0x01433d1a -[UIViewController dealloc] + 1854 18 UIKit 0x01430915 -[UIViewController release] + 89 19 libobjc.A.dylib 0x02669e97 objc_release + 71 20 libobjc.A.dylib 0x02656bf0 objc_setProperty_nonatomic + 48 21 UIKit 0x01a6167d -[_UIViewControllerOneToOneTransitionContext _setFromViewController:] + 47 22 UIKit 0x01a61490 -[_UIViewControllerOneToOneTransitionContext dealloc] + 43 23 libobjc.A.dylib 0x0266a692 _ZN11objc_object17sidetable_releaseEb + 268 24 libobjc.A.dylib 0x0266baeb -[NSObject release] + 25 25 UIKit 0x01a60834 -[_UIViewControllerTransitionContext completeTransition:] + 135 26 UIKit 0x01a7a5b1 -[UIViewControllerBuiltinTransitionViewAnimator transitionViewDidComplete:fromView:toView:removeFromView:] + 50 27 UIKit 0x01416137 -[UITransitionView notifyDidCompleteTransition:] + 345 28 UIKit 0x01415e61 -[UITransitionView _didCompleteTransition:] + 1333 29 UIKit 0x014181b7 -[UITransitionView _transitionDidStop:finished:] + 107 30 UIKit 0x013666dc -[UIViewAnimationState sendDelegateAnimationDidStop:finished:] + 267 31 UIKit 0x013669c8 -[UIViewAnimationState animationDidStop:finished:] + 80 32 QuartzCore 0x00fd6bb4 _ZN2CA5Layer23run_animation_callbacksEPv + 304 33 libdispatch.dylib 0x0326b4d0 _dispatch_client_callout + 14 34 libdispatch.dylib 0x03259726 _dispatch_main_queue_callback_4CF + 340 35 CoreFoundation 0x0294243e CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE + 14 36 CoreFoundation 0x028835cb CFRunLoopRun + 1963 37 CoreFoundation 0x028829d3 CFRunLoopRunSpecific + 467 38 CoreFoundation 0x028827eb CFRunLoopRunInMode + 123 39 GraphicsServices 0x0301f5ee GSEventRunModal + 192 40 GraphicsServices 0x0301f42b GSEventRun + 104 41 UIKit 0x01316f9b UIApplicationMain + 1225 42 CloudFella 0x000eeea6 main + 94 43 libdyld.dylib 0x034af6d9 start + 1 ) libc++abi.dylib: terminating with uncaught exception of type NSException

If I log into the other cloud services available in my app I got no issues at all.

The problem is happening with both the old LiveSDK API (the one included in the current good release out in the store) and the newest build (2 months old) added to the app to solve some validation issues described here: https://github.com/liveservices/LiveSDK-for-iOS/issues/43

I suspect that going from Xcode 5 to xcode 6 something changed in the building parameters that is causing the issue, however I am not sure where the issue is and how to workaround.

As test I forced building the app for 32 bit architectures only but it crashed as well: this was expected as the LiveSDK API is compatible with 64 bit arch, but certainly wanted to try... .

Any help is greatly appreciated.

Thanks, dom

DomenicoTanzarella commented 9 years ago

Hi, any update on this issue ? can you reproduce it ? Thanks, dom

aclev commented 9 years ago

I haven't been able to reproduce the issue, How are you storing the LiveConnectClient Object? It seems that when your view controller is dismissed it releases the last reference to the LiveConnectClient. It seems there is a bug in the dealloc in a certain state.

DomenicoTanzarella commented 9 years ago

Thanks for your reply: you are correct, the release of the reference to LiveConnectClient causes the crash. I am looking at a workaround to either have it released without crash or share the LiveConnectClient Object across multiple views. Any idea? What is weird is that there was no issue compiling the app with Xcode5. Thanks,dom

sylverb commented 9 years ago

I had the same issue ! It was crashing because of "[authRefreshRequest cancel];" in the release method of LiveConnectClientCore.m . I had a temporary fix by removing the autorelease at this line in refreshSessionWithDelegate method (also in LiveConnectClientCore.m) :

    self.authRefreshRequest = [[[LiveAuthRefreshRequest alloc] initWithClientId:_clientId
                                                                     scope:_scopes
                                                              refreshToken:refreshToken
                                                                  delegate:delegate
                                                                 userState:userState
                                                                clientStub:self]
                          autorelease];

But I finally managed to make it work without crashing and without changing this line but I can't remember how I did it ... You can check my project if needed : https://github.com/sylverb/NAStify/tree/master/NAStify/ConnectionManager/Plugins/OneDrive

DomenicoTanzarella commented 9 years ago

Hi Sylver, you nailed it! Thanks so much for the hint. Feel free to reply to the post "https://stackoverflow.com/questions/27752827/ios-8-livesdk-authentication-crashes-my-app" and I will mark it as solved :)

Ace, do you think you can work on a root cause and a fix? I am assuming that workaround such this one may cause memory leak(?) so on the long term it would be great to have the fix integrated in the API.

Thanks again, Domenico

sylverb commented 9 years ago

My solution is just a dirty hack, I don't think it's a good thing to put it in stackoverflow :p It's a pity I don't remember how I did fix that at the end ... I have included this patch in my live sdk : https://github.com/liveservices/LiveSDK-for-iOS/pull/48 maybe it helped solving the issue ?

sylverb commented 9 years ago

Ok I remember now ... Original code is :

    authRefreshRequest = [[[LiveAuthRefreshRequest alloc] initWithClientId:_clientId
                                                                     scope:_scopes
                                                              refreshToken:refreshToken
                                                                  delegate:delegate
                                                                 userState:userState
                                                                clientStub:self]
                          autorelease];

and I replaced it with :

    self.authRefreshRequest = [[[LiveAuthRefreshRequest alloc] initWithClientId:_clientId
                                                                     scope:_scopes
                                                              refreshToken:refreshToken
                                                                  delegate:delegate
                                                                 userState:userState
                                                                clientStub:self]
                          autorelease];

Yes I've just added a "self." at the beginning ! as the authRefreshRequest property is declared as "retain", this modification is equivalent to removing the autorelease actually ... In the original code, there is nothing that seems to retain the object, so I guess it is just released quickly ... Not sure if this is a proper correction as the autorelease was added in a patch that is supposed to remove some memory leaks ...

DomenicoTanzarella commented 9 years ago

Thanks again: I was really stuck on this one.

Domenico

On Jan 6, 2015, at 12:53 PM, Sylver Bruneau notifications@github.com wrote:

Ok I remember now ... Original code is :

authRefreshRequest = [[[LiveAuthRefreshRequest alloc] initWithClientId:_clientId
                                                                 scope:_scopes
                                                          refreshToken:refreshToken
                                                              delegate:delegate
                                                             userState:userState
                                                            clientStub:self]
                      autorelease];

and I replaced it with :

self.authRefreshRequest = [[[LiveAuthRefreshRequest alloc] initWithClientId:_clientId
                                                                 scope:_scopes
                                                          refreshToken:refreshToken
                                                              delegate:delegate
                                                             userState:userState
                                                            clientStub:self]
                      autorelease];

Yes I've just added a "self." at the beginning ! as the authRefreshRequest property is declared as "retain", this modification is equivalent to removing the autorelease actually ... In the original code, there is nothing that seems to retain the object, so I guess it is just released quickly ... Not sure if this is a proper correction as the autorelease was added in a patch that is supposed to remove some memory leaks ...

— Reply to this email directly or view it on GitHub.

rmaddy commented 9 years ago

I just ran into this issue. Thanks for pointing out the fix. Oddly, this bug was introduced in a code change made April 29, 2014.

aclev commented 9 years ago

close via #62