Skip to content

Commit dfb6a40

Browse files
authored
[Fast Refresh] Fix crashes caused by rogue Proxies (#20030) (#20039)
1 parent 37cb732 commit dfb6a40

File tree

2 files changed

+33
-2
lines changed

2 files changed

+33
-2
lines changed

packages/react-refresh/src/ReactFreshRuntime.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -178,6 +178,16 @@ function cloneSet<T>(set: Set<T>): Set<T> {
178178
return clone;
179179
}
180180

181+
// This is a safety mechanism to protect against rogue getters and Proxies.
182+
function getProperty(object, property) {
183+
try {
184+
return object[property];
185+
} catch (err) {
186+
// Intentionally ignore.
187+
return undefined;
188+
}
189+
}
190+
181191
export function performReactRefresh(): RefreshUpdate | null {
182192
if (!__DEV__) {
183193
throw new Error(
@@ -322,7 +332,7 @@ export function register(type: any, id: string): void {
322332

323333
// Visit inner types because we might not have registered them.
324334
if (typeof type === 'object' && type !== null) {
325-
switch (type.$$typeof) {
335+
switch (getProperty(type, '$$typeof')) {
326336
case REACT_FORWARD_REF_TYPE:
327337
register(type.render, id + '$render');
328338
break;
@@ -676,7 +686,7 @@ export function isLikelyComponentType(type: any): boolean {
676686
}
677687
case 'object': {
678688
if (type != null) {
679-
switch (type.$$typeof) {
689+
switch (getProperty(type, '$$typeof')) {
680690
case REACT_FORWARD_REF_TYPE:
681691
case REACT_MEMO_TYPE:
682692
// Definitely React components.

packages/react-refresh/src/__tests__/ReactFresh-test.js

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3612,20 +3612,41 @@ describe('ReactFresh', () => {
36123612
const useStore = () => {};
36133613
expect(ReactFreshRuntime.isLikelyComponentType(useStore)).toBe(false);
36143614
expect(ReactFreshRuntime.isLikelyComponentType(useTheme)).toBe(false);
3615+
const rogueProxy = new Proxy(
3616+
{},
3617+
{
3618+
get(target, property) {
3619+
throw new Error();
3620+
},
3621+
},
3622+
);
3623+
expect(ReactFreshRuntime.isLikelyComponentType(rogueProxy)).toBe(false);
36153624

36163625
// These seem like function components.
36173626
const Button = () => {};
36183627
expect(ReactFreshRuntime.isLikelyComponentType(Button)).toBe(true);
36193628
expect(ReactFreshRuntime.isLikelyComponentType(Widget)).toBe(true);
3629+
const ProxyButton = new Proxy(Button, {
3630+
get(target, property) {
3631+
return target[property];
3632+
},
3633+
});
3634+
expect(ReactFreshRuntime.isLikelyComponentType(ProxyButton)).toBe(true);
36203635
const anon = (() => () => {})();
36213636
anon.displayName = 'Foo';
36223637
expect(ReactFreshRuntime.isLikelyComponentType(anon)).toBe(true);
36233638

36243639
// These seem like class components.
36253640
class Btn extends React.Component {}
36263641
class PureBtn extends React.PureComponent {}
3642+
const ProxyBtn = new Proxy(Btn, {
3643+
get(target, property) {
3644+
return target[property];
3645+
},
3646+
});
36273647
expect(ReactFreshRuntime.isLikelyComponentType(Btn)).toBe(true);
36283648
expect(ReactFreshRuntime.isLikelyComponentType(PureBtn)).toBe(true);
3649+
expect(ReactFreshRuntime.isLikelyComponentType(ProxyBtn)).toBe(true);
36293650
expect(
36303651
ReactFreshRuntime.isLikelyComponentType(
36313652
createReactClass({render() {}}),

0 commit comments

Comments
 (0)