react-native: [iOS] Crash in [RCTModuleData setUpMethodQueue]

I’m looking for a squashing bug in an iOS app that I can’t work out/reproduce. I am getting a logged error of Selector name found in current argument registers: retain

This only seems to happen on iOS devices with 9.3 (Currently one of our top crashes in our application)

Log file for crash:

Thread 19 Crashed:
0   libdispatch.dylib                    0x0000000181c02534 _os_object_retain + 72
1   libobjc.A.dylib                      0x0000000181834128 objc_storeStrong + 40
2   libobjc.A.dylib                      0x000000018181a908 object_setIvar + 272
3   Foundation                           0x0000000182ac36e4 -[NSObject(NSKeyValueCoding) setValue:forKey:] + 264
4   myapp                              0x00000001007a4908 -[RCTModuleData setUpMethodQueue] (RCTModuleData.m:186)
5   myapp                              0x00000001007a43f8 -[RCTModuleData setUpInstanceAndBridge] (RCTModuleData.m:120)
6   myapp                              0x00000001007a4a6c -[RCTModuleData instance] (RCTModuleData.m:222)
7   myapp                              0x000000010079e2b4 -[RCTBatchedBridge moduleForName:] (RCTBatchedBridge.m:216)
8   myapp                              0x00000001007b4660 -[RCTBridge moduleForClass:] (RCTBridge.m:199)
9   myapp                              0x000000010074e254 __100-[RCTImageLoader loadImageOrDataWithURLRequest:size:scale:resizeMode:progressBlock:completionBlock:]_block_invoke.142 (RCTImageLoader.m:415)
10  libdispatch.dylib                    0x0000000181c014bc _dispatch_call_block_and_release + 20
11  libdispatch.dylib                    0x0000000181c0147c _dispatch_client_callout + 12
12  libdispatch.dylib                    0x0000000181c0d4c0 _dispatch_queue_drain + 860
13  libdispatch.dylib                    0x0000000181c04f80 _dispatch_queue_invoke + 460
14  libdispatch.dylib                    0x0000000181c0147c _dispatch_client_callout + 12
15  libdispatch.dylib                    0x0000000181c0f914 _dispatch_root_queue_drain + 2136
16  libdispatch.dylib                    0x0000000181c0f0b0 _dispatch_worker_thread3 + 108
17  libsystem_pthread.dylib              0x0000000181e19470 _pthread_wqthread + 1088
18  libsystem_pthread.dylib              0x0000000181e19020 start_wqthread + 0

About this issue

  • Original URL
  • State: closed
  • Created 8 years ago
  • Reactions: 3
  • Comments: 37 (14 by maintainers)

Commits related to this issue

Most upvoted comments

what’s the status on this?

So the RCTImageLoader crashes persist despite hardier strongSelf and weakSelf checking, as well as into 0.33.0-rc0’s changes with the image loading classes.

In current testing, it seems like this block is the culprit:

return ^{
    if (cancelLoad) {
      cancelLoad();
      cancelLoad = nil;
    }
    OSAtomicOr32Barrier(1, &cancelled);
  };

This is in RCTImageLoader.m, and in the methods:

  • _loadImageOrDataWithURLRequest:size:scale:resizeMode:progressBlock:completionBlock
  • loadImageWithURLRequest:size:scale:clipped:resizeMode:progressBlock:completionBlock

The call stack flows from RCTImageView::reloadImage -> RCTImageView::cancelImageLoad -> those methods.

The following lines will throw an EXC_BAD_ACCESS exception:

  • cancelLoad = nil;
  • After commenting that out, OSAtomicOr32Barrier(1, &cancelled); throws the exception as well.
  • Sometimes (less frequently), cancelLoad() will throw it as well

This is reproducible, but not pinned down to an exact set of steps that will make it crash guaranteed. We have a ListView with a large number of rows in which a <Text> component is wrapping a remotely loaded <Image> component. This crash happens basically every time after scrolling quickly through the list, but not on a certain row or image url. That’s why it’s quasi-reproducible.


Ideas:

Setting a property to nil that has already been dereferenced, will cause an EXC_BAD_ACCESS exception. Obviously this property is being released, but where and why that can happen is still unclear. My current idea is that the app is experiencing memory pressure and pruning views, which are still loading and holding references to the callback blocks, and then the app crashes doing what it thinks it should do.

I’m not sure who to ping on this, but I’m going to ping @brentvatne since he seems to be all over the place in the issues here. Sorry if this is not your area Brent, but maybe you could point us in the right direction here?

We are testing some block changes, and will update with results from the newest build.

We are transitioning the code that looks like this:

return ^{
    if (cancelLoad) {
      cancelLoad();
      cancelLoad = nil;
    }
    OSAtomicOr32Barrier(1, &cancelled);
  };

to this:

return ^{
    dispatch_block_t innerCancel = [cancelLoad copy];
    if (innerCancel) {
      innerCancel();
      innerCancel = nil;
    }
    OSAtomicOr32Barrier(1, &cancelled);
  };

Doing this seems to fix it while testing, but this is really a huge problem in memory starved cases that are harder to debug and test in house. We really only started seeing these crashes once the app was out in production and crash reports started arriving in droves.

Our theory behind this is that there are several places where weak refs are being treated like strong refs. And also a series of places where things were not being null-checked. We are in the process of testing a patch: https://github.com/Curse/react-native/commit/bdf1354f67e872bcbaff45eba050d93ba8e15c4a Apply at your own risk, obviously.

@Griffosx I believe you’re seeing this “work” because technically the image has already been downloaded at that point.

There’s a _pendingImageSource and an _imageSource and I believe the problem comes in play when you call [self cancelImageLoad] while it is still in the process of loading. So with your fix, it just continues loading all the way through instead of removing the network task from the queue.

It looks like there have been two commits to master that potentially deal with this problem.

The first one is slated for 0.35 release, and the second is in master and most likely to be added to 0.36.

The first fix “sounds” like it’s correct via the commit description and reasoning. I’m going to add these two commit changes to our current fork and see if we can get the app to crash or not.

The issue is not resolved in 0.34.1 After a quick investigation I think I found what causes the problem (in my case). In very short, when an image goes out of the screen and it’s still loading sometimes the app crashes.

Workoround In RCTImageView.m replace in the method didMoveToWindow the line: [self cancelImageLoad]; with if (_imageSource.request.URL.absoluteString) { [self cancelImageLoad]; } With this modification my crashes vanished

Note: I don’t know exactly why sometimes the imagesSource is nil, I only noticed that this happens. Also, I’m quite sure that my modification doesn’t hurt the system, because that line is only an optimization, it can be commented also without problem.

@javache thanks for the great news, I’ll update to the 0.34 stable version asap and release a new app version in the following week(s). I will monitor our crashes, if there are any, and let you know if I can verify the fix.

@bennyguitar We are seeing this crash disappear at FB with the latest version of React Native. Your patch can cause the scenario where items are cancelled multiple times, since cancelLoad is never nilled out.

My use case made it very easy to reproduce - this change fixes it thanks @bennyguitar !!!

I met the same crash.