Skip to content

Commit cd56347

Browse files
motiz88facebook-github-bot
authored andcommitted
Prevent LogBox from crashing on long messages (#38005)
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
1 parent f544376 commit cd56347

File tree

3 files changed

+66
-21
lines changed

3 files changed

+66
-21
lines changed

flow-typed/npm/ansi-regex_v5.x.x.js

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
/**
2+
* @flow strict
3+
* @format
4+
*/
5+
6+
declare module 'ansi-regex' {
7+
declare export type Options = {
8+
/**
9+
* Match only the first ANSI escape.
10+
*/
11+
+onlyFirst?: boolean,
12+
};
13+
declare export default function ansiRegex(options?: Options): RegExp;
14+
}

packages/react-native/Libraries/LogBox/Data/parseLogBoxLog.js

Lines changed: 51 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -14,12 +14,38 @@ import type {LogBoxLogData} from './LogBoxLog';
1414
import parseErrorStack from '../../Core/Devtools/parseErrorStack';
1515
import UTFSequence from '../../UTFSequence';
1616
import stringifySafe from '../../Utilities/stringifySafe';
17+
import ansiRegex from 'ansi-regex';
18+
19+
const ANSI_REGEX = ansiRegex().source;
1720

1821
const BABEL_TRANSFORM_ERROR_FORMAT =
1922
/^(?:TransformError )?(?:SyntaxError: |ReferenceError: )(.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/;
23+
24+
// https://github.com/babel/babel/blob/33dbb85e9e9fe36915273080ecc42aee62ed0ade/packages/babel-code-frame/src/index.ts#L183-L184
25+
const BABEL_CODE_FRAME_MARKER_PATTERN = new RegExp(
26+
[
27+
// Beginning of a line (per 'm' flag)
28+
'^',
29+
// Optional ANSI escapes for colors
30+
`(?:${ANSI_REGEX})*`,
31+
// Marker
32+
'>',
33+
// Optional ANSI escapes for colors
34+
`(?:${ANSI_REGEX})*`,
35+
// Left padding for line number
36+
' +',
37+
// Line number
38+
'[0-9]+',
39+
// Gutter
40+
' \\|',
41+
].join(''),
42+
'm',
43+
);
44+
2045
const BABEL_CODE_FRAME_ERROR_FORMAT =
2146
// eslint-disable-next-line no-control-regex
2247
/^(?:TransformError )?(?:.*):? (?:.*?)(\/.*): ([\s\S]+?)\n([ >]{2}[\d\s]+ \|[\s\S]+|\u{001b}[\s\S]+)/u;
48+
2349
const METRO_ERROR_FORMAT =
2450
/^(?:InternalError Metro has encountered an error:) (.*): (.*) \((\d+):(\d+)\)\n\n([\s\S]+)/u;
2551

@@ -243,28 +269,32 @@ export function parseLogBoxException(
243269
};
244270
}
245271

246-
const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
272+
// Perform a cheap match first before trying to parse the full message, which
273+
// can get expensive for arbitrary input.
274+
if (BABEL_CODE_FRAME_MARKER_PATTERN.test(message)) {
275+
const babelCodeFrameError = message.match(BABEL_CODE_FRAME_ERROR_FORMAT);
247276

248-
if (babelCodeFrameError) {
249-
// Codeframe errors are thrown from any use of buildCodeFrameError.
250-
const [fileName, content, codeFrame] = babelCodeFrameError.slice(1);
251-
return {
252-
level: 'syntax',
253-
stack: [],
254-
isComponentError: false,
255-
componentStack: [],
256-
codeFrame: {
257-
fileName,
258-
location: null, // We are not given the location.
259-
content: codeFrame,
260-
},
261-
message: {
262-
content,
263-
substitutions: [],
264-
},
265-
category: `${fileName}-${1}-${1}`,
266-
extraData: error.extraData,
267-
};
277+
if (babelCodeFrameError) {
278+
// Codeframe errors are thrown from any use of buildCodeFrameError.
279+
const [fileName, content, codeFrame] = babelCodeFrameError.slice(1);
280+
return {
281+
level: 'syntax',
282+
stack: [],
283+
isComponentError: false,
284+
componentStack: [],
285+
codeFrame: {
286+
fileName,
287+
location: null, // We are not given the location.
288+
content: codeFrame,
289+
},
290+
message: {
291+
content,
292+
substitutions: [],
293+
},
294+
category: `${fileName}-${1}-${1}`,
295+
extraData: error.extraData,
296+
};
297+
}
268298
}
269299

270300
if (message.match(/^TransformError /)) {

packages/react-native/package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,7 @@
105105
"@react-native/virtualized-lists": "^0.73.0",
106106
"abort-controller": "^3.0.0",
107107
"anser": "^1.4.9",
108+
"ansi-regex": "^5.0.0",
108109
"base64-js": "^1.5.1",
109110
"deprecated-react-native-prop-types": "4.1.0",
110111
"event-target-shim": "^5.0.1",

0 commit comments

Comments
 (0)