[v8-users] Re: Is there any way to create a Handle from a Handle?

Mon, 02 Mar 2009 14:03:29 -0800

Your problem is apparently that the same object cannot be in multiple  
contexts at once.

Or, more likely, it cannot be the global object of one context and  
still be used in another context. That would explain the presence of a  
DetachGlobal (or something like that) function in Context to allow you  
to re-use the context's global object.

You can get the object back; if you use Context::DetachGlobal() and  
Context::Global(), you should be able to use the object again. The  
only problem is that the original object still won't be modified -- it  
will still have been set to NULL. But then again, do you really want  
to allow one context to modify a variable from another? If your sub- 
context can modify an object in the original context, you might have a  
security concern.

For instance, what if you used this:
var obj = {"foo": this}; //passing the global scope
evalcx(code, obj); //we just gave the other context our global scope.  
Security!

Of course, if you have complete, 100% control over the code calling  
evalcx, this wouldn't be a problem, I suppose.

A possibly simpler and more secure alternative might be to pass the  
object back. Your JavaScript code would then look like:

obj = evalcx(code, obj);

Also, just wondering, why do they need to be global variables? Why  
have the variables be global, instead of members of an object passed  
to a function? You could then just create a new context, load the  
script, find the script's function, and pass it the object. You'd  
still have the security of multiple contexts, but things would be a  
lot simpler.

Alex Iskander

On Mar 2, 2009, at 3:10 PM, Isaac Z. Schlueter wrote:

>
>
>
> On Mar 2, 9:18 am, Alex Iskander <[email protected]> wrote:
>> You may be able to use this to call Context::New(0, GlobalTemplate,
>> GlobalObject);
>>
>> Where GlobalObject is the object passed to evalcx.
>
> Thanks, Alex.
>
> That seems to do two things:
> 1. the code executes in a new context with no globals.
> 2. the object passed to evalcx is set to null. (!?)
>
> Here's my code:
>
> // the c++ function
> static v8::Handle<v8::Value> EvalCX (const v8::Arguments& args)
> {
>       v8::HandleScope handlescope;
>       v8::String::Utf8Value code(args[0]);
>       v8::Local<v8::Object> sandbox = args[1]->ToObject();
>       v8::Handle<v8::String> source = v8::String::New(*code);
>
>       // Create a new execution environment for sandbox
>       // problem here.
>       v8::Handle<v8::Context> context = v8::Context::New(NULL,
> Handle<ObjectTemplate>(), sandbox);
>
>       // Enter the newly created execution environment.
>       v8::Context::Scope context_scope(context);
>
>       v8::Handle<v8::Script> script = v8::Script::Compile(source,
> v8::String::New("evalcx"));
>       if (script.IsEmpty()) return v8::ThrowException(v8::String::New
> ("Error parsing script"));
>
>       // destroys the sandbox object!?
>       v8::Handle<v8::Value> result = script->Run();
>       if (result.IsEmpty()) return v8::ThrowException(v8::String::New
> ("Error running script"));
>
>       return result;
> }
>
> // the binding to global in main()
> global->Set(v8::String::New("evalcx"), v8::FunctionTemplate::New
> (EvalCX)->GetFunction());
>
> // the js
> code = "foo = 1; bar = 2;";
> foo = 2;
> o = { foo : 0 };
> evalcx(code, obj);
> print( o.foo ); // expected: 1. actual: error, o is null
> print( o.bar ); // expected: 2. actual: error, o is null
> print( foo ); // expected: 2. actual: 2
> print( bar ); // expected: undefined. actual: undefined
>
> So, it looks like it's taking the code out of the caller's global
> context, and putting it into a new context.  That's great. However,
> it's also destroying the object that gets passed in, rather than
> modifying it.
>
>
>
>>
>> However, it may not work; I'm not certain what would happen if you
>> pass an object belonging to another context as a global object of a
>> new context.
>>
>> So, plan B might be to manually copy the items from your global  
>> object
>> passed to evalcx to the global object for your new context.
>>
>> I hope that helps,
>>
>> Alex
>>
>> On Mar 2, 2009, at 11:05 AM, Isaac Z. Schlueter wrote:
>>
>>
>>
>>
>>
>>> Thanks, Stephan.
>>
>>> It looks like what you're doing will execute the code and set "this"
>>> to the object in question.
>>
>>> However, what I'd really like to do is execute code and set a given
>>> object as the global scope.  Here's an example with some code:
>>
>>> var code = "var foo = 'bar';";
>>> var obj = { foo : "baz" };
>>> evalcx( code, obj ); // execute code using "obj" as the global  
>>> object
>>> print( obj.foo ); // prints "bar"
>>
>>> Unless I'm misreading your example, what you're describing will work
>>> in this case:
>>
>>> var code = "this.foo = 'bar';";
>>> var obj = { foo : "baz" };
>>
>>> But, I can already do that from JS like so:
>>
>>> (new Function(code)).call(obj);
>>
>>> If I could eval code in an arbitrary global scope within Javascript,
>>> which did not have any access to the global scope, then it would be
>>> possible to implement a capability-based security model.
>>
>>> Also, it would make it possible to load and execute many different
>>> scripts in a row without having to "clean up" the globals that each
>>> one might create.  After being evaluated, the temporary global scope
>>> could be discarded, and would be garbage collected normally.
>>
>>> For example, let's say you have a fastcgi handler written in
>>> Javascript, which reads and evals the SCRIPT_FILENAME file.  The
>>> problem is that, since the evaled code shares a global scope with  
>>> the
>>> fcgi handler, it also shares a global scope with *every other script
>>> loaded by that handler.*  That means that every global variable is
>>> persistent in memory, and only gets garbage collected when you  
>>> restart
>>> the server.  Not ideal! :)
>>
>>> --
>>> Isaac Z. Schlueter
>>
>>> On Mar 1, 5:06 pm, Stephan Beal <[email protected]> wrote:
>>>> On Mar 2, 1:34 am, "Isaac Z. Schlueter" <[email protected]> wrote:
>>
>>>>> I'm trying to write a function that will execute a bit of  
>>>>> Javascript
>>>>> within an arbitrary global scope.  Something like the "evalcx"
>>>>> function in the Spidermonkey shell.
>>
>>>>> I've got a function defined and exposed to the Javascript that  
>>>>> takes
>>>>> an object as an argument, and stores it as a Handle<Object>.
>>>>> However,
>>>>> in order to create a new execution context, I need a
>>>>> Handle<ObjectTemplate>.
>>
>>>> Do you need a new Context, or just an object to eval the code in?  
>>>> If
>>>> you just need an Object to execute the code in...
>>
>>>> They way i ended up doing this was getting the 'eval' function from
>>>> my
>>>> local object, then using Call() on that Function object:
>>
>>>>         TryCatch tryer;
>>>>         Local<Value> rv;
>>>>         Local<Function> eval = Function::Cast( *(db->jsobj-
>>>>> Get(String::New
>>>> ("eval"))) );
>>>> // ^^^^^ db->jsobj is my context object
>>>>         for( int i = 0; i < argc; ++i )
>>>>         {
>>>>             char const * cp = reinterpret_cast<char const *>
>>>> ( sqlite3_value_text( argv[i] ) );
>>>>             if( ! cp || !*cp ) continue;
>>>>             Local<Value> arg = String::New( cp,
>>>> sqlite3_value_bytes( argv
>>>> [i] ) );
>>>>             rv = eval->Call( db->jsobj, 1, &arg );
>>>> // ^^^^ that will, in theory, eval the code in the context of db-
>>>>> jsobj
>>
>>>>             if( rv.IsEmpty() )
>>>>             {
>>>>                 std::string
>>>> err( CastFromJS<std::string>( tryer.Exception() ) );
>>>>                 sqlite3_result_text( context, err.c_str(),
>>>> static_cast<int>(err.size
>>>> ()), SQLITE_TRANSIENT );
>>>>                 return;
>>>>             }
>>>>         }
>>
>> Alex Iskander
>> Web and Marketing
>> TPSi
> >






--~--~---------~--~----~------------~-------~--~----~
v8-users mailing list
[email protected]
http://groups.google.com/group/v8-users
-~----------~----~----~----~------~----~------~--~---

Reply via email to