Skip to content

Commit

Permalink
Prevent LogBox from crashing on long messages (#38005)
Browse files Browse the repository at this point in the history
Summary:
Pull Request resolved: #38005

Fixes #32093 by guarding the expensive `BABEL_CODE_FRAME_ERROR_FORMAT` regex with a cheaper initial scan. (Longer term, we should reduce our reliance on string parsing and propagate more structured errors.)

Changelog: [General][Fixed] Prevent LogBox from crashing on very long messages

Reviewed By: GijsWeterings

Differential Revision: D46892454

fbshipit-source-id: 3afadcdd75969c2589bbb06f47d1c4c1c2690abd

# Conflicts:
#	Libraries/LogBox/Data/parseLogBoxLog.js
#	packages/react-native/package.json
  • Loading branch information
motiz88 authored and kelset committed Jul 3, 2023
1 parent fc1abe1 commit f59db07
Show file tree
Hide file tree
Showing 3 changed files with 65 additions and 20 deletions.
70 changes: 50 additions & 20 deletions Libraries/LogBox/Data/parseLogBoxLog.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,38 @@ import type {LogBoxLogData} from './LogBoxLog';
import parseErrorStack from '../../Core/Devtools/parseErrorStack';
import UTFSequence from '../../UTFSequence';
import stringifySafe from '../../Utilities/stringifySafe';
import ansiRegex from 'ansi-regex';

const ANSI_REGEX = ansiRegex().source;

const BABEL_TRANSFORM_ERROR_FORMAT =
/^(?:TransformError )?(?:SyntaxError: |ReferenceError: )(.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/;

// https://github.com/babel/babel/blob/33dbb85e9e9fe36915273080ecc42aee62ed0ade/packages/babel-code-frame/src/index.ts#L183-L184
const BABEL_CODE_FRAME_MARKER_PATTERN = new RegExp(
[
// Beginning of a line (per 'm' flag)
'^',
// Optional ANSI escapes for colors
`(?:${ANSI_REGEX})*`,
// Marker
'>',
// Optional ANSI escapes for colors
`(?:${ANSI_REGEX})*`,
// Left padding for line number
' +',
// Line number
'[0-9]+',
// Gutter
' \\|',
].join(''),
'm',
);

const BABEL_CODE_FRAME_ERROR_FORMAT =
// eslint-disable-next-line no-control-regex
/^(?:TransformError )?(?:.*):? (?:.*?)(\/.*): ([\s\S]+?)\n([ >]{2}[\d\s]+ \|[\s\S]+|\u{001b}[\s\S]+)/u;

const METRO_ERROR_FORMAT =
/^(?:InternalError Metro has encountered an error:) (.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/u;

Expand Down Expand Up @@ -241,27 +267,31 @@ export function parseLogBoxException(
};
}
const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
// Perform a cheap match first before trying to parse the full message, which
// can get expensive for arbitrary input.
if (BABEL_CODE_FRAME_MARKER_PATTERN.test(message)) {
const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
if (babelCodeFrameError) {
// Codeframe errors are thrown from any use of buildCodeFrameError.
const [fileName, content, codeFrame] = babelCodeFrameError.slice(1);
return {
level: 'syntax',
stack: [],
isComponentError: false,
componentStack: [],
codeFrame: {
fileName,
location: null, // We are not given the location.
content: codeFrame,
},
message: {
content,
substitutions: [],
},
category: `${fileName}-${1}-${1}`,
};
if (babelCodeFrameError) {
// Codeframe errors are thrown from any use of buildCodeFrameError.
const [fileName, content, codeFrame] = babelCodeFrameError.slice(1);
return {
level: 'syntax',
stack: [],
isComponentError: false,
componentStack: [],
codeFrame: {
fileName,
location: null, // We are not given the location.
content: codeFrame,
},
message: {
content,
substitutions: [],
},
category: `${fileName}-${1}-${1}`,
};
}
}
if (message.match(/^TransformError /)) {
Expand Down
14 changes: 14 additions & 0 deletions flow-typed/npm/ansi-regex_v5.x.x.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* @flow strict
* @format
*/

declare module 'ansi-regex' {
declare export type Options = {
/**
* Match only the first ANSI escape.
*/
+onlyFirst?: boolean,
};
declare export default function ansiRegex(options?: Options): RegExp;
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,7 @@
"@react-native/polyfills": "2.0.0",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
"ansi-regex": "^5.0.0",
"base64-js": "^1.1.2",
"deprecated-react-native-prop-types": "^3.0.1",
"event-target-shim": "^5.0.1",
Expand Down

1 comment on commit f59db07

@evelant
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this in 0.72.4? If so the fix unfortunately doesn't work, exactly the same behavior as before. It makes Android dev unusable as it locks up the app for over a minute before failing.

Please sign in to comment.