From 7718d5cb56692a7eb102a2e158e5d7aa9a8e77e4 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Tue, 24 Nov 2015 11:59:53 -0700 Subject: [PATCH 1/2] Merge pull request #9773 from atom/mb-ns-prepare-stack-trace-fixes Allow Error.prepareStackTrace to be temporarily reassigned --- spec/compile-cache-spec.coffee | 15 ++++++++++++++ src/compile-cache.js | 38 ++++++++++++++++++++-------------- 2 files changed, 38 insertions(+), 15 deletions(-) diff --git a/spec/compile-cache-spec.coffee b/spec/compile-cache-spec.coffee index d80e05fc5..8a6cc214e 100644 --- a/spec/compile-cache-spec.coffee +++ b/spec/compile-cache-spec.coffee @@ -69,3 +69,18 @@ describe 'CompileCache', -> CompileCache.addPathToCache(path.join(fixtures, 'cson.cson'), atomHome) expect(CSONParser.parse.callCount).toBe 1 + + describe 'overriding Error.prepareStackTrace', -> + it 'removes the override on the next tick, and always assigns the raw stack', -> + Error.prepareStackTrace = -> 'a-stack-trace' + + error = new Error("Oops") + expect(error.stack).toBe 'a-stack-trace' + expect(Array.isArray(error.getRawStack())).toBe true + + waits(1) + runs -> + error = new Error("Oops again") + console.log error.stack + expect(error.stack).toContain('compile-cache-spec.coffee') + expect(Array.isArray(error.getRawStack())).toBe true diff --git a/src/compile-cache.js b/src/compile-cache.js index f11856a47..aed72ee36 100644 --- a/src/compile-cache.js +++ b/src/compile-cache.js @@ -160,25 +160,33 @@ require('source-map-support').install({ Error.stackTraceLimit = 30 -var sourceMapPrepareStackTrace = Error.prepareStackTrace -var prepareStackTrace = sourceMapPrepareStackTrace +var prepareStackTraceWithSourceMapping = Error.prepareStackTrace -// Prevent coffee-script from reassigning Error.prepareStackTrace -Object.defineProperty(Error, 'prepareStackTrace', { - get: function () { return prepareStackTrace }, - set: function (newValue) {} -}) +let prepareStackTrace = prepareStackTraceWithSourceMapping -// Enable Grim to access the raw stack without reassigning Error.prepareStackTrace -Error.prototype.getRawStack = function () { // eslint-disable-line no-extend-native - prepareStackTrace = getRawStack - var result = this.stack - prepareStackTrace = sourceMapPrepareStackTrace - return result +function prepareStackTraceWithRawStackAssignment (error, frames) { + error.rawStack = frames + return prepareStackTrace(error, frames) } -function getRawStack (_, stack) { - return stack +Object.defineProperty(Error, 'prepareStackTrace', { + get: function () { + return prepareStackTraceWithRawStackAssignment + }, + + set: function (newValue) { + prepareStackTrace = newValue + process.nextTick(function () { + prepareStackTrace = prepareStackTraceWithSourceMapping + }) + } +}) + +Error.prototype.getRawStack = function () { // eslint-disable-line no-extend-native + // Access this.stack to ensure prepareStackTrace has been run on this error + // because it assigns this.rawStack as a side-effect + this.stack + return this.rawStack } Object.keys(COMPILERS).forEach(function (extension) { From 3567d477903d837ad68d8f828696d8a93fc7a356 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Mon, 30 Nov 2015 12:32:06 -0800 Subject: [PATCH 2/2] Merge pull request #9878 from atom/ns-mb-fix-prepare-stack-trace-recursion Avoid infinite recursion in Error.prepareStackTrace --- spec/compile-cache-spec.coffee | 23 ++++++++++++++++++++++- src/compile-cache.js | 8 ++++++-- 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/spec/compile-cache-spec.coffee b/spec/compile-cache-spec.coffee index 8a6cc214e..848da6b49 100644 --- a/spec/compile-cache-spec.coffee +++ b/spec/compile-cache-spec.coffee @@ -81,6 +81,27 @@ describe 'CompileCache', -> waits(1) runs -> error = new Error("Oops again") - console.log error.stack expect(error.stack).toContain('compile-cache-spec.coffee') expect(Array.isArray(error.getRawStack())).toBe true + + it 'does not infinitely loop when the original prepareStackTrace value is reassigned', -> + originalPrepareStackTrace = Error.prepareStackTrace + + Error.prepareStackTrace = -> 'a-stack-trace' + Error.prepareStackTrace = originalPrepareStackTrace + + error = new Error('Oops') + expect(error.stack).toContain('compile-cache-spec.coffee') + expect(Array.isArray(error.getRawStack())).toBe true + + it 'does not infinitely loop when the assigned prepareStackTrace calls the original prepareStackTrace', -> + originalPrepareStackTrace = Error.prepareStackTrace + + Error.prepareStackTrace = (error, stack) -> + error.foo = 'bar' + originalPrepareStackTrace(error, stack) + + error = new Error('Oops') + expect(error.stack).toContain('compile-cache-spec.coffee') + expect(error.foo).toBe('bar') + expect(Array.isArray(error.getRawStack())).toBe true diff --git a/src/compile-cache.js b/src/compile-cache.js index aed72ee36..fde04a2f4 100644 --- a/src/compile-cache.js +++ b/src/compile-cache.js @@ -165,8 +165,12 @@ var prepareStackTraceWithSourceMapping = Error.prepareStackTrace let prepareStackTrace = prepareStackTraceWithSourceMapping function prepareStackTraceWithRawStackAssignment (error, frames) { - error.rawStack = frames - return prepareStackTrace(error, frames) + if (error.rawStack) { // avoid infinite recursion + return prepareStackTraceWithSourceMapping(error, frames) + } else { + error.rawStack = frames + return prepareStackTrace(error, frames) + } } Object.defineProperty(Error, 'prepareStackTrace', {