vm: fix crash on fatal error in debug context
Ensure that the debug context has an Environment assigned in case a fatal error is raised. The fatal exception handler in node.cc is not equipped to deal with contexts that don't have one and can't easily be taught that due to a deficiency in the V8 API: there is no way for the embedder to tell if the data index is in use. Fixes: https://github.com/iojs/io.js/issues/1190 PR-URL: https://github.com/iojs/io.js/pull/1229 Reviewed-By: Fedor Indutny <fedor@indutny.com>
This commit is contained in:
parent
d8f383ba3f
commit
cf081a4712
@ -474,6 +474,8 @@ class Environment {
|
|||||||
inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; }
|
inline HandleWrapQueue* handle_wrap_queue() { return &handle_wrap_queue_; }
|
||||||
inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; }
|
inline ReqWrapQueue* req_wrap_queue() { return &req_wrap_queue_; }
|
||||||
|
|
||||||
|
static const int kContextEmbedderDataIndex = NODE_CONTEXT_EMBEDDER_DATA_INDEX;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static const int kIsolateSlot = NODE_ISOLATE_SLOT;
|
static const int kIsolateSlot = NODE_ISOLATE_SLOT;
|
||||||
|
|
||||||
@ -482,10 +484,6 @@ class Environment {
|
|||||||
inline ~Environment();
|
inline ~Environment();
|
||||||
inline IsolateData* isolate_data() const;
|
inline IsolateData* isolate_data() const;
|
||||||
|
|
||||||
enum ContextEmbedderDataIndex {
|
|
||||||
kContextEmbedderDataIndex = NODE_CONTEXT_EMBEDDER_DATA_INDEX
|
|
||||||
};
|
|
||||||
|
|
||||||
v8::Isolate* const isolate_;
|
v8::Isolate* const isolate_;
|
||||||
IsolateData* const isolate_data_;
|
IsolateData* const isolate_data_;
|
||||||
uv_check_t immediate_check_handle_;
|
uv_check_t immediate_check_handle_;
|
||||||
|
@ -233,10 +233,32 @@ class ContextifyContext {
|
|||||||
|
|
||||||
|
|
||||||
static void RunInDebugContext(const FunctionCallbackInfo<Value>& args) {
|
static void RunInDebugContext(const FunctionCallbackInfo<Value>& args) {
|
||||||
|
// Ensure that the debug context has an Environment assigned in case
|
||||||
|
// a fatal error is raised. The fatal exception handler in node.cc
|
||||||
|
// is not equipped to deal with contexts that don't have one and
|
||||||
|
// can't easily be taught that due to a deficiency in the V8 API:
|
||||||
|
// there is no way for the embedder to tell if the data index is
|
||||||
|
// in use.
|
||||||
|
struct ScopedEnvironment {
|
||||||
|
ScopedEnvironment(Local<Context> context, Environment* env)
|
||||||
|
: context_(context) {
|
||||||
|
const int index = Environment::kContextEmbedderDataIndex;
|
||||||
|
context->SetAlignedPointerInEmbedderData(index, env);
|
||||||
|
}
|
||||||
|
~ScopedEnvironment() {
|
||||||
|
const int index = Environment::kContextEmbedderDataIndex;
|
||||||
|
context_->SetAlignedPointerInEmbedderData(index, nullptr);
|
||||||
|
}
|
||||||
|
Local<Context> context_;
|
||||||
|
};
|
||||||
|
|
||||||
Local<String> script_source(args[0]->ToString(args.GetIsolate()));
|
Local<String> script_source(args[0]->ToString(args.GetIsolate()));
|
||||||
if (script_source.IsEmpty())
|
if (script_source.IsEmpty())
|
||||||
return; // Exception pending.
|
return; // Exception pending.
|
||||||
Context::Scope context_scope(Debug::GetDebugContext());
|
Local<Context> debug_context = Debug::GetDebugContext();
|
||||||
|
Environment* env = Environment::GetCurrent(args);
|
||||||
|
ScopedEnvironment env_scope(debug_context, env);
|
||||||
|
Context::Scope context_scope(debug_context);
|
||||||
Local<Script> script = Script::Compile(script_source);
|
Local<Script> script = Script::Compile(script_source);
|
||||||
if (script.IsEmpty())
|
if (script.IsEmpty())
|
||||||
return; // Exception pending.
|
return; // Exception pending.
|
||||||
|
4
test/fixtures/vm-run-in-debug-context.js
vendored
Normal file
4
test/fixtures/vm-run-in-debug-context.js
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
if (process.argv[2] === 'handle-fatal-exception')
|
||||||
|
process._fatalException = process.exit.bind(null, 42);
|
||||||
|
|
||||||
|
require('vm').runInDebugContext('*');
|
@ -1,6 +1,7 @@
|
|||||||
var common = require('../common');
|
var common = require('../common');
|
||||||
var assert = require('assert');
|
var assert = require('assert');
|
||||||
var vm = require('vm');
|
var vm = require('vm');
|
||||||
|
var spawn = require('child_process').spawn;
|
||||||
|
|
||||||
assert.throws(function() {
|
assert.throws(function() {
|
||||||
vm.runInDebugContext('*');
|
vm.runInDebugContext('*');
|
||||||
@ -25,3 +26,25 @@ assert.strictEqual(vm.runInDebugContext(), undefined);
|
|||||||
assert.strictEqual(vm.runInDebugContext(0), 0);
|
assert.strictEqual(vm.runInDebugContext(0), 0);
|
||||||
assert.strictEqual(vm.runInDebugContext(null), null);
|
assert.strictEqual(vm.runInDebugContext(null), null);
|
||||||
assert.strictEqual(vm.runInDebugContext(undefined), undefined);
|
assert.strictEqual(vm.runInDebugContext(undefined), undefined);
|
||||||
|
|
||||||
|
// See https://github.com/iojs/io.js/issues/1190, fatal errors should not
|
||||||
|
// crash the process.
|
||||||
|
var script = common.fixturesDir + '/vm-run-in-debug-context.js';
|
||||||
|
var proc = spawn(process.execPath, [script]);
|
||||||
|
var data = [];
|
||||||
|
proc.stdout.on('data', assert.fail);
|
||||||
|
proc.stderr.on('data', data.push.bind(data));
|
||||||
|
proc.once('exit', common.mustCall(function(exitCode, signalCode) {
|
||||||
|
assert.equal(exitCode, 1);
|
||||||
|
assert.equal(signalCode, null);
|
||||||
|
var haystack = Buffer.concat(data).toString('utf8');
|
||||||
|
assert(/SyntaxError: Unexpected token \*/.test(haystack));
|
||||||
|
}));
|
||||||
|
|
||||||
|
var proc = spawn(process.execPath, [script, 'handle-fatal-exception']);
|
||||||
|
proc.stdout.on('data', assert.fail);
|
||||||
|
proc.stderr.on('data', assert.fail);
|
||||||
|
proc.once('exit', common.mustCall(function(exitCode, signalCode) {
|
||||||
|
assert.equal(exitCode, 42);
|
||||||
|
assert.equal(signalCode, null);
|
||||||
|
}));
|
||||||
|
Loading…
x
Reference in New Issue
Block a user