mirror of https://github.com/nodejs/node.git
module: fix column offsets in errors
Because Node modules are wrapped, errors on the first line of a file leak the wrapper to the user and report the wrong column number. This commit adds a line break to the module wrapper so that the first line is treated the same as all other lines. To compensate for the additional line, a line offset of -1 is also applied to errors. Fixes: https://github.com/nodejs/node/issues/2860 PR-URL: https://github.com/nodejs/node/pull/2867 Reviewed-By: Colin Ihrig <cjihrig@gmail.com>pull/2867/merge
parent
94c3507f5c
commit
dfee4e3712
|
@ -26,10 +26,16 @@ The options when creating a script are:
|
|||
|
||||
- `filename`: allows you to control the filename that shows up in any stack
|
||||
traces produced from this script.
|
||||
- `lineOffset`: allows you to add an offset to the line number that is
|
||||
displayed in stack traces
|
||||
- `columnOffset`: allows you to add an offset to the column number that is
|
||||
displayed in stack traces
|
||||
- `displayErrors`: whether or not to print any errors to stderr, with the
|
||||
line of code that caused them highlighted, before throwing an exception.
|
||||
Applies only to syntax errors compiling the code; errors while running the
|
||||
code are controlled by the options to the script's methods.
|
||||
- `timeout`: a number of milliseconds to execute `code` before terminating
|
||||
execution. If execution is terminated, an `Error` will be thrown.
|
||||
|
||||
### script.runInContext(contextifiedSandbox[, options])
|
||||
|
||||
|
@ -124,8 +130,14 @@ multiple times:
|
|||
|
||||
The options for running a script are:
|
||||
|
||||
- `displayErrors`: whether or not to print any runtime errors to stderr, with
|
||||
the line of code that caused them highlighted, before throwing an exception.
|
||||
- `filename`: allows you to control the filename that shows up in any stack
|
||||
traces produced.
|
||||
- `lineOffset`: allows you to add an offset to the line number that is
|
||||
displayed in stack traces
|
||||
- `columnOffset`: allows you to add an offset to the column number that is
|
||||
displayed in stack traces
|
||||
- `displayErrors`: whether or not to print any errors to stderr, with the
|
||||
line of code that caused them highlighted, before throwing an exception.
|
||||
Applies only to runtime errors executing the code; it is impossible to create
|
||||
a `Script` instance with syntax errors, as the constructor will throw.
|
||||
- `timeout`: a number of milliseconds to execute the script before terminating
|
||||
|
@ -252,6 +264,10 @@ e.g. `(0,eval)('code')`. However, it also has the following additional options:
|
|||
|
||||
- `filename`: allows you to control the filename that shows up in any stack
|
||||
traces produced.
|
||||
- `lineOffset`: allows you to add an offset to the line number that is
|
||||
displayed in stack traces
|
||||
- `columnOffset`: allows you to add an offset to the column number that is
|
||||
displayed in stack traces
|
||||
- `displayErrors`: whether or not to print any errors to stderr, with the
|
||||
line of code that caused them highlighted, before throwing an exception.
|
||||
Will capture both syntax errors from compiling `code` and runtime errors
|
||||
|
|
|
@ -47,7 +47,6 @@ Module.wrapper = NativeModule.wrapper;
|
|||
Module.wrap = NativeModule.wrap;
|
||||
Module._debug = util.debuglog('module');
|
||||
|
||||
|
||||
// We use this alias for the preprocessor that filters it out
|
||||
const debug = Module._debug;
|
||||
|
||||
|
@ -401,7 +400,8 @@ Module.prototype._compile = function(content, filename) {
|
|||
// create wrapper function
|
||||
var wrapper = Module.wrap(content);
|
||||
|
||||
var compiledWrapper = runInThisContext(wrapper, { filename: filename });
|
||||
var compiledWrapper = runInThisContext(wrapper,
|
||||
{ filename: filename, lineOffset: -1 });
|
||||
if (global.v8debug) {
|
||||
if (!resolvedArgv) {
|
||||
// we enter the repl if we're not given a filename argument.
|
||||
|
|
|
@ -955,7 +955,7 @@
|
|||
};
|
||||
|
||||
NativeModule.wrapper = [
|
||||
'(function (exports, require, module, __filename, __dirname) { ',
|
||||
'(function (exports, require, module, __filename, __dirname) {\n',
|
||||
'\n});'
|
||||
];
|
||||
|
||||
|
|
|
@ -504,13 +504,15 @@ class ContextifyScript : public BaseObject {
|
|||
TryCatch try_catch;
|
||||
Local<String> code = args[0]->ToString(env->isolate());
|
||||
Local<String> filename = GetFilenameArg(args, 1);
|
||||
Local<Integer> lineOffset = GetLineOffsetArg(args, 1);
|
||||
Local<Integer> columnOffset = GetColumnOffsetArg(args, 1);
|
||||
bool display_errors = GetDisplayErrorsArg(args, 1);
|
||||
if (try_catch.HasCaught()) {
|
||||
try_catch.ReThrow();
|
||||
return;
|
||||
}
|
||||
|
||||
ScriptOrigin origin(filename);
|
||||
ScriptOrigin origin(filename, lineOffset, columnOffset);
|
||||
ScriptCompiler::Source source(code, origin);
|
||||
Local<UnboundScript> v8_script =
|
||||
ScriptCompiler::CompileUnbound(env->isolate(), &source);
|
||||
|
@ -675,6 +677,39 @@ class ContextifyScript : public BaseObject {
|
|||
}
|
||||
|
||||
|
||||
static Local<Integer> GetLineOffsetArg(
|
||||
const FunctionCallbackInfo<Value>& args,
|
||||
const int i) {
|
||||
Local<Integer> defaultLineOffset = Integer::New(args.GetIsolate(), 0);
|
||||
|
||||
if (!args[i]->IsObject()) {
|
||||
return defaultLineOffset;
|
||||
}
|
||||
|
||||
Local<String> key = FIXED_ONE_BYTE_STRING(args.GetIsolate(), "lineOffset");
|
||||
Local<Value> value = args[i].As<Object>()->Get(key);
|
||||
|
||||
return value->IsUndefined() ? defaultLineOffset : value->ToInteger();
|
||||
}
|
||||
|
||||
|
||||
static Local<Integer> GetColumnOffsetArg(
|
||||
const FunctionCallbackInfo<Value>& args,
|
||||
const int i) {
|
||||
Local<Integer> defaultColumnOffset = Integer::New(args.GetIsolate(), 0);
|
||||
|
||||
if (!args[i]->IsObject()) {
|
||||
return defaultColumnOffset;
|
||||
}
|
||||
|
||||
Local<String> key = FIXED_ONE_BYTE_STRING(args.GetIsolate(),
|
||||
"columnOffset");
|
||||
Local<Value> value = args[i].As<Object>()->Get(key);
|
||||
|
||||
return value->IsUndefined() ? defaultColumnOffset : value->ToInteger();
|
||||
}
|
||||
|
||||
|
||||
static bool EvalMachine(Environment* env,
|
||||
const int64_t timeout,
|
||||
const bool display_errors,
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
error
|
|
@ -60,3 +60,15 @@ var ctx = {};
|
|||
Object.defineProperty(ctx, 'b', { configurable: false });
|
||||
ctx = vm.createContext(ctx);
|
||||
assert.equal(script.runInContext(ctx), false);
|
||||
|
||||
// Error on the first line of a module should
|
||||
// have the correct line and column number
|
||||
assert.throws(function() {
|
||||
vm.runInContext('throw new Error()', context, {
|
||||
filename: 'expected-filename.js',
|
||||
lineOffset: 32,
|
||||
columnOffset: 123
|
||||
});
|
||||
}, function(err) {
|
||||
return /expected-filename.js:33:130/.test(err.stack);
|
||||
}, 'Expected appearance of proper offset in Error stack');
|
||||
|
|
|
@ -279,3 +279,11 @@ process.on('exit', function() {
|
|||
// #1440 Loading files with a byte order marker.
|
||||
assert.equal(42, require('../fixtures/utf8-bom.js'));
|
||||
assert.equal(42, require('../fixtures/utf8-bom.json'));
|
||||
|
||||
// Error on the first line of a module should
|
||||
// have the correct line and column number
|
||||
assert.throws(function() {
|
||||
require('../fixtures/test-error-first-line-offset.js');
|
||||
}, function(err) {
|
||||
return /test-error-first-line-offset.js:1:1/.test(err.stack);
|
||||
}, 'Expected appearance of proper offset in Error stack');
|
||||
|
|
Loading…
Reference in New Issue