Skip to content

Commit

Permalink
Switch back to Error.prepareStackTrace: Memory leak caused by Error.c…
Browse files Browse the repository at this point in the history
…aptureStackTrace invoking prepareStackTrace
  • Loading branch information
Adam Crabtree committed Apr 1, 2014
1 parent f8f9935 commit 264389e
Show file tree
Hide file tree
Showing 5 changed files with 206 additions and 104 deletions.
112 changes: 112 additions & 0 deletions lib/FormatStackTrace.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
// Copyright 2006-2008 the V8 project authors. All rights reserved.
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are
// met:
//
// * Redistributions of source code must retain the above copyright
// notice, this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above
// copyright notice, this list of conditions and the following
// disclaimer in the documentation and/or other materials provided
// with the distribution.
// * Neither the name of Google Inc. nor the names of its
// contributors may be used to endorse or promote products derived
// from this software without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
// A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
// OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
// SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
// LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
// DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
// THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
function FormatStackTrace(error, frames) {
var lines = [];
try {
lines.push(error.toString());
} catch (e) {
try {
lines.push("<error: " + e + ">");
} catch (ee) {
lines.push("<error>");
}
}
for (var i = 0; i < frames.length; i++) {
var frame = frames[i];
var line;
try {
line = FormatSourcePosition(frame);
} catch (e) {
try {
line = "<error: " + e + ">";
} catch (ee) {
// Any code that reaches this point is seriously nasty!
line = "<error>";
}
}
if (line !== undefined) {
line = " at " + line;
lines.push(line);
}
}
return lines.join("\n");
}

function FormatSourcePosition(frame) {
var fileLocation = "";
if (frame.isNative()) {
fileLocation = "native";
} else if (frame.isEval()) {
fileLocation = "eval at " + frame.getEvalOrigin();
} else {
var fileName = frame.getFileName();
if (fileName) {
fileLocation += fileName;
var lineNumber = frame.getLineNumber();
if (lineNumber != null) {
fileLocation += ":" + lineNumber;
var columnNumber = frame.getColumnNumber();
if (columnNumber) {
fileLocation += ":" + columnNumber;
}
}
}
}
if (!fileLocation) {
fileLocation = "unknown source";
}
var line = "";
var functionName = frame.getFunction().name;
var addPrefix = true;
var isConstructor = frame.isConstructor();
var isMethodCall = !(frame.isToplevel() || isConstructor);
if (isMethodCall) {
var methodName = frame.getMethodName();
line += frame.getTypeName() + ".";
if (functionName) {
line += functionName;
if (methodName && (methodName != functionName)) {
line += " [as " + methodName + "]";
}
} else {
line += methodName || "<anonymous>";
}
} else if (isConstructor) {
line += "new " + (functionName || "<anonymous>");
} else if (functionName) {
line += functionName;
} else {
line += fileLocation;
addPrefix = false;
}
if (addPrefix) {
line += " (" + fileLocation + ")";
}
return line;
}

module.exports = FormatStackTrace
47 changes: 22 additions & 25 deletions lib/formatError.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,42 +6,37 @@ var path = require('path')
// use chalk module, if available
try {chalk = require('chalk') } catch(err) {}

function formatError(err, options) {
err = normalizeError(err)
function formatError(err, stack, options) {
normalizeError(err, stack)

err.stack = formatStack(err
stack = formatStack(stack || ''
, {
lineFormatter: options.lineFormatter
, colors: options.colors
, filter: options.filter
})
return err

return stack
}

// Ensure error conforms to common expectations
function normalizeError(err) {
function coerceToError(err) {
// Coerce to error
if (!isError(err)) {
err = new Error(err)
addNonEnumerableValue(err, 'coerced', true)
// For when Error.stackTraceLimit = 0
} else if (!err.stack) {
addNonEnumerableValue(err, 'stack', String(err))
}

if (err.caught) {
addNonEnumerableValue(err, 'rethrown', true)
} else addNonEnumerableValue(err, 'caught', true)

if (err.normalized) return err

addNonEnumerableValue(err, 'normalized', true)
addNonEnumerableValue(err, 'originalStack', err.stack)
addNonEnumerableValue(err, 'coreThrown', isCoreError(err))
addNonEnumerableValue(err, 'catchable', isCatchableError(err))
err.stack
return err
}

// Ensure error conforms to common expectations
function normalizeError(err, stack) {
addNonEnumerableValue(err, 'originalStack', stack || err.message)
addNonEnumerableValue(err, 'normalized', true)
addNonEnumerableValue(err, 'coreThrown', isCoreError(err))
addNonEnumerableValue(err, 'catchable', isCatchableError(err))
}

function addNonEnumerableValue(obj, property, value) {
Object.defineProperty(obj, property, {
writable: true
Expand All @@ -54,7 +49,7 @@ function addNonEnumerableValue(obj, property, value) {
function isCatchableError(err) {
if (!isCoreError(err)) return true

if (false === err.domainThrown || false === err.domain_thrown) return true
if (true === err.domainThrown || true === err.domain_thrown) return false

// Unexpected runtime errors aren't catchable
if (err instanceof EvalError ||
Expand All @@ -76,13 +71,14 @@ function isCoreError(err) {
}

/* Post-generation formatting */
function formatStack(err, options) {
var stack = err.stack.split('\n')
, newStack = []
function formatStack(stack, options) {
var newStack = []
, lineFormatter = options.lineFormatter || defaultFormatter
, line
, i, l, j, m

stack = stack.split('\n')

for (i=0, l=stack.length; i<l; i++) {
line = lineFormatter(stack[i], {colors: options.colors})
for (j=0, m=options.filter.length; j<m; j++) {
Expand Down Expand Up @@ -129,4 +125,5 @@ function isError(err) {
}

module.exports.formatError = formatError
module.exports.normalizeError = normalizeError
module.exports.coerceToError = coerceToError
module.exports.addNonEnumerableValue = addNonEnumerableValue
Loading

0 comments on commit 264389e

Please sign in to comment.