Skip to content
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

Crash when [CBLRemoteRequest connection:didFailWithError:] #1015

Closed
Vitalii-Gozhenko opened this issue Jan 5, 2016 · 8 comments
Closed

Crash when [CBLRemoteRequest connection:didFailWithError:] #1015

Vitalii-Gozhenko opened this issue Jan 5, 2016 · 8 comments

Comments

@Vitalii-Gozhenko
Copy link

Crash comes from Fabric on production version. Trying to reproduce it, but have no idea when this problem happens.

More details about crash:
https://gist.github.com/Magnat12/0260a0c66e0ff4198adb

@snej
Copy link
Contributor

snej commented Jan 6, 2016

What version of Couchbase Lite?

@Vitalii-Gozhenko
Copy link
Author

fork from release/1.2

@snej
Copy link
Contributor

snej commented Jan 7, 2016

The crash log says the crash is in the callback block in -[CBLRestPuller pullRemoteRevision:]. Since there are no stack frames past that, I'm assuming it's something like a bad pointer deref — if it were messaging a bad id, there'd be a call to objc_msgsend on the stack.

The likely culprit here is the reference to _httpConnectionCount on line 463 — it's about the only thing this block does directly, not as a method/function call. This block might be called after the puller's already been dealloced... It shouldn't be referencing that instance variable directly anyway, it should go through strongSelf. I can speculatively fix that.

snej added a commit that referenced this issue Jan 7, 2016
The point of the weakSelf/strongSelf dance is to avoid a reference cycle,
but that means that when the block is called, the receiver may have been
dealloced already, so strongSelf will end up nil. In that case,
dereferencing it would crash. So check it for nil first.

Also fixed some inadvertent references to self in the blocks, which
defeat the purpose of using weakSelf.

Fixes #1015 (I think; this is a speculative fix)
@snej
Copy link
Contributor

snej commented Jan 7, 2016

Fixed on release/1.2 branch. I'm not 100% sure this is what caused your crash, but I'm at least 90% sure. :)

@snej snej closed this as completed Jan 7, 2016
@Vitalii-Gozhenko
Copy link
Author

Thanks!

@pasin
Copy link
Contributor

pasin commented Feb 8, 2016

The same issue reported by @lucatorella in #1103.

__36-[CBLRestPuller pullRemoteRevision:]_block_invoke (CBLRestPuller.m:461)
__36-[CBLRestPuller pullRemoteRevision:]_block_invoke (CBLRestPuller.m:461)
-[CBLRemoteRequest respondWithResult:error:] (CBLRemoteRequest.m:180)
-[CBLRemoteRequest connection:didFailWithError:] (CBLRemoteRequest.m:449)
-[CBLRemoteRequest cancelWithStatus:] (CBLRemoteRequest.m:210)
-[CBLRemoteRequest connection:didReceiveResponse:] (CBLRemoteRequest.m:409)
-[CBLMultipartDownloader connection:didReceiveResponse:] (CBLMultipartDownloader.m:87)
__65-[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:]_block_invoke + 80
-[NSURLConnectionInternal _withConnectionAndDelegate:onlyActive:] + 200
-[NSURLConnectionInternal _withActiveConnectionAndDelegate:] + 56
_NSURLConnectionDidReceiveResponse(_CFURLConnection*, _CFURLResponse*, void const*) + 80
___ZN27URLConnectionClient_Classic28_delegate_didReceiveResponseEP14_CFURLResponse_block_invoke + 108
___ZN27URLConnectionClient_Classic18_withDelegateAsyncEPKcU13block_pointerFvP16_CFURLConnectionPK33CFURLConnectionClientCurrent_VMaxE_block_invoke_2 + 108
_dispatch_client_callout + 16
_dispatch_block_invoke + 540
RunloopBlockContext::_invoke_block(void const*, void*) + 36
CFArrayApplyFunction + 68
RunloopBlockContext::perform() + 136
MultiplexerSource::perform() + 312
MultiplexerSource::_perform(void*) + 68
__CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 24
__CFRunLoopDoSources0 + 540
__CFRunLoopRun + 724
CFRunLoopRunSpecific + 384
-[NSRunLoop(NSRunLoop) runMode:beforeDate:] + 308
-[CBL_RunLoopServer runServerThread] (CBL_Server.m:190)
__NSThread__start__ + 1000
_pthread_body + 156
_pthread_body + 0
thread_start + 4

@pasin pasin reopened this Feb 8, 2016
@pasin pasin added the crash! label Feb 8, 2016
@snej
Copy link
Contributor

snej commented Feb 9, 2016

The crashing line is

            [strongSelf removeRemoteRequest:dl];

but the crash is before the call to objc_msgsend -- it's dereferencing a pointer read from the stack frame to get dl. Since dl is a captured __block variable, the crash seems to come from accessing the block's storage … so I think the block object has been dealloced by this point.

The block is owned by the CBLMultipartDownloader, and it's called in -[CBLRemoteRequest respondWithResult:error:]:

    _onCompletion(result, error);

So maybe _onCompletion got set to nil while in the block, causing the block object to be dealloced?

snej added a commit that referenced this issue Feb 9, 2016
If a block ref is stored in an ivar, and the ivar might change due to
a re-entrant call during a call to the block, then be safe and copy the
block ref to a local variable before calling it. Otherwise the block
might be dealloced while its code is running, which will cause garbage
results or even crashes when it accesses a captured variable.

Fixes #1015
@snej
Copy link
Contributor

snej commented Feb 9, 2016

I looked at the disassembly of the call to _onCompletion — it doesn't retain the block before making the call. So it's entirely possible for the block object to be dealloced while its code is running, if the ivar gets reassigned by a call back into the CBLRemoteRequest (such as -stop.)

The fix is to assign the block to a local variable first, then call that. That causes it to be retained until after the call returns.

I searched the code for all the places where we call a block in an ivar directly, and fixed the ones where there was a possibility of the block calling back into the calling object.

@snej snej added this to the 1.3 milestone Jul 3, 2016
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants