Skip to content

Commit

Permalink
Prevent LogBox from crashing on long messages
Browse files Browse the repository at this point in the history
Summary:
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: f5194fb6022d9be16eb06d660c25bc1d1bea6444
  • Loading branch information
motiz88 authored and facebook-github-bot committed Jun 21, 2023
1 parent 4715e04 commit d918037
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 21 deletions.
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;
}
72 changes: 51 additions & 21 deletions packages/react-native/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 @@ -243,28 +269,32 @@ 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}`,
extraData: error.extraData,
};
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}`,
extraData: error.extraData,
};
}
}

if (message.match(/^TransformError /)) {
Expand Down
1 change: 1 addition & 0 deletions packages/react-native/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@
"@react-native/virtualized-lists": "^0.73.0",
"abort-controller": "^3.0.0",
"anser": "^1.4.9",
"ansi-regex": "^5.0.0",
"base64-js": "^1.5.1",
"deprecated-react-native-prop-types": "4.1.0",
"event-target-shim": "^5.0.1",
Expand Down

0 comments on commit d918037

Please sign in to comment.