Skip to content

Commit 5700352

Browse files
committedJan 26, 2016
src: attach error to stack on displayErrors
The vm module's displayErrors option attaches error arrow messages as a hidden property. Later, core JavaScript code can optionally decorate the error stack with the arrow message. However, when user code catches an error, it has no way to access the arrow message. This commit changes the behavior of displayErrors to mean "decorate the error stack if an error occurs." Fixes: nodejs#4835 PR-URL: nodejs#4874 Reviewed-By: Ben Noordhuis <[email protected]>
1 parent d66f18e commit 5700352

File tree

7 files changed

+68
-28
lines changed

7 files changed

+68
-28
lines changed
 

‎doc/api/vm.markdown

+12-12
Original file line numberDiff line numberDiff line change
@@ -32,10 +32,10 @@ The options when creating a script are:
3232
displayed in stack traces
3333
- `columnOffset`: allows you to add an offset to the column number that is
3434
displayed in stack traces
35-
- `displayErrors`: whether or not to print any errors to stderr, with the
36-
line of code that caused them highlighted, before throwing an exception.
37-
Applies only to syntax errors compiling the code; errors while running the
38-
code are controlled by the options to the script's methods.
35+
- `displayErrors`: if `true`, on error, attach the line of code that caused
36+
the error to the stack trace. Applies only to syntax errors compiling the
37+
code; errors while running the code are controlled by the options to the
38+
script's methods.
3939
- `timeout`: a number of milliseconds to execute `code` before terminating
4040
execution. If execution is terminated, an [`Error`][] will be thrown.
4141
- `cachedData`: an optional `Buffer` with V8's code cache data for the supplied
@@ -150,10 +150,10 @@ The options for running a script are:
150150
displayed in stack traces
151151
- `columnOffset`: allows you to add an offset to the column number that is
152152
displayed in stack traces
153-
- `displayErrors`: whether or not to print any errors to stderr, with the
154-
line of code that caused them highlighted, before throwing an exception.
155-
Applies only to runtime errors executing the code; it is impossible to create
156-
a `Script` instance with syntax errors, as the constructor will throw.
153+
- `displayErrors`: if `true`, on error, attach the line of code that caused
154+
the error to the stack trace. Applies only to runtime errors executing the
155+
code; it is impossible to create a `Script` instance with syntax errors, as
156+
the constructor will throw.
157157
- `timeout`: a number of milliseconds to execute the script before terminating
158158
execution. If execution is terminated, an [`Error`][] will be thrown.
159159

@@ -290,10 +290,10 @@ e.g. `(0,eval)('code')`. However, it also has the following additional options:
290290
displayed in stack traces
291291
- `columnOffset`: allows you to add an offset to the column number that is
292292
displayed in stack traces
293-
- `displayErrors`: whether or not to print any errors to stderr, with the
294-
line of code that caused them highlighted, before throwing an exception.
295-
Will capture both syntax errors from compiling `code` and runtime errors
296-
thrown by executing the compiled code. Defaults to `true`.
293+
- `displayErrors`: if `true`, on error, attach the line of code that caused
294+
the error to the stack trace. Will capture both syntax errors from compiling
295+
`code` and runtime errors thrown by executing the compiled code. Defaults to
296+
`true`.
297297
- `timeout`: a number of milliseconds to execute `code` before terminating
298298
execution. If execution is terminated, an [`Error`][] will be thrown.
299299

‎lib/module.js

+6-12
Original file line numberDiff line numberDiff line change
@@ -23,16 +23,6 @@ function hasOwnProperty(obj, prop) {
2323
}
2424

2525

26-
function tryWrapper(wrapper, opts) {
27-
try {
28-
return runInThisContext(wrapper, opts);
29-
} catch (e) {
30-
internalUtil.decorateErrorStack(e);
31-
throw e;
32-
}
33-
}
34-
35-
3626
function stat(filename) {
3727
filename = path._makeLong(filename);
3828
const cache = stat.cache;
@@ -394,8 +384,12 @@ Module.prototype._compile = function(content, filename) {
394384
// create wrapper function
395385
var wrapper = Module.wrap(content);
396386

397-
var compiledWrapper = tryWrapper(wrapper,
398-
{ filename: filename, lineOffset: 0 });
387+
var compiledWrapper = runInThisContext(wrapper, {
388+
filename: filename,
389+
lineOffset: 0,
390+
displayErrors: true
391+
});
392+
399393
if (global.v8debug) {
400394
if (!resolvedArgv) {
401395
// we enter the repl if we're not given a filename argument.

‎src/node.js

+3-2
Original file line numberDiff line numberDiff line change
@@ -605,7 +605,7 @@
605605
'global.require = require;\n' +
606606
'return require("vm").runInThisContext(' +
607607
JSON.stringify(body) + ', { filename: ' +
608-
JSON.stringify(name) + ' });\n';
608+
JSON.stringify(name) + ', displayErrors: true });\n';
609609
// Defer evaluation for a tick. This is a workaround for deferred
610610
// events not firing when evaluating scripts from the command line,
611611
// see https://github.com/nodejs/node/issues/1600.
@@ -988,7 +988,8 @@
988988

989989
var fn = runInThisContext(source, {
990990
filename: this.filename,
991-
lineOffset: 0
991+
lineOffset: 0,
992+
displayErrors: true
992993
});
993994
fn(this.exports, NativeModule.require, this, this.filename);
994995

‎src/node_contextify.cc

+26-2
Original file line numberDiff line numberDiff line change
@@ -541,7 +541,7 @@ class ContextifyScript : public BaseObject {
541541

542542
if (v8_script.IsEmpty()) {
543543
if (display_errors) {
544-
AppendExceptionLine(env, try_catch.Exception(), try_catch.Message());
544+
DecorateErrorStack(env, try_catch);
545545
}
546546
try_catch.ReThrow();
547547
return;
@@ -640,6 +640,30 @@ class ContextifyScript : public BaseObject {
640640
}
641641
}
642642

643+
static void DecorateErrorStack(Environment* env, const TryCatch& try_catch) {
644+
Local<Value> exception = try_catch.Exception();
645+
646+
if (!exception->IsObject())
647+
return;
648+
649+
Local<Object> err_obj = exception.As<Object>();
650+
651+
if (IsExceptionDecorated(env, err_obj))
652+
return;
653+
654+
AppendExceptionLine(env, exception, try_catch.Message());
655+
Local<Value> stack = err_obj->Get(env->stack_string());
656+
Local<Value> arrow = err_obj->GetHiddenValue(env->arrow_message_string());
657+
658+
if (!(stack->IsString() && arrow->IsString()))
659+
return;
660+
661+
Local<String> decorated_stack = String::Concat(arrow.As<String>(),
662+
stack.As<String>());
663+
err_obj->Set(env->stack_string(), decorated_stack);
664+
err_obj->SetHiddenValue(env->decorated_string(), True(env->isolate()));
665+
}
666+
643667
static int64_t GetTimeoutArg(const FunctionCallbackInfo<Value>& args,
644668
const int i) {
645669
if (args[i]->IsUndefined() || args[i]->IsString()) {
@@ -816,7 +840,7 @@ class ContextifyScript : public BaseObject {
816840
if (result.IsEmpty()) {
817841
// Error occurred during execution of the script.
818842
if (display_errors) {
819-
AppendExceptionLine(env, try_catch.Exception(), try_catch.Message());
843+
DecorateErrorStack(env, try_catch);
820844
}
821845
try_catch.ReThrow();
822846
return false;

‎src/node_internals.h

+2
Original file line numberDiff line numberDiff line change
@@ -125,6 +125,8 @@ inline static int snprintf(char *buffer, size_t n, const char *format, ...) {
125125
# define NO_RETURN
126126
#endif
127127

128+
bool IsExceptionDecorated(Environment* env, v8::Local<v8::Value> er);
129+
128130
void AppendExceptionLine(Environment* env,
129131
v8::Local<v8::Value> er,
130132
v8::Local<v8::Message> message);

‎test/message/vm_display_syntax_error.js

+6
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,12 @@ var vm = require('vm');
44

55
console.error('beginning');
66

7+
try {
8+
vm.runInThisContext('var 4;', { filename: 'foo.vm', displayErrors: true });
9+
} catch (err) {
10+
console.error(err.stack);
11+
}
12+
713
vm.runInThisContext('var 5;', { filename: 'test.vm' });
814

915
console.error('end');

‎test/message/vm_display_syntax_error.out

+13
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,18 @@
11
beginning
22

3+
foo.vm:1
4+
var 4;
5+
^
6+
SyntaxError: Unexpected number
7+
at Object.exports.runInThisContext (vm.js:*)
8+
at Object.<anonymous> (*test*message*vm_display_syntax_error.js:*)
9+
at Module._compile (module.js:*)
10+
at Object.Module._extensions..js (module.js:*)
11+
at Module.load (module.js:*)
12+
at Function.Module._load (module.js:*)
13+
at Function.Module.runMain (module.js:*)
14+
at startup (node.js:*)
15+
at node.js:*
316
test.vm:1
417
var 5;
518
^

0 commit comments

Comments
 (0)
Please sign in to comment.