Skip to content

Commit 769cfc7

Browse files
committed
Bugfix: Synchronous ping during render phase sometimes unwinds the stack, leading to crash (#25851)
I found this bug when working on a different task. `pingSuspendedRoot` sometimes calls `prepareFreshStack` to interupt the work-in-progress tree and force a restart from the root. The idea is that if the current render is already in a state where it be blocked from committing, and there's new data that could unblock it, we might as well restart from the beginning. The problem is that this is only safe to do if `pingSuspendedRoot` is called from a non-React task, like an event handler or a microtask. While this is usually the case, it's entirely possible for a thenable to resolve (i.e. to call `pingSuspendedRoot`) synchronously while the render phase is already executing. If that happens, and work loop attempts to unwind the stack, it causes the render phase to crash. DiffTrain build for [5fcf1a4](5fcf1a4) [View git log for this commit](https://github.com/facebook/react/commits/5fcf1a4b4c2150a1b9fe0de0144a82a053c63966)
1 parent ecbf597 commit 769cfc7

28 files changed

+90
-66
lines changed

compiled/facebook-www/REVISION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2b1fb91a55deb9b7b60452cb57184c2f182a42fd
1+
5fcf1a4b4c2150a1b9fe0de0144a82a053c63966
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2b1fb91a55deb9b7b60452cb57184c2f182a42fd
1+
5fcf1a4b4c2150a1b9fe0de0144a82a053c63966

compiled/facebook-www/React-dev.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (
2727
}
2828
"use strict";
2929

30-
var ReactVersion = "18.3.0-www-classic-2b1fb91a5-20221220";
30+
var ReactVersion = "18.3.0-www-classic-5fcf1a4b4-20221221";
3131

3232
// ATTENTION
3333
// When adding new symbols to this file,

compiled/facebook-www/React-dev.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ if (
2727
}
2828
"use strict";
2929

30-
var ReactVersion = "18.3.0-www-modern-2b1fb91a5-20221220";
30+
var ReactVersion = "18.3.0-www-modern-5fcf1a4b4-20221221";
3131

3232
// ATTENTION
3333
// When adding new symbols to this file,

compiled/facebook-www/React-prod.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -643,4 +643,4 @@ exports.useSyncExternalStore = function(
643643
);
644644
};
645645
exports.useTransition = useTransition;
646-
exports.version = "18.3.0-www-classic-2b1fb91a5-20221220";
646+
exports.version = "18.3.0-www-classic-5fcf1a4b4-20221221";

compiled/facebook-www/React-prod.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -635,4 +635,4 @@ exports.useSyncExternalStore = function(
635635
);
636636
};
637637
exports.useTransition = useTransition;
638-
exports.version = "18.3.0-www-modern-2b1fb91a5-20221220";
638+
exports.version = "18.3.0-www-modern-5fcf1a4b4-20221221";

compiled/facebook-www/React-profiling.classic.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -654,7 +654,7 @@ exports.useSyncExternalStore = function(
654654
);
655655
};
656656
exports.useTransition = useTransition;
657-
exports.version = "18.3.0-www-classic-2b1fb91a5-20221220";
657+
exports.version = "18.3.0-www-classic-5fcf1a4b4-20221221";
658658

659659
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
660660
if (

compiled/facebook-www/React-profiling.modern.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -646,7 +646,7 @@ exports.useSyncExternalStore = function(
646646
);
647647
};
648648
exports.useTransition = useTransition;
649-
exports.version = "18.3.0-www-modern-2b1fb91a5-20221220";
649+
exports.version = "18.3.0-www-modern-5fcf1a4b4-20221221";
650650

651651
/* global __REACT_DEVTOOLS_GLOBAL_HOOK__ */
652652
if (

compiled/facebook-www/ReactART-dev.classic.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
6969
return self;
7070
}
7171

72-
var ReactVersion = "18.3.0-www-classic-2b1fb91a5-20221220";
72+
var ReactVersion = "18.3.0-www-classic-5fcf1a4b4-20221221";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -25766,8 +25766,11 @@ function pingSuspendedRoot(root, wakeable, pingedLanes) {
2576625766
includesOnlyRetries(workInProgressRootRenderLanes) &&
2576725767
now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS)
2576825768
) {
25769-
// Restart from the root.
25770-
prepareFreshStack(root, NoLanes);
25769+
// Force a restart from the root by unwinding the stack. Unless this is
25770+
// being called from the render phase, because that would cause a crash.
25771+
if ((executionContext & RenderContext) === NoContext) {
25772+
prepareFreshStack(root, NoLanes);
25773+
}
2577125774
} else {
2577225775
// Even though we can't restart right now, we might get an
2577325776
// opportunity later. So we mark this render as having a ping.

compiled/facebook-www/ReactART-dev.modern.js

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ function _assertThisInitialized(self) {
6969
return self;
7070
}
7171

72-
var ReactVersion = "18.3.0-www-modern-2b1fb91a5-20221220";
72+
var ReactVersion = "18.3.0-www-modern-5fcf1a4b4-20221221";
7373

7474
var LegacyRoot = 0;
7575
var ConcurrentRoot = 1;
@@ -25455,8 +25455,11 @@ function pingSuspendedRoot(root, wakeable, pingedLanes) {
2545525455
includesOnlyRetries(workInProgressRootRenderLanes) &&
2545625456
now() - globalMostRecentFallbackTime < FALLBACK_THROTTLE_MS)
2545725457
) {
25458-
// Restart from the root.
25459-
prepareFreshStack(root, NoLanes);
25458+
// Force a restart from the root by unwinding the stack. Unless this is
25459+
// being called from the render phase, because that would cause a crash.
25460+
if ((executionContext & RenderContext) === NoContext) {
25461+
prepareFreshStack(root, NoLanes);
25462+
}
2546025463
} else {
2546125464
// Even though we can't restart right now, we might get an
2546225465
// opportunity later. So we mark this render as having a ping.

0 commit comments

Comments
 (0)