Skip to content

Commit 02966c6

Browse files
kamilogorekHazAT
authored andcommitted
fix: Use 'native code' as a filename for some frames (getsentry#2064)
* fix: Use 'native code' as a filename for some frames * test: Add tests for computeStackTrace native frames * misc: Note regarding Tracekit Chromium browsers
1 parent a872223 commit 02966c6

File tree

2 files changed

+203
-10
lines changed

2 files changed

+203
-10
lines changed

packages/browser/src/tracekit.ts

+9-10
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ interface ComputeStackTrace {
3838
* @param {(string|number)=} depth
3939
*/
4040
(ex: Error, depth?: string | number): StackTrace;
41+
_computeStackTraceFromStackProp(ex: any): StackTrace;
4142
}
4243

4344
/**
@@ -469,10 +470,11 @@ TraceKit._computeStackTrace = (function _computeStackTraceWrapper() {
469470
* @memberof TraceKit._computeStackTrace
470471
*/
471472
function _computeStackTraceFromStackProp(ex: any) {
472-
if (!ex.stack) {
473+
if (!ex || !ex.stack) {
473474
return null;
474475
}
475476

477+
// Chromium based browsers: Chrome, Brave, new Opera, new Edge
476478
var chrome = /^\s*at (?:(.*?) ?\()?((?:file|https?|blob|chrome-extension|native|eval|webpack|<anonymous>|[a-z]:|\/).*?)(?::(\d+))?(?::(\d+))?\)?\s*$/i,
477479
// gecko regex: `(?:bundle|\d+\.js)`: `bundle` is for react native, `\d+\.js` also but specifically for ram bundles because it
478480
// generates filenames without a prefix like `file://` the filenames in the stacktrace are just 42.js
@@ -492,19 +494,17 @@ TraceKit._computeStackTrace = (function _computeStackTraceWrapper() {
492494

493495
for (var i = 0, j = lines.length; i < j; ++i) {
494496
if ((parts = chrome.exec(lines[i]))) {
495-
var isNative = parts[2] && parts[2].indexOf('native') === 0; // start of line
496497
isEval = parts[2] && parts[2].indexOf('eval') === 0; // start of line
497498
if (isEval && (submatch = chromeEval.exec(parts[2]))) {
498499
// throw out eval line/column and use top-most line/column number
499500
parts[2] = submatch[1]; // url
500-
// NOTE: It's messing out our integration tests in Karma, let's see if we can live with it – Kamil
501-
// parts[3] = submatch[2]; // line
502-
// parts[4] = submatch[3]; // column
501+
parts[3] = submatch[2]; // line
502+
parts[4] = submatch[3]; // column
503503
}
504504
element = {
505-
url: !isNative ? parts[2] : null,
505+
url: parts[2],
506506
func: parts[1] || UNKNOWN_FUNCTION,
507-
args: isNative ? [parts[2]] : [],
507+
args: [],
508508
line: parts[3] ? +parts[3] : null,
509509
column: parts[4] ? +parts[4] : null,
510510
};
@@ -521,9 +521,8 @@ TraceKit._computeStackTrace = (function _computeStackTraceWrapper() {
521521
if (isEval && (submatch = geckoEval.exec(parts[3]))) {
522522
// throw out eval line/column and use top-most line number
523523
parts[3] = submatch[1];
524-
// NOTE: It's messing out our integration tests in Karma, let's see if we can live with it – Kamil
525-
// parts[4] = submatch[2];
526-
// parts[5] = null; // no column when eval
524+
parts[4] = submatch[2];
525+
parts[5] = ''; // no column when eval
527526
} else if (i === 0 && !parts[5] && ex.columnNumber !== void 0) {
528527
// FireFox uses this awesome columnNumber property for its top frame
529528
// Also note, Firefox's column number is 0-based and everything else expects 1-based,
+194
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,194 @@
1+
import { expect } from 'chai';
2+
3+
import { _computeStackTrace } from '../src/tracekit';
4+
5+
const CHROME73_NATIVE_CODE_EXCEPTION = {
6+
stack: `Error: test
7+
at fooIterator (http://192.168.20.143:5000/test:20:17)
8+
at Array.map (<anonymous>)
9+
at foo (http://192.168.20.143:5000/test:19:19)
10+
at http://192.168.20.143:5000/test:24:7`,
11+
};
12+
13+
const FIREFOX66_NATIVE_CODE_EXCEPTION = {
14+
stack: `fooIterator@http://192.168.20.143:5000/test:20:17
15+
foo@http://192.168.20.143:5000/test:19:19
16+
@http://192.168.20.143:5000/test:24:7`,
17+
};
18+
19+
const SAFARI12_NATIVE_CODE_EXCEPTION = {
20+
stack: `fooIterator@http://192.168.20.143:5000/test:20:26
21+
map@[native code]
22+
foo@http://192.168.20.143:5000/test:19:22
23+
global code@http://192.168.20.143:5000/test:24:10`,
24+
};
25+
26+
const EDGE44_NATIVE_CODE_EXCEPTION = {
27+
stack: `Error: test
28+
at fooIterator (http://192.168.20.143:5000/test:20:11)
29+
at Array.prototype.map (native code)
30+
at foo (http://192.168.20.143:5000/test:19:9)
31+
at Global code (http://192.168.20.143:5000/test:24:7)`,
32+
};
33+
34+
describe('Tracekit', () => {
35+
describe('computeStackTrace', () => {
36+
it('no exception', () => {
37+
const stacktrace = _computeStackTrace._computeStackTraceFromStackProp(undefined);
38+
expect(stacktrace).equal(null);
39+
});
40+
41+
it('no stack', () => {
42+
const stacktrace = _computeStackTrace._computeStackTraceFromStackProp({});
43+
expect(stacktrace).equal(null);
44+
});
45+
46+
it('chrome73', () => {
47+
const stacktrace = _computeStackTrace._computeStackTraceFromStackProp(CHROME73_NATIVE_CODE_EXCEPTION);
48+
49+
expect(stacktrace.stack).deep.equal([
50+
{
51+
args: [],
52+
column: 17,
53+
context: null,
54+
func: 'fooIterator',
55+
line: 20,
56+
url: 'http://192.168.20.143:5000/test',
57+
},
58+
{
59+
args: [],
60+
column: null,
61+
context: null,
62+
func: 'Array.map',
63+
line: null,
64+
url: '<anonymous>',
65+
},
66+
{
67+
args: [],
68+
column: 19,
69+
context: null,
70+
func: 'foo',
71+
line: 19,
72+
url: 'http://192.168.20.143:5000/test',
73+
},
74+
{
75+
args: [],
76+
column: 7,
77+
context: null,
78+
func: '?',
79+
line: 24,
80+
url: 'http://192.168.20.143:5000/test',
81+
},
82+
]);
83+
});
84+
85+
it('firefox66', () => {
86+
const stacktrace = _computeStackTrace._computeStackTraceFromStackProp(FIREFOX66_NATIVE_CODE_EXCEPTION);
87+
88+
expect(stacktrace.stack).deep.equal([
89+
{
90+
args: [],
91+
column: 17,
92+
context: null,
93+
func: 'fooIterator',
94+
line: 20,
95+
url: 'http://192.168.20.143:5000/test',
96+
},
97+
{
98+
args: [],
99+
column: 19,
100+
context: null,
101+
func: 'foo',
102+
line: 19,
103+
url: 'http://192.168.20.143:5000/test',
104+
},
105+
{
106+
args: [],
107+
column: 7,
108+
context: null,
109+
func: '?',
110+
line: 24,
111+
url: 'http://192.168.20.143:5000/test',
112+
},
113+
]);
114+
});
115+
116+
it('safari12', () => {
117+
const stacktrace = _computeStackTrace._computeStackTraceFromStackProp(SAFARI12_NATIVE_CODE_EXCEPTION);
118+
119+
expect(stacktrace.stack).deep.equal([
120+
{
121+
args: [],
122+
column: 26,
123+
context: null,
124+
func: 'fooIterator',
125+
line: 20,
126+
url: 'http://192.168.20.143:5000/test',
127+
},
128+
{
129+
args: [],
130+
column: null,
131+
context: null,
132+
func: 'map',
133+
line: null,
134+
url: '[native code]',
135+
},
136+
{
137+
args: [],
138+
column: 22,
139+
context: null,
140+
func: 'foo',
141+
line: 19,
142+
url: 'http://192.168.20.143:5000/test',
143+
},
144+
{
145+
args: [],
146+
column: 10,
147+
context: null,
148+
func: 'global code',
149+
line: 24,
150+
url: 'http://192.168.20.143:5000/test',
151+
},
152+
]);
153+
});
154+
155+
it('edge44', () => {
156+
const stacktrace = _computeStackTrace._computeStackTraceFromStackProp(EDGE44_NATIVE_CODE_EXCEPTION);
157+
158+
expect(stacktrace.stack).deep.equal([
159+
{
160+
args: [],
161+
column: 11,
162+
context: null,
163+
func: 'fooIterator',
164+
line: 20,
165+
url: 'http://192.168.20.143:5000/test',
166+
},
167+
{
168+
args: [],
169+
column: null,
170+
context: null,
171+
func: 'Array.prototype.map',
172+
line: null,
173+
url: 'native code',
174+
},
175+
{
176+
args: [],
177+
column: 9,
178+
context: null,
179+
func: 'foo',
180+
line: 19,
181+
url: 'http://192.168.20.143:5000/test',
182+
},
183+
{
184+
args: [],
185+
column: 7,
186+
context: null,
187+
func: 'Global code',
188+
line: 24,
189+
url: 'http://192.168.20.143:5000/test',
190+
},
191+
]);
192+
});
193+
});
194+
});

0 commit comments

Comments
 (0)