Terminating a script mid-execution?

79 views
Skip to first unread message

Danny Dorfman

unread,
Jun 19, 2014, 8:04:00 AM6/19/14
to v8-u...@googlegroups.com
Hello guys,

I searched through the group, but couldn't find any responses on this subject.
I'd like to run a script, and terminate it from C++ code, by the decision of a callback function.
I tried using TerminateExectuion(isolate), but the program crashes.

Here is a small sample. I assign values to the "specific" object using JavaScript.
Whenever the "alfa" field is set to "666", I'd like the script to terminate.

-----------------------------------------------------------------------------------------------------------------------------------------------------------------
  1 #include <v8.h>
  2 #include <stdio.h>
  3 using namespace v8;
  4 
  5 void SetAlfa(Local<String> property, Local<Value> value, const PropertyCallbackInfo<void>& info)
  6 {
  7     String::Utf8Value property_str(property);
  8     String::Utf8Value value_str(value);
  9     printf("SetAlfa: about to set %s=%s\n", *property_str, *value_str);
 10     Handle<Value> show_stopper = String::NewFromUtf8(info.GetIsolate(),"666");
 11     if (value->Equals(show_stopper))
 12     {
 13         printf("SetAlfa: STOPPING!\n");
 14         V8::TerminateExecution(info.GetIsolate());
 15     }
 16 }
 17 
 18 void RunIt(Isolate *isolate, const char *script_text)
 19 {
 20     printf("RunIt: about to run \"%s\"\n", script_text);
 21     Handle<String> source = String::NewFromUtf8(isolate,script_text);
 22     Handle<Script> script = Script::Compile(source);
 23     Handle<Value> result = script->Run();
 24     String::Utf8Value ascii(result);
 25     printf("RunIt: returned \"%s\"\n", *ascii);
 26 }
 27 
 28 
 29 int main(int argc, char* argv[])
 30 {
 31     Isolate* isolate = Isolate::GetCurrent();
 32     HandleScope handle_scope(isolate);
 33     Handle<Context> context = Context::New(isolate);
 34     Context::Scope context_scope(context);
 35     Handle<String> alfa_str = String::NewFromUtf8(isolate,"alfa");
 36     Handle<String> specific_str = String::NewFromUtf8(isolate,"specific");
 37 
 38     Handle<Object> specific_obj = Object::New(isolate);
 39     specific_obj->SetAccessor(alfa_str, NULL, SetAlfa);
 40     context->Global()->Set(specific_str, specific_obj);
 41 
 42     RunIt(isolate,"specific.alfa=123");
 43     RunIt(isolate,"specific.alfa=666; specific.alfa=999");
 44 
 45     return 0;
 46 }
-----------------------------------------------------------------------------------------------------------------------------------------------------------------

The output I get is:

-----------------------------------------------------------------------------------------------------------------------------------------------------------------
RunIt: about to run "specific.alfa=123"
SetAlfa: about to set alfa=123
RunIt: returned "123"
RunIt: about to run "specific.alfa=666; specific.alfa=999"
SetAlfa: about to set alfa=666
SetAlfa: STOPPING!
SetAlfa: about to set alfa=(null)


#
# Fatal error in ../src/api.cc, line 2899
# CHECK(!(isolate)->external_caught_exception()) failed
#

==== C stack trace ===============================

 1: V8_Fatal
 2: v8::Value::Equals(v8::Handle<v8::Value>) const
 3: SetAlfa(v8::Local<v8::String>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<void> const&)
 4: v8::internal::PropertyCallbackArguments::Call(void (*)(v8::Local<v8::String>, v8::Local<v8::Value>, v8::PropertyCallbackInfo<void> const&), v8::Local<v8::String>, v8::Local<v8::Value>)
 5: v8::internal::JSObject::SetPropertyWithCallback(v8::internal::Handle<v8::internal::JSObject>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::JSObject>, v8::internal::StrictModeFlag)
 6: v8::internal::JSObject::SetPropertyForResult(v8::internal::Handle<v8::internal::JSObject>, v8::internal::LookupResult*, v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::Object>, PropertyAttributes, v8::internal::StrictModeFlag, v8::internal::JSReceiver::StoreFromKeyed)
 7: v8::internal::JSReceiver::SetProperty(v8::internal::Handle<v8::internal::JSReceiver>, v8::internal::LookupResult*, v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::Object>, PropertyAttributes, v8::internal::StrictModeFlag, v8::internal::JSReceiver::StoreFromKeyed)
 8: v8::internal::JSReceiver::SetProperty(v8::internal::Handle<v8::internal::JSReceiver>, v8::internal::Handle<v8::internal::Name>, v8::internal::Handle<v8::internal::Object>, PropertyAttributes, v8::internal::StrictModeFlag, v8::internal::JSReceiver::StoreFromKeyed)
 9: v8::internal::StoreIC::Store(v8::internal::Handle<v8::internal::Object>, v8::internal::Handle<v8::internal::String>, v8::internal::Handle<v8::internal::Object>, v8::internal::JSReceiver::StoreFromKeyed)
10: ??
11: v8::internal::StoreIC_Miss(int, v8::internal::Object**, v8::internal::Isolate*)
12: ??
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
                                              

Can anyone tell, what I'm doing wrong here?
Thanks in advance,
Danny

Ben Noordhuis

unread,
Jun 19, 2014, 4:39:04 PM6/19/14
to v8-u...@googlegroups.com
V8::TerminateExecution() doesn't terminate execution right away. It
sets a 'is terminating' flag that is checked in the generated code in
function prologues and at loop edges.

The effect of the flag is that of a pending exception and that means
it's no longer allowed to call into the VM (which many V8 API
functions do, like Value::Equals().)

Try adding a V8::IsExecutionTerminating() guard at the top of your
SetAlfa() function.

Danny Dorfman

unread,
Jun 22, 2014, 2:36:48 AM6/22/14
to v8-u...@googlegroups.com
Hello Ben,
I already tried that, but  V8::IsExecutionTerminating() returned false.
I don't know if it's a bug or a feature.

Ben Noordhuis

unread,
Jun 22, 2014, 1:24:01 PM6/22/14
to v8-u...@googlegroups.com
On Sun, Jun 22, 2014 at 8:36 AM, Danny Dorfman <wilder...@gmail.com> wrote:
> I already tried that, but V8::IsExecutionTerminating() returned false.
> I don't know if it's a bug or a feature.

I just remembered something from our code base: termination doesn't go
into effect until you enter the VM again. In our project, we force
that by executing a no-op script, see below. HTH.

void ExitFunction(const v8::FunctionCallbackInfo<v8::Value>& info) {
v8::Isolate* isolate = info.GetIsolate();
v8::HandleScope handle_scope(isolate);
// Sets a thread-local flag that is checked by the JS function prologue.
v8::V8::TerminateExecution(isolate);
// Which means it's not in effect yet.
CHECK_EQ(false, v8::V8::IsExecutionTerminating(isolate));
// Now force the termination exception by entering the VM.
v8::Local<v8::String> script_source = v8::String::NewFromUtf8(isolate, "0");
v8::TryCatch try_catch;
v8::Script::Compile(script_source)->Run();
CHECK_EQ(true, try_catch.HasCaught());
CHECK_EQ(true, try_catch.HasTerminated());
CHECK_EQ(true, v8::V8::IsExecutionTerminating(isolate));
}

Danny Dorfman

unread,
Jun 23, 2014, 3:12:04 AM6/23/14
to v8-u...@googlegroups.com
This is much much better. Thank you for the tip!
Reply all
Reply to author
Forward
0 new messages