Browse Source

Unwind V8 execution context on fatal error, refs #87

This is yet a first hack to prove applicability.  Currently
unwind environment is held in a global variable, i.e. solution
is neither thread safe nor reentrant yet.
Stefan Siegl 11 năm trước cách đây
mục cha
commit
a49fa8ce02
3 tập tin đã thay đổi với 48 bổ sung2 xóa
  1. 2 0
      php_v8js_macros.h
  2. 4 0
      v8js.cc
  3. 42 2
      v8js_convert.cc

+ 2 - 0
php_v8js_macros.h

@@ -205,6 +205,8 @@ struct php_v8js_ctx {
 
   std::vector<php_v8js_accessor_ctx *> accessor_list;
   char *tz;
+
+  bool fatal_error_abort;
 #ifdef ZTS
   void ***zts_ctx;
 #endif

+ 4 - 0
v8js.cc

@@ -1134,6 +1134,10 @@ static PHP_METHOD(V8Js, executeString)
 		php_v8js_timer_pop(TSRMLS_C);
 	}
 
+	if(c->fatal_error_abort) {
+		zend_error(E_ERROR, "V8Js caught fatal error; message lost, sorry :-)");
+	}
+
 	char exception_string[64];
 
 	if (c->time_limit_hit) {

+ 42 - 2
v8js_convert.cc

@@ -30,6 +30,17 @@ extern "C" {
 #include <stdexcept>
 #include <limits>
 
+
+jmp_buf *unwind_env;
+
+static void php_v8js_error_handler(int error_num, const char *error_filename, const uint error_lineno, const char *format, va_list args)
+{
+	longjmp(*unwind_env, 1);
+}
+
+
+
+
 static void php_v8js_weak_object_callback(const v8::WeakCallbackData<v8::Object, zval> &data);
 
 /* Callback for PHP methods and functions */
@@ -43,6 +54,13 @@ static void php_v8js_call_php_func(zval *value, zend_class_entry *ce, zend_funct
 	char *error;
 	int error_len, i, flags = V8JS_FLAG_NONE;
 
+#if PHP_V8_API_VERSION <= 3023008
+	/* Until V8 3.23.8 Isolate could only take one external pointer. */
+	php_v8js_ctx *ctx = (php_v8js_ctx *) isolate->GetData();
+#else
+	php_v8js_ctx *ctx = (php_v8js_ctx *) isolate->GetData(0);
+#endif
+
 	/* Set parameter limits */
 	min_num_args = method_ptr->common.required_num_args;
 	max_num_args = method_ptr->common.num_args;
@@ -125,12 +143,34 @@ static void php_v8js_call_php_func(zval *value, zend_class_entry *ce, zend_funct
 		fcc.called_scope = ce;
 		fcc.object_ptr = value;
 
-		/* Call the method */
-		zend_call_function(&fci, &fcc TSRMLS_CC);
+		jmp_buf env;
+		int val;
+
+		void (*old_error_handler)(int, const char *, const uint, const char*, va_list);
+		old_error_handler = zend_error_cb;
+		zend_error_cb = php_v8js_error_handler;
+
+		val = setjmp (env);
+		unwind_env = &env;
+
+		if (val) {
+			ctx->fatal_error_abort = true;
+			zend_error_cb = old_error_handler;
+		}
+		else {
+			/* Call the method */
+			zend_call_function(&fci, &fcc TSRMLS_CC);
+		}
 	}
 
 	isolate->Enter();
 
+	if(ctx->fatal_error_abort) {
+		v8::V8::TerminateExecution(isolate);
+		info.GetReturnValue().Set(V8JS_NULL);
+		return;
+	}
+
 failure:
 	/* Cleanup */
 	if (argc) {