From 0bea6a9b1995e651ebabbc074db39809ef63323d Mon Sep 17 00:00:00 2001 From: Joshua Gross Date: Mon, 28 Oct 2019 19:26:12 -0700 Subject: [PATCH] Work around ancient race condition in ReactInstanceManager Summary: See T55861104. In rare cases if `removeReactInstanceEventListener` is called right after (like, a small number of CPU instructions later, on a different thread) we allocate the `listeners` array with a certain size, then we could have one or more `null` listeners in the array, which is what we've been seeing in prod, at very low volumes, for several years. Without solving the root of the race condition we can just add a null check here. Maybe it's also possible that if `addReactInstanceEventListener` is called on another thread in a racey way, that the size will be incremented on the array before we can access the additional member. That seems crazy, but maybe. While this has been firing for multiple years it seems like a more recent change caused a regression. This diff doesn't address that and only resolves the crash. Changelog: [Internal] Reviewed By: ejanzer Differential Revision: D18192801 fbshipit-source-id: c1000cfcdf6f251b03061d1386eabb9f0617a7d3 --- .../java/com/facebook/react/ReactInstanceManager.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java index 24d6fcc7c326c3..9bd89a6f13b15e 100644 --- a/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java +++ b/ReactAndroid/src/main/java/com/facebook/react/ReactInstanceManager.java @@ -1034,6 +1034,8 @@ private void setupReactContext(final ReactApplicationContext reactContext) { ReactMarker.logMarker(ATTACH_MEASURED_ROOT_VIEWS_END); } + // There is a race condition here - `finalListeners` can contain null entries + // See usage below for more details. ReactInstanceEventListener[] listeners = new ReactInstanceEventListener[mReactInstanceEventListeners.size()]; final ReactInstanceEventListener[] finalListeners = @@ -1044,7 +1046,13 @@ private void setupReactContext(final ReactApplicationContext reactContext) { @Override public void run() { for (ReactInstanceEventListener listener : finalListeners) { - listener.onReactContextInitialized(reactContext); + // Sometimes this listener is null - probably due to race + // condition between allocating listeners with a certain + // size, and getting a `final` version of the array on + // the following line. + if (listener != null) { + listener.onReactContextInitialized(reactContext); + } } } });