Skip to content
This repository has been archived by the owner on Apr 22, 2023. It is now read-only.

Commit

Permalink
vm context with accessors
Browse files Browse the repository at this point in the history
true copy of sandbox properties

catch sealed errors, pass global's prototype to CloneObject

Fixes #1673
  • Loading branch information
indutny authored and ry committed Sep 8, 2011
1 parent bb3a1d5 commit 4527de8
Show file tree
Hide file tree
Showing 3 changed files with 74 additions and 22 deletions.
13 changes: 13 additions & 0 deletions lib/vm.js
Expand Up @@ -21,6 +21,19 @@

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.createScript = function(code, ctx, name) {
return new exports.Script(code, ctx, name);
Expand Down
57 changes: 35 additions & 22 deletions src/node_script.cc
Expand Up @@ -37,9 +37,11 @@ using v8::TryCatch;
using v8::String;
using v8::Exception;
using v8::Local;
using v8::Null;
using v8::Array;
using v8::Persistent;
using v8::Integer;
using v8::Function;
using v8::FunctionTemplate;


Expand Down Expand Up @@ -94,10 +96,23 @@ class WrappedScript : ObjectWrap {
static Handle<Value> CompileRunInThisContext(const Arguments& args);
static Handle<Value> CompileRunInNewContext(const Arguments& args);

static Handle<Value> SetCloneMethod(const Arguments& args);

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) {
HandleScope scope;

Expand Down Expand Up @@ -177,6 +192,10 @@ void WrappedScript::Initialize(Handle<Object> target) {
"runInNewContext",
WrappedScript::RunInNewContext);

NODE_SET_PROTOTYPE_METHOD(constructor_template,
"_setCloneMethod",
WrappedScript::SetCloneMethod);

NODE_SET_METHOD(constructor_template,
"createContext",
WrappedScript::CreateContext);
Expand All @@ -193,6 +212,10 @@ void WrappedScript::Initialize(Handle<Object> target) {
"runInNewContext",
WrappedScript::CompileRunInNewContext);

NODE_SET_METHOD(constructor_template,
"_setCloneMethod",
WrappedScript::SetCloneMethod);

target->Set(String::NewSymbol("NodeScript"),
constructor_template->GetFunction());
}
Expand Down Expand Up @@ -225,14 +248,8 @@ Handle<Value> WrappedScript::CreateContext(const Arguments& args) {

if (args.Length() > 0) {
Local<Object> sandbox = args[0]->ToObject();
Local<Array> keys = sandbox->GetPropertyNames();

for (uint32_t 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; }
context->Set(key, value);
}
CloneObject(args.This(), sandbox, context);
}


Expand Down Expand Up @@ -275,6 +292,15 @@ Handle<Value> WrappedScript::CompileRunInNewContext(const Arguments& 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,
WrappedScript::EvalContextFlags context_flag,
Expand Down Expand Up @@ -343,14 +369,7 @@ Handle<Value> WrappedScript::EvalMachine(const Arguments& args) {

// Copy everything from the passed in sandbox (either the persistent
// context for runInContext(), or the sandbox arg to runInNewContext()).
keys = sandbox->GetPropertyNames();

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);
}
CloneObject(args.This(), sandbox, context->Global()->GetPrototype());
}

// Catch errors
Expand Down Expand Up @@ -408,13 +427,7 @@ Handle<Value> WrappedScript::EvalMachine(const Arguments& args) {

if (context_flag == userContext || context_flag == newContext) {
// success! copy changes back onto the sandbox object.
keys = context->Global()->GetPropertyNames();
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);
}
CloneObject(args.This(), context->Global()->GetPrototype(), sandbox);
}

if (context_flag == newContext) {
Expand Down
26 changes: 26 additions & 0 deletions test/simple/test-vm-create-context-accessors.js
@@ -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']);

0 comments on commit 4527de8

Please sign in to comment.