Skip to content

Chrome and Firefox Extensions stack trace parsing #1235

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Feb 21, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

28 changes: 24 additions & 4 deletions test/vendor/fixtures/captured-errors.js
Original file line number Diff line number Diff line change
Expand Up @@ -193,10 +193,18 @@ CapturedExceptions.CHROME_XX_WEBPACK = {
name: 'TypeError',
stack:
"TypeError: Cannot read property 'error' of undefined\n" +
' at TESTTESTTEST.eval(webpack:///./src/components/test/test.jsx?:295:108)\n' +
' at TESTTESTTEST.render(webpack:///./src/components/test/test.jsx?:272:32)\n' +
' at TESTTESTTEST.tryRender(webpack:///./~/react-transform-catch-errors/lib/index.js?:34:31)\n' +
' at TESTTESTTEST.proxiedMethod(webpack:///./~/react-proxy/modules/createPrototypeProxy.js?:44:30)'
' at TESTTESTTEST.eval(webpack:///./src/components/test/test.jsx?:295:108)\n' +
' at TESTTESTTEST.render(webpack:///./src/components/test/test.jsx?:272:32)\n' +
' at TESTTESTTEST.tryRender(webpack:///./~/react-transform-catch-errors/lib/index.js?:34:31)\n' +
' at TESTTESTTEST.proxiedMethod(webpack:///./~/react-proxy/modules/createPrototypeProxy.js?:44:30)'
};

CapturedExceptions.CHROME_EXTENSION = {
message: 'oops!',
name: 'Error',
stack:
'Error: oops!\n' +
' at chrome-extension://negengibeecgiokdifncekejdgkcoono/content-script-main.js:93:12'
};

CapturedExceptions.FIREFOX_3 = {
Expand Down Expand Up @@ -297,6 +305,18 @@ CapturedExceptions.FIREFOX_50_RESOURCE_URL = {
name: 'TypeError'
};

CapturedExceptions.FIREFOX_MOZ_EXTENSION = {
stack:
'render@moz-extension://path/data/content/bundle.js:5529:16\n' +
'dispatchEvent@moz-extension://path/data/content/vendor.bundle.js:18:23028\n' +
'wrapped@moz-extension//path/data/content/bundle.js:7270:25',
fileName: 'moz-extension://path/data/content/bundle.js',
lineNumber: 5529,
columnNumber: 16,
message: 'this.props.raw[this.state.dataSource].rows is undefined',
name: 'TypeError'
};

CapturedExceptions.SAFARI_6 = {
message: "'null' is not an object (evaluating 'x.undef')",
stack:
Expand Down
28 changes: 28 additions & 0 deletions test/vendor/tracekit-parser.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -431,6 +431,19 @@ describe('TraceKit', function() {
});
});

it('should parse Chrome Extension errors', function() {
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.CHROME_EXTENSION);
assert.ok(stackFrames);
assert.deepEqual(stackFrames.stack.length, 1);
assert.deepEqual(stackFrames.stack[0], {
url: 'chrome-extension://negengibeecgiokdifncekejdgkcoono/content-script-main.js',
func: '?',
args: [],
line: 93,
column: 12
});
});

it('should parse nested eval() from Chrome', function() {
var stackFrames = TraceKit.computeStackTrace(CapturedExceptions.CHROME_48_EVAL);
assert.ok(stackFrames);
Expand Down Expand Up @@ -788,6 +801,21 @@ describe('TraceKit', function() {
});
});

it('should parse Firefox Extension errors', function() {
var stackFrames = TraceKit.computeStackTrace(
CapturedExceptions.FIREFOX_MOZ_EXTENSION
);
assert.ok(stackFrames);
assert.deepEqual(stackFrames.stack.length, 3);
assert.deepEqual(stackFrames.stack[0], {
url: 'moz-extension://path/data/content/bundle.js',
func: 'render',
args: [],
line: 5529,
column: 16
});
});

it('should parse React Native errors on Android', function() {
var stackFrames = TraceKit.computeStackTrace(
CapturedExceptions.ANDROID_REACT_NATIVE
Expand Down
116 changes: 58 additions & 58 deletions vendor/TraceKit/tracekit.js
Original file line number Diff line number Diff line change
Expand Up @@ -80,18 +80,18 @@ TraceKit.report = (function reportModuleWrapper() {
lastExceptionStack = null;

/**
* Add a crash handler.
* @param {Function} handler
*/
* Add a crash handler.
* @param {Function} handler
*/
function subscribe(handler) {
installGlobalHandler();
handlers.push(handler);
}

/**
* Remove a crash handler.
* @param {Function} handler
*/
* Remove a crash handler.
* @param {Function} handler
*/
function unsubscribe(handler) {
for (var i = handlers.length - 1; i >= 0; --i) {
if (handlers[i] === handler) {
Expand All @@ -101,17 +101,17 @@ TraceKit.report = (function reportModuleWrapper() {
}

/**
* Remove all crash handlers.
*/
* Remove all crash handlers.
*/
function unsubscribeAll() {
uninstallGlobalHandler();
handlers = [];
}

/**
* Dispatch stack information to all handlers.
* @param {Object.<string, *>} stack
*/
* Dispatch stack information to all handlers.
* @param {Object.<string, *>} stack
*/
function notifyHandlers(stack, isWindowError) {
var exception = null;
if (isWindowError && !TraceKit.collectWindowErrors) {
Expand All @@ -135,16 +135,16 @@ TraceKit.report = (function reportModuleWrapper() {
var _oldOnerrorHandler, _onErrorHandlerInstalled;

/**
* Ensures all global unhandled exceptions are recorded.
* Supported by Gecko and IE.
* @param {string} msg Error message.
* @param {string} url URL of script that generated the exception.
* @param {(number|string)} lineNo The line number at which the error
* occurred.
* @param {?(number|string)} colNo The column number at which the error
* occurred.
* @param {?Error} ex The actual Error object.
*/
* Ensures all global unhandled exceptions are recorded.
* Supported by Gecko and IE.
* @param {string} msg Error message.
* @param {string} url URL of script that generated the exception.
* @param {(number|string)} lineNo The line number at which the error
* occurred.
* @param {?(number|string)} colNo The column number at which the error
* occurred.
* @param {?Error} ex The actual Error object.
*/
function traceKitWindowOnError(msg, url, lineNo, colNo, ex) {
var stack = null;
// If 'ex' is ErrorEvent, get real Error from inside
Expand Down Expand Up @@ -232,12 +232,12 @@ TraceKit.report = (function reportModuleWrapper() {
}

/**
* Reports an unhandled Error to TraceKit.
* @param {Error} ex
* @param {?boolean} rethrow If false, do not re-throw the exception.
* Only used for window.onerror to not cause an infinite loop of
* rethrowing.
*/
* Reports an unhandled Error to TraceKit.
* @param {Error} ex
* @param {?boolean} rethrow If false, do not re-throw the exception.
* Only used for window.onerror to not cause an infinite loop of
* rethrowing.
*/
function report(ex, rethrow) {
var args = _slice.call(arguments, 1);
if (lastExceptionStack) {
Expand Down Expand Up @@ -364,16 +364,16 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
// ex.stacktrace = n/a; see 'opera:config#UserPrefs|Exceptions Have Stacktrace'

/**
* Computes stack trace information from the stack property.
* Chrome and Gecko use this property.
* @param {Error} ex
* @return {?Object.<string, *>} Stack trace information.
*/
* Computes stack trace information from the stack property.
* Chrome and Gecko use this property.
* @param {Error} ex
* @return {?Object.<string, *>} Stack trace information.
*/
function computeStackTraceFromStackProp(ex) {
if (typeof ex.stack === 'undefined' || !ex.stack) return;

var chrome = /^\s*at (.*?) ?\(((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|[a-z]:|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,
gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i,
var chrome = /^\s*at (?:(.*?) ?\()?((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|[a-z]:|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,
gecko = /^\s*(.*?)(?:\((.*?)\))?(?:^|@)((?:file|https?|blob|chrome|webpack|resource|moz-extension|\[native).*?|[^@]*bundle)(?::(\d+))?(?::(\d+))?\s*$/i,
winjs = /^\s*at (?:((?:\[object object\])?.+) )?\(?((?:file|ms-appx(?:-web)|https?|webpack|blob):.*?):(\d+)(?::(\d+))?\)?\s*$/i,
// Used to additionally parse URL/line/column from eval frames
geckoEval = /(\S+) line (\d+)(?: > eval line \d+)* > eval/i,
Expand Down Expand Up @@ -455,18 +455,18 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
}

/**
* Adds information about the first frame to incomplete stack traces.
* Safari and IE require this to get complete data on the first frame.
* @param {Object.<string, *>} stackInfo Stack trace information from
* one of the compute* methods.
* @param {string} url The URL of the script that caused an error.
* @param {(number|string)} lineNo The line number of the script that
* caused an error.
* @param {string=} message The error generated by the browser, which
* hopefully contains the name of the object that caused the error.
* @return {boolean} Whether or not the stack information was
* augmented.
*/
* Adds information about the first frame to incomplete stack traces.
* Safari and IE require this to get complete data on the first frame.
* @param {Object.<string, *>} stackInfo Stack trace information from
* one of the compute* methods.
* @param {string} url The URL of the script that caused an error.
* @param {(number|string)} lineNo The line number of the script that
* caused an error.
* @param {string=} message The error generated by the browser, which
* hopefully contains the name of the object that caused the error.
* @return {boolean} Whether or not the stack information was
* augmented.
*/
function augmentStackTraceWithInitialElement(stackInfo, url, lineNo, message) {
var initial = {
url: url,
Expand Down Expand Up @@ -505,14 +505,14 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
}

/**
* Computes stack trace information by walking the arguments.caller
* chain at the time the exception occurred. This will cause earlier
* frames to be missed but is the only way to get any stack trace in
* Safari and IE. The top frame is restored by
* {@link augmentStackTraceWithInitialElement}.
* @param {Error} ex
* @return {?Object.<string, *>} Stack trace information.
*/
* Computes stack trace information by walking the arguments.caller
* chain at the time the exception occurred. This will cause earlier
* frames to be missed but is the only way to get any stack trace in
* Safari and IE. The top frame is restored by
* {@link augmentStackTraceWithInitialElement}.
* @param {Error} ex
* @return {?Object.<string, *>} Stack trace information.
*/
function computeStackTraceByWalkingCallerChain(ex, depth) {
var functionName = /function\s+([_$a-zA-Z\xA0-\uFFFF][_$a-zA-Z0-9\xA0-\uFFFF]*)?\s*\(/i,
stack = [],
Expand Down Expand Up @@ -582,10 +582,10 @@ TraceKit.computeStackTrace = (function computeStackTraceWrapper() {
}

/**
* Computes a stack trace for an exception.
* @param {Error} ex
* @param {(string|number)=} depth
*/
* Computes a stack trace for an exception.
* @param {Error} ex
* @param {(string|number)=} depth
*/
function computeStackTrace(ex, depth) {
var stack = null;
depth = depth == null ? 0 : +depth;
Expand Down