vm context with accessors
true copy of sandbox properties catch sealed errors, pass global's prototype to CloneObject Fixes #1673
This commit is contained in:
parent
bb3a1d5b67
commit
4527de8cba
13
lib/vm.js
13
lib/vm.js
@ -21,6 +21,19 @@
|
|||||||
|
|
||||||
var binding = process.binding('evals');
|
var binding = process.binding('evals');
|
||||||
|
|
||||||
|
binding.NodeScript._setCloneMethod(function(source, target) {
|
||||||
|
Object.getOwnPropertyNames(source).forEach(function(key) {
|
||||||
|
try {
|
||||||
|
var desc = Object.getOwnPropertyDescriptor(source, key);
|
||||||
|
if (desc.value === source) desc.value = target;
|
||||||
|
|
||||||
|
Object.defineProperty(target, key, desc);
|
||||||
|
} catch (e) {
|
||||||
|
// Catch sealed properties errors
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
exports.Script = binding.NodeScript;
|
exports.Script = binding.NodeScript;
|
||||||
exports.createScript = function(code, ctx, name) {
|
exports.createScript = function(code, ctx, name) {
|
||||||
return new exports.Script(code, ctx, name);
|
return new exports.Script(code, ctx, name);
|
||||||
|
@ -37,9 +37,11 @@ using v8::TryCatch;
|
|||||||
using v8::String;
|
using v8::String;
|
||||||
using v8::Exception;
|
using v8::Exception;
|
||||||
using v8::Local;
|
using v8::Local;
|
||||||
|
using v8::Null;
|
||||||
using v8::Array;
|
using v8::Array;
|
||||||
using v8::Persistent;
|
using v8::Persistent;
|
||||||
using v8::Integer;
|
using v8::Integer;
|
||||||
|
using v8::Function;
|
||||||
using v8::FunctionTemplate;
|
using v8::FunctionTemplate;
|
||||||
|
|
||||||
|
|
||||||
@ -94,10 +96,23 @@ class WrappedScript : ObjectWrap {
|
|||||||
static Handle<Value> CompileRunInThisContext(const Arguments& args);
|
static Handle<Value> CompileRunInThisContext(const Arguments& args);
|
||||||
static Handle<Value> CompileRunInNewContext(const Arguments& args);
|
static Handle<Value> CompileRunInNewContext(const Arguments& args);
|
||||||
|
|
||||||
|
static Handle<Value> SetCloneMethod(const Arguments& args);
|
||||||
|
|
||||||
Persistent<Script> script_;
|
Persistent<Script> script_;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
Persistent<Function> cloneObjectMethod;
|
||||||
|
|
||||||
|
void CloneObject(Handle<Object> recv,
|
||||||
|
Handle<Value> source, Handle<Value> target) {
|
||||||
|
HandleScope scope;
|
||||||
|
|
||||||
|
Handle<Value> args[] = {source, target};
|
||||||
|
cloneObjectMethod->Call(recv, 2, args);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void WrappedContext::Initialize(Handle<Object> target) {
|
void WrappedContext::Initialize(Handle<Object> target) {
|
||||||
HandleScope scope;
|
HandleScope scope;
|
||||||
|
|
||||||
@ -177,6 +192,10 @@ void WrappedScript::Initialize(Handle<Object> target) {
|
|||||||
"runInNewContext",
|
"runInNewContext",
|
||||||
WrappedScript::RunInNewContext);
|
WrappedScript::RunInNewContext);
|
||||||
|
|
||||||
|
NODE_SET_PROTOTYPE_METHOD(constructor_template,
|
||||||
|
"_setCloneMethod",
|
||||||
|
WrappedScript::SetCloneMethod);
|
||||||
|
|
||||||
NODE_SET_METHOD(constructor_template,
|
NODE_SET_METHOD(constructor_template,
|
||||||
"createContext",
|
"createContext",
|
||||||
WrappedScript::CreateContext);
|
WrappedScript::CreateContext);
|
||||||
@ -193,6 +212,10 @@ void WrappedScript::Initialize(Handle<Object> target) {
|
|||||||
"runInNewContext",
|
"runInNewContext",
|
||||||
WrappedScript::CompileRunInNewContext);
|
WrappedScript::CompileRunInNewContext);
|
||||||
|
|
||||||
|
NODE_SET_METHOD(constructor_template,
|
||||||
|
"_setCloneMethod",
|
||||||
|
WrappedScript::SetCloneMethod);
|
||||||
|
|
||||||
target->Set(String::NewSymbol("NodeScript"),
|
target->Set(String::NewSymbol("NodeScript"),
|
||||||
constructor_template->GetFunction());
|
constructor_template->GetFunction());
|
||||||
}
|
}
|
||||||
@ -225,14 +248,8 @@ Handle<Value> WrappedScript::CreateContext(const Arguments& args) {
|
|||||||
|
|
||||||
if (args.Length() > 0) {
|
if (args.Length() > 0) {
|
||||||
Local<Object> sandbox = args[0]->ToObject();
|
Local<Object> sandbox = args[0]->ToObject();
|
||||||
Local<Array> keys = sandbox->GetPropertyNames();
|
|
||||||
|
|
||||||
for (uint32_t i = 0; i < keys->Length(); i++) {
|
CloneObject(args.This(), sandbox, context);
|
||||||
Handle<String> key = keys->Get(Integer::New(i))->ToString();
|
|
||||||
Handle<Value> value = sandbox->Get(key);
|
|
||||||
if(value == sandbox) { value = context; }
|
|
||||||
context->Set(key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@ -275,6 +292,15 @@ Handle<Value> WrappedScript::CompileRunInNewContext(const Arguments& args) {
|
|||||||
WrappedScript::EvalMachine<compileCode, newContext, returnResult>(args);
|
WrappedScript::EvalMachine<compileCode, newContext, returnResult>(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Handle<Value> WrappedScript::SetCloneMethod(const Arguments& args) {
|
||||||
|
HandleScope scope;
|
||||||
|
|
||||||
|
Local<Function> cloneObjectMethod_ = Local<Function>::Cast(args[0]);
|
||||||
|
cloneObjectMethod = Persistent<Function>::New(cloneObjectMethod_);
|
||||||
|
|
||||||
|
return scope.Close(Null());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
template <WrappedScript::EvalInputFlags input_flag,
|
template <WrappedScript::EvalInputFlags input_flag,
|
||||||
WrappedScript::EvalContextFlags context_flag,
|
WrappedScript::EvalContextFlags context_flag,
|
||||||
@ -343,14 +369,7 @@ Handle<Value> WrappedScript::EvalMachine(const Arguments& args) {
|
|||||||
|
|
||||||
// Copy everything from the passed in sandbox (either the persistent
|
// Copy everything from the passed in sandbox (either the persistent
|
||||||
// context for runInContext(), or the sandbox arg to runInNewContext()).
|
// context for runInContext(), or the sandbox arg to runInNewContext()).
|
||||||
keys = sandbox->GetPropertyNames();
|
CloneObject(args.This(), sandbox, context->Global()->GetPrototype());
|
||||||
|
|
||||||
for (i = 0; i < keys->Length(); i++) {
|
|
||||||
Handle<String> key = keys->Get(Integer::New(i))->ToString();
|
|
||||||
Handle<Value> value = sandbox->Get(key);
|
|
||||||
if (value == sandbox) { value = context->Global(); }
|
|
||||||
context->Global()->Set(key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Catch errors
|
// Catch errors
|
||||||
@ -408,13 +427,7 @@ Handle<Value> WrappedScript::EvalMachine(const Arguments& args) {
|
|||||||
|
|
||||||
if (context_flag == userContext || context_flag == newContext) {
|
if (context_flag == userContext || context_flag == newContext) {
|
||||||
// success! copy changes back onto the sandbox object.
|
// success! copy changes back onto the sandbox object.
|
||||||
keys = context->Global()->GetPropertyNames();
|
CloneObject(args.This(), context->Global()->GetPrototype(), sandbox);
|
||||||
for (i = 0; i < keys->Length(); i++) {
|
|
||||||
Handle<String> key = keys->Get(Integer::New(i))->ToString();
|
|
||||||
Handle<Value> value = context->Global()->Get(key);
|
|
||||||
if (value == context->Global()) { value = sandbox; }
|
|
||||||
sandbox->Set(key, value);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context_flag == newContext) {
|
if (context_flag == newContext) {
|
||||||
|
26
test/simple/test-vm-create-context-accessors.js
Normal file
26
test/simple/test-vm-create-context-accessors.js
Normal file
@ -0,0 +1,26 @@
|
|||||||
|
var common = require('../common');
|
||||||
|
var assert = require('assert');
|
||||||
|
var vm = require('vm');
|
||||||
|
|
||||||
|
var ctx = {};
|
||||||
|
|
||||||
|
Object.defineProperty(ctx, 'getter', {
|
||||||
|
get: function() {
|
||||||
|
return 'ok';
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var val;
|
||||||
|
Object.defineProperty(ctx, 'setter', {
|
||||||
|
set: function(_val) {
|
||||||
|
val = _val;
|
||||||
|
},
|
||||||
|
get: function() {
|
||||||
|
return 'ok=' + val;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
ctx = vm.createContext(ctx);
|
||||||
|
|
||||||
|
var result = vm.runInContext('setter = "test";[getter,setter]', ctx);
|
||||||
|
assert.deepEqual(result, ['ok', 'ok=test']);
|
Loading…
x
Reference in New Issue
Block a user