Skip to content

Instantly share code, notes, and snippets.

@metamatt
Created March 3, 2015 01:53
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save metamatt/c53e6b80bb3d0c89f9a2 to your computer and use it in GitHub Desktop.
Save metamatt/c53e6b80bb3d0c89f9a2 to your computer and use it in GitHub Desktop.
In NodeJS 0.10 (V8 3.14), V8 Error.stack getter replaces itself on the first call. In NodeJS 0.10 (V8 3.28), it does not. How to tell if it's already been called?
matt@matt-dev ~> ~/node-binaries/nodejs-0.10.33
> e = new Error()
[Error]
> Object.getOwnPropertyDescriptor(e, 'stack')
{ get: [Function],
set: [Function],
enumerable: false,
configurable: true }
> e.stack
'Error\n at repl:1:6\n at REPLServer.self.eval (repl.js:110:21)\n at Interface.<anonymous> (repl.js:239:12)\n at Interface.emit (events.js:95:17)\n at Interface._onLine (readline.js:202:10)\n at Interface._line (readline.js:531:8)\n at Interface._ttyWrite (readline.js:760:14)\n at ReadStream.onkeypress (readline.js:99:10)\n at ReadStream.emit (events.js:98:17)\n at emitKey (readline.js:1095:12)'
> Object.getOwnPropertyDescriptor(e, 'stack')
{ value: 'Error\n at repl:1:6\n at REPLServer.self.eval (repl.js:110:21)\n at Interface.<anonymous> (repl.js:239:12)\n at Interface.emit (events.js:95:17)\n at Interface._onLine (readline.js:202:10)\n at Interface._line (readline.js:531:8)\n at Interface._ttyWrite (readline.js:760:14)\n at ReadStream.onkeypress (readline.js:99:10)\n at ReadStream.emit (events.js:98:17)\n at emitKey (readline.js:1095:12)',
writable: true,
enumerable: true,
configurable: true }
matt@matt-dev ~> ~/node-binaries/nodejs-0.12.0
> e = new Error()
[Error]
> Object.getOwnPropertyDescriptor(e, 'stack')
{ get: [Function],
set: [Function],
enumerable: false,
configurable: true }
> e.stack
'Error\n at repl:1:5\n at REPLServer.defaultEval (repl.js:132:27)\n at bound (domain.js:254:14)\n at REPLServer.runBound [as eval] (domain.js:267:12)\n at REPLServer.<anonymous> (repl.js:279:12)\n at REPLServer.emit (events.js:107:17)\n at REPLServer.Interface._onLine (readline.js:214:10)\n at REPLServer.Interface._line (readline.js:553:8)\n at REPLServer.Interface._ttyWrite (readline.js:830:14)\n at ReadStream.onkeypress (readline.js:109:10)'
> Object.getOwnPropertyDescriptor(e, 'stack')
{ get: [Function],
set: [Function],
enumerable: false,
configurable: true }
@metamatt
Copy link
Author

metamatt commented Mar 3, 2015

'use strict';

var assert = require('assert');

function revertStackBehavior(holder) {
   var pd = Object.getOwnPropertyDescriptor(holder, 'stack');
   function getAndReset() {
      console.log('read via getter, should happen only once');
      var stack = pd.get.call(this);
      overwrite(stack);
      return stack;
   }
   function overwrite(newValue) {
      console.log('write, should replace getter');
      Object.defineProperty(holder, 'stack', { value: newValue });
   }
   var res = Object.defineProperty(holder, 'stack', {
      get: getAndReset,
      set: overwrite,
      enumerable: false,
      configurable: true,
   });
   console.log('redefine result', res);
}

var e = new Error();
var pd = Object.getOwnPropertyDescriptor(e, 'stack');
console.log('e.stack pd before mucking with it', pd);

revertStackBehavior(e);

pd = Object.getOwnPropertyDescriptor(e, 'stack');
console.log('e.stack pd before read', pd);
var stack = e.stack;
console.log('first read of stack', stack);
pd = Object.getOwnPropertyDescriptor(e, 'stack');
console.log('e.stack pd after read', pd);
var stack2 = e.stack;
console.log('second read of stack', stack2);
assert(stack === stack2);

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment