mirror of
https://github.com/phpv8/v8js.git
synced 2025-01-18 11:51:51 +00:00
Merge pull request #156 from stesie/php-exception-behaviour
PHP->JS exception propagation
This commit is contained in:
commit
83f51e5021
26
README.md
26
README.md
@ -52,6 +52,7 @@ class V8Js
|
|||||||
|
|
||||||
const FLAG_NONE = 1;
|
const FLAG_NONE = 1;
|
||||||
const FLAG_FORCE_ARRAY = 2;
|
const FLAG_FORCE_ARRAY = 2;
|
||||||
|
const FLAG_PROPAGATE_PHP_EXCEPTIONS = 4;
|
||||||
|
|
||||||
const DEBUG_AUTO_BREAK_NEVER = 1;
|
const DEBUG_AUTO_BREAK_NEVER = 1;
|
||||||
const DEBUG_AUTO_BREAK_ONCE = 2;
|
const DEBUG_AUTO_BREAK_ONCE = 2;
|
||||||
@ -301,3 +302,28 @@ PHP Objects implementing ArrayAccess, Countable
|
|||||||
The above rule that PHP objects are generally converted to JavaScript objects also applies to PHP objects of `ArrayObject` type or other classes, that implement both the `ArrayAccess` and the `Countable` interface -- even so they behave like PHP arrays.
|
The above rule that PHP objects are generally converted to JavaScript objects also applies to PHP objects of `ArrayObject` type or other classes, that implement both the `ArrayAccess` and the `Countable` interface -- even so they behave like PHP arrays.
|
||||||
|
|
||||||
This behaviour can be changed by enabling the php.ini flag `v8js.use_array_access`. If set, objects of PHP classes that implement the aforementioned interfaces are converted to JavaScript Array-like objects. This is by-index access of this object results in immediate calls to the `offsetGet` or `offsetSet` PHP methods (effectively this is live-binding of JavaScript against the PHP object). Such an Array-esque object also supports calling every attached public method of the PHP object + methods of JavaScript's native Array.prototype methods (as long as they are not overloaded by PHP methods).
|
This behaviour can be changed by enabling the php.ini flag `v8js.use_array_access`. If set, objects of PHP classes that implement the aforementioned interfaces are converted to JavaScript Array-like objects. This is by-index access of this object results in immediate calls to the `offsetGet` or `offsetSet` PHP methods (effectively this is live-binding of JavaScript against the PHP object). Such an Array-esque object also supports calling every attached public method of the PHP object + methods of JavaScript's native Array.prototype methods (as long as they are not overloaded by PHP methods).
|
||||||
|
|
||||||
|
Exceptions
|
||||||
|
==========
|
||||||
|
|
||||||
|
If the JavaScript code throws (without catching), causes errors or doesn't
|
||||||
|
compile, `V8JsScriptException` exceptions are thrown unless the `V8Js` object
|
||||||
|
is constructed with `report_uncaught_exceptions` set `FALSE`.
|
||||||
|
|
||||||
|
PHP exceptions that occur due to calls from JavaScript code by default are
|
||||||
|
*not* re-thrown into JavaScript context but cause the JavaScript execution to
|
||||||
|
be stopped immediately and then are reported at the location calling the JS code.
|
||||||
|
|
||||||
|
This behaviour can be changed by setting the `FLAG_PROPAGATE_PHP_EXCEPTIONS`
|
||||||
|
flag. If it is set, PHP exception (objects) are converted to JavaScript
|
||||||
|
objects obeying the above rules and re-thrown in JavaScript context. If they
|
||||||
|
are not caught by JavaScript code the execution stops and a
|
||||||
|
`V8JsScriptException` is thrown, which has the original PHP exception accessible
|
||||||
|
via `getPrevious` method.
|
||||||
|
|
||||||
|
V8Js versions 0.2.4 and before did not stop JS code execution on PHP exceptions,
|
||||||
|
but silently ignored them (even so succeeding PHP calls from within the same piece
|
||||||
|
of JS code were not executed by the PHP engine). This behaviour is considered as
|
||||||
|
a bug and hence was fixed with 0.2.5 release. Nevertheless there is a
|
||||||
|
compatibility php.ini switch (`v8js.compat_php_exceptions`) which turns previous
|
||||||
|
behaviour back on.
|
||||||
|
@ -80,13 +80,10 @@ extern "C" {
|
|||||||
# define V8JS_CONST (char *)
|
# define V8JS_CONST (char *)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
/* Global flags */
|
|
||||||
#define V8JS_GLOBAL_SET_FLAGS(isolate,flags) V8JS_GLOBAL(isolate)->SetHiddenValue(V8JS_SYM("__php_flags__"), V8JS_INT(flags))
|
|
||||||
#define V8JS_GLOBAL_GET_FLAGS(isolate) V8JS_GLOBAL(isolate)->GetHiddenValue(V8JS_SYM("__php_flags__"))->IntegerValue();
|
|
||||||
|
|
||||||
/* Options */
|
/* Options */
|
||||||
#define V8JS_FLAG_NONE (1<<0)
|
#define V8JS_FLAG_NONE (1<<0)
|
||||||
#define V8JS_FLAG_FORCE_ARRAY (1<<1)
|
#define V8JS_FLAG_FORCE_ARRAY (1<<1)
|
||||||
|
#define V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS (1<<2)
|
||||||
|
|
||||||
#define V8JS_DEBUG_AUTO_BREAK_NEVER 0
|
#define V8JS_DEBUG_AUTO_BREAK_NEVER 0
|
||||||
#define V8JS_DEBUG_AUTO_BREAK_ONCE 1
|
#define V8JS_DEBUG_AUTO_BREAK_ONCE 1
|
||||||
@ -124,6 +121,7 @@ ZEND_BEGIN_MODULE_GLOBALS(v8js)
|
|||||||
char *v8_flags; /* V8 command line flags */
|
char *v8_flags; /* V8 command line flags */
|
||||||
bool use_date; /* Generate JS Date objects instead of PHP DateTime */
|
bool use_date; /* Generate JS Date objects instead of PHP DateTime */
|
||||||
bool use_array_access; /* Convert ArrayAccess, Countable objects to array-like objects */
|
bool use_array_access; /* Convert ArrayAccess, Countable objects to array-like objects */
|
||||||
|
bool compat_php_exceptions; /* Don't stop JS execution on PHP exception */
|
||||||
|
|
||||||
// Timer thread globals
|
// Timer thread globals
|
||||||
std::deque<v8js_timer_ctx *> timer_stack;
|
std::deque<v8js_timer_ctx *> timer_stack;
|
||||||
|
@ -14,6 +14,9 @@ class Foo {
|
|||||||
$this->v8->foo = $this;
|
$this->v8->foo = $this;
|
||||||
$this->v8->executeString('fooobar', 'throw_0');
|
$this->v8->executeString('fooobar', 'throw_0');
|
||||||
var_dump($this->v8->getPendingException());
|
var_dump($this->v8->getPendingException());
|
||||||
|
// the exception is not cleared before the next executeString call,
|
||||||
|
// hence the next *exiting* executeString will throw.
|
||||||
|
// In this case this is the executeString call in bar() function.
|
||||||
$this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " caught!\n"); }', 'trycatch1');
|
$this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " caught!\n"); }', 'trycatch1');
|
||||||
$this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " caught!\n"); }', 'trycatch2');
|
$this->v8->executeString('try { PHP.foo.bar(); } catch (e) { print(e + " caught!\n"); }', 'trycatch2');
|
||||||
}
|
}
|
||||||
@ -21,6 +24,8 @@ class Foo {
|
|||||||
public function bar()
|
public function bar()
|
||||||
{
|
{
|
||||||
echo "To Bar!\n";
|
echo "To Bar!\n";
|
||||||
|
// This executeString call throws a PHP exception, not propagated
|
||||||
|
// to JS, hence immediately triggering the top-level catch handler.
|
||||||
$this->v8->executeString('throw new Error();', 'throw_1');
|
$this->v8->executeString('throw new Error();', 'throw_1');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -71,7 +76,7 @@ object(V8JsScriptException)#%d (13) {
|
|||||||
["file"]=>
|
["file"]=>
|
||||||
string(%d) "%s"
|
string(%d) "%s"
|
||||||
["line"]=>
|
["line"]=>
|
||||||
int(24)
|
int(29)
|
||||||
["function"]=>
|
["function"]=>
|
||||||
string(11) "__construct"
|
string(11) "__construct"
|
||||||
["class"]=>
|
["class"]=>
|
||||||
@ -100,6 +105,5 @@ object(V8JsScriptException)#%d (13) {
|
|||||||
at throw_0:1:1"
|
at throw_0:1:1"
|
||||||
}
|
}
|
||||||
To Bar!
|
To Bar!
|
||||||
Error caught!
|
|
||||||
PHP Exception: throw_0:1: ReferenceError: fooobar is not defined
|
PHP Exception: throw_0:1: ReferenceError: fooobar is not defined
|
||||||
===EOF===
|
===EOF===
|
||||||
|
33
tests/issue_156_001.phpt
Normal file
33
tests/issue_156_001.phpt
Normal file
@ -0,0 +1,33 @@
|
|||||||
|
--TEST--
|
||||||
|
Test V8::executeString() : Backwards compatibility for issue #156
|
||||||
|
--SKIPIF--
|
||||||
|
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
|
||||||
|
--INI--
|
||||||
|
v8js.compat_php_exceptions = 1
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
$v8 = new V8Js();
|
||||||
|
|
||||||
|
$v8->throwPHPException = function () {
|
||||||
|
echo "throwing PHP exception now ...\n";
|
||||||
|
throw new \Exception('foo');
|
||||||
|
};
|
||||||
|
|
||||||
|
$JS = <<< EOT
|
||||||
|
PHP.throwPHPException();
|
||||||
|
print("... old behaviour was to not stop JS execution on PHP exceptions\\n");
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$v8->executeString($JS, 'issue_156_001.js');
|
||||||
|
} catch(Exception $e) {
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
===EOF===
|
||||||
|
--EXPECT--
|
||||||
|
throwing PHP exception now ...
|
||||||
|
... old behaviour was to not stop JS execution on PHP exceptions
|
||||||
|
string(3) "foo"
|
||||||
|
===EOF===
|
50
tests/php_exceptions_001.phpt
Normal file
50
tests/php_exceptions_001.phpt
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
--TEST--
|
||||||
|
Test V8::executeString() : PHP Exception handling (repeated)
|
||||||
|
--SKIPIF--
|
||||||
|
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
function throwException() {
|
||||||
|
throw new \Exception("Test-Exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v8 = new V8Js();
|
||||||
|
$v8->foo = new \Foo();
|
||||||
|
|
||||||
|
$JS = <<< EOT
|
||||||
|
try {
|
||||||
|
PHP.foo.throwException();
|
||||||
|
// the exception should abort further execution,
|
||||||
|
// hence the print must not pop up
|
||||||
|
print("after throwException\\n");
|
||||||
|
} catch(e) {
|
||||||
|
// JS should not catch in default mode
|
||||||
|
print("JS caught exception");
|
||||||
|
}
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
for($i = 0; $i < 5; $i ++) {
|
||||||
|
var_dump($i);
|
||||||
|
try {
|
||||||
|
$v8->executeString($JS);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
===EOF===
|
||||||
|
--EXPECTF--
|
||||||
|
int(0)
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
int(1)
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
int(2)
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
int(3)
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
int(4)
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
===EOF===
|
67
tests/php_exceptions_002.phpt
Normal file
67
tests/php_exceptions_002.phpt
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
--TEST--
|
||||||
|
Test V8::executeString() : PHP Exception handling (multi-level)
|
||||||
|
--SKIPIF--
|
||||||
|
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
function throwException() {
|
||||||
|
throw new \Exception("Test-Exception");
|
||||||
|
}
|
||||||
|
|
||||||
|
function recurse($i) {
|
||||||
|
echo "recurse[$i] ...\n";
|
||||||
|
global $work;
|
||||||
|
$work($i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v8 = new V8Js();
|
||||||
|
$v8->foo = new \Foo();
|
||||||
|
|
||||||
|
$work = $v8->executeString(<<<EOT
|
||||||
|
var work = function(level) {
|
||||||
|
if(level--) {
|
||||||
|
PHP.foo.recurse(level);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
PHP.foo.throwException();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
work;
|
||||||
|
EOT
|
||||||
|
);
|
||||||
|
|
||||||
|
for($i = 0; $i < 5; $i ++) {
|
||||||
|
var_dump($i);
|
||||||
|
try {
|
||||||
|
$work($i);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
===EOF===
|
||||||
|
--EXPECT--
|
||||||
|
int(0)
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
int(1)
|
||||||
|
recurse[0] ...
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
int(2)
|
||||||
|
recurse[1] ...
|
||||||
|
recurse[0] ...
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
int(3)
|
||||||
|
recurse[2] ...
|
||||||
|
recurse[1] ...
|
||||||
|
recurse[0] ...
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
int(4)
|
||||||
|
recurse[3] ...
|
||||||
|
recurse[2] ...
|
||||||
|
recurse[1] ...
|
||||||
|
recurse[0] ...
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
===EOF===
|
36
tests/php_exceptions_003.phpt
Normal file
36
tests/php_exceptions_003.phpt
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
--TEST--
|
||||||
|
Test V8::executeString() : PHP Exception handling (basic JS propagation)
|
||||||
|
--SKIPIF--
|
||||||
|
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
function throwException() {
|
||||||
|
throw new \Exception("Test-Exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v8 = new V8Js();
|
||||||
|
$v8->foo = new \Foo();
|
||||||
|
|
||||||
|
$JS = <<< EOT
|
||||||
|
try {
|
||||||
|
PHP.foo.throwException();
|
||||||
|
// the exception should abort further execution,
|
||||||
|
// hence the print must not pop up
|
||||||
|
print("after throwException\\n");
|
||||||
|
} catch(e) {
|
||||||
|
print("JS caught exception!\\n");
|
||||||
|
var_dump(e.getMessage());
|
||||||
|
}
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
$v8->executeString($JS, 'php_exceptions_003', V8Js::FLAG_PROPAGATE_PHP_EXCEPTIONS);
|
||||||
|
|
||||||
|
?>
|
||||||
|
===EOF===
|
||||||
|
--EXPECTF--
|
||||||
|
JS caught exception!
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
===EOF===
|
36
tests/php_exceptions_004.phpt
Normal file
36
tests/php_exceptions_004.phpt
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
--TEST--
|
||||||
|
Test V8::executeString() : PHP Exception handling (PHP->JS->PHP back propagation)
|
||||||
|
--SKIPIF--
|
||||||
|
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
function throwException() {
|
||||||
|
throw new \Exception("Test-Exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v8 = new V8Js();
|
||||||
|
$v8->foo = new \Foo();
|
||||||
|
|
||||||
|
$JS = <<< EOT
|
||||||
|
PHP.foo.throwException();
|
||||||
|
// the exception should abort further execution,
|
||||||
|
// hence the print must not pop up
|
||||||
|
print("after throwException\\n");
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$v8->executeString($JS, 'php_exceptions_004', V8Js::FLAG_PROPAGATE_PHP_EXCEPTIONS);
|
||||||
|
}
|
||||||
|
catch(V8JsScriptException $e) {
|
||||||
|
echo "Got V8JsScriptException\n";
|
||||||
|
var_dump($e->getPrevious()->getMessage());
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
===EOF===
|
||||||
|
--EXPECTF--
|
||||||
|
Got V8JsScriptException
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
===EOF===
|
43
tests/php_exceptions_005.phpt
Normal file
43
tests/php_exceptions_005.phpt
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
--TEST--
|
||||||
|
Test V8::executeString() : PHP Exception handling (JS throw PHP-exception)
|
||||||
|
--SKIPIF--
|
||||||
|
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
function getException() {
|
||||||
|
return new \Exception("Test-Exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v8 = new V8Js();
|
||||||
|
$v8->foo = new \Foo();
|
||||||
|
|
||||||
|
$JS = <<< EOT
|
||||||
|
var ex = PHP.foo.getException();
|
||||||
|
print("after getException\\n");
|
||||||
|
throw ex;
|
||||||
|
print("after throw\\n");
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$v8->executeString($JS, 'php_exceptions_005');
|
||||||
|
}
|
||||||
|
catch(V8JsScriptException $e) {
|
||||||
|
echo "Got V8JsScriptException\n";
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
var_dump($e->getPrevious()->getMessage());
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
===EOF===
|
||||||
|
--EXPECTF--
|
||||||
|
after getException
|
||||||
|
Got V8JsScriptException
|
||||||
|
string(%d) "php_exceptions_005:3: exception 'Exception' with message 'Test-Exception' in %s
|
||||||
|
Stack trace:
|
||||||
|
#0 [internal function]: Foo->getException()
|
||||||
|
#1 %s: V8Js->executeString('var ex = PHP.fo...', 'php_exceptions_...')
|
||||||
|
#2 {main}"
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
===EOF===
|
40
tests/php_exceptions_006.phpt
Normal file
40
tests/php_exceptions_006.phpt
Normal file
@ -0,0 +1,40 @@
|
|||||||
|
--TEST--
|
||||||
|
Test V8::executeString() : PHP Exception handling (JS throws normal PHP-object)
|
||||||
|
--SKIPIF--
|
||||||
|
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
function getNonExceptionObject() {
|
||||||
|
return new \Foo();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v8 = new V8Js();
|
||||||
|
$v8->foo = new \Foo();
|
||||||
|
|
||||||
|
$JS = <<< EOT
|
||||||
|
var ex = PHP.foo.getNonExceptionObject();
|
||||||
|
print("after getNonExceptionObject\\n");
|
||||||
|
throw ex;
|
||||||
|
print("after throw\\n");
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$v8->executeString($JS, 'php_exceptions_006');
|
||||||
|
}
|
||||||
|
catch(V8JsScriptException $e) {
|
||||||
|
echo "Got V8JsScriptException\n";
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
// previous exception should be NULL, as it is *not* a php exception
|
||||||
|
var_dump($e->getPrevious());
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
===EOF===
|
||||||
|
--EXPECTF--
|
||||||
|
after getNonExceptionObject
|
||||||
|
Got V8JsScriptException
|
||||||
|
string(34) "php_exceptions_006:3: [object Foo]"
|
||||||
|
NULL
|
||||||
|
===EOF===
|
42
tests/php_exceptions_basic.phpt
Normal file
42
tests/php_exceptions_basic.phpt
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
--TEST--
|
||||||
|
Test V8::executeString() : PHP Exception handling (basic)
|
||||||
|
--SKIPIF--
|
||||||
|
<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?>
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
|
||||||
|
class Foo {
|
||||||
|
function throwException() {
|
||||||
|
throw new \Exception("Test-Exception");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$v8 = new V8Js();
|
||||||
|
$v8->foo = new \Foo();
|
||||||
|
|
||||||
|
$JS = <<< EOT
|
||||||
|
try {
|
||||||
|
PHP.foo.throwException();
|
||||||
|
// the exception should abort further execution,
|
||||||
|
// hence the print must not pop up
|
||||||
|
print("after throwException\\n");
|
||||||
|
} catch(e) {
|
||||||
|
// JS should not catch in default mode
|
||||||
|
print("JS caught exception");
|
||||||
|
}
|
||||||
|
EOT;
|
||||||
|
|
||||||
|
try {
|
||||||
|
$v8->executeString($JS);
|
||||||
|
} catch (Exception $e) {
|
||||||
|
var_dump($e->getMessage());
|
||||||
|
var_dump($e->getFile());
|
||||||
|
var_dump($e->getLine());
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
===EOF===
|
||||||
|
--EXPECTF--
|
||||||
|
string(14) "Test-Exception"
|
||||||
|
string(%d) "%sphp_exceptions_basic.php"
|
||||||
|
int(5)
|
||||||
|
===EOF===
|
18
v8js.cc
18
v8js.cc
@ -82,10 +82,28 @@ static ZEND_INI_MH(v8js_OnUpdateUseArrayAccess) /* {{{ */
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
static ZEND_INI_MH(v8js_OnUpdateCompatExceptions) /* {{{ */
|
||||||
|
{
|
||||||
|
bool value;
|
||||||
|
if (new_value_length==2 && strcasecmp("on", new_value)==0) {
|
||||||
|
value = (bool) 1;
|
||||||
|
} else if (new_value_length==3 && strcasecmp("yes", new_value)==0) {
|
||||||
|
value = (bool) 1;
|
||||||
|
} else if (new_value_length==4 && strcasecmp("true", new_value)==0) {
|
||||||
|
value = (bool) 1;
|
||||||
|
} else {
|
||||||
|
value = (bool) atoi(new_value);
|
||||||
|
}
|
||||||
|
V8JSG(compat_php_exceptions) = value;
|
||||||
|
return SUCCESS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
ZEND_INI_BEGIN() /* {{{ */
|
ZEND_INI_BEGIN() /* {{{ */
|
||||||
ZEND_INI_ENTRY("v8js.flags", NULL, ZEND_INI_ALL, v8js_OnUpdateV8Flags)
|
ZEND_INI_ENTRY("v8js.flags", NULL, ZEND_INI_ALL, v8js_OnUpdateV8Flags)
|
||||||
ZEND_INI_ENTRY("v8js.use_date", "0", ZEND_INI_ALL, v8js_OnUpdateUseDate)
|
ZEND_INI_ENTRY("v8js.use_date", "0", ZEND_INI_ALL, v8js_OnUpdateUseDate)
|
||||||
ZEND_INI_ENTRY("v8js.use_array_access", "0", ZEND_INI_ALL, v8js_OnUpdateUseArrayAccess)
|
ZEND_INI_ENTRY("v8js.use_array_access", "0", ZEND_INI_ALL, v8js_OnUpdateUseArrayAccess)
|
||||||
|
ZEND_INI_ENTRY("v8js.compat_php_exceptions", "0", ZEND_INI_ALL, v8js_OnUpdateCompatExceptions)
|
||||||
ZEND_INI_END()
|
ZEND_INI_END()
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| PHP Version 5 |
|
| PHP Version 5 |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| Copyright (c) 1997-2013 The PHP Group |
|
| Copyright (c) 1997-2015 The PHP Group |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| http://www.opensource.org/licenses/mit-license.php MIT License |
|
| http://www.opensource.org/licenses/mit-license.php MIT License |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| Author: Jani Taskinen <jani.taskinen@iki.fi> |
|
| Author: Jani Taskinen <jani.taskinen@iki.fi> |
|
||||||
| Author: Patrick Reilly <preilly@php.net> |
|
| Author: Patrick Reilly <preilly@php.net> |
|
||||||
|
| Author: Stefan Siegl <stesie@php.net> |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -517,7 +518,7 @@ static void v8js_compile_script(zval *this_ptr, const char *str, int str_len, co
|
|||||||
|
|
||||||
/* Compile errors? */
|
/* Compile errors? */
|
||||||
if (script.IsEmpty()) {
|
if (script.IsEmpty()) {
|
||||||
v8js_throw_script_exception(&try_catch TSRMLS_CC);
|
v8js_throw_script_exception(c->isolate, &try_catch TSRMLS_CC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
res = (v8js_script *)emalloc(sizeof(v8js_script));
|
res = (v8js_script *)emalloc(sizeof(v8js_script));
|
||||||
@ -1097,6 +1098,7 @@ PHP_MINIT_FUNCTION(v8js_class) /* {{{ */
|
|||||||
|
|
||||||
zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("FLAG_NONE"), V8JS_FLAG_NONE TSRMLS_CC);
|
zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("FLAG_NONE"), V8JS_FLAG_NONE TSRMLS_CC);
|
||||||
zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("FLAG_FORCE_ARRAY"), V8JS_FLAG_FORCE_ARRAY TSRMLS_CC);
|
zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("FLAG_FORCE_ARRAY"), V8JS_FLAG_FORCE_ARRAY TSRMLS_CC);
|
||||||
|
zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("FLAG_PROPAGATE_PHP_EXCEPTIONS"), V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS TSRMLS_CC);
|
||||||
|
|
||||||
#ifdef ENABLE_DEBUGGER_SUPPORT
|
#ifdef ENABLE_DEBUGGER_SUPPORT
|
||||||
zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("DEBUG_AUTO_BREAK_NEVER"), V8JS_DEBUG_AUTO_BREAK_NEVER TSRMLS_CC);
|
zend_declare_class_constant_long(php_ce_v8js, ZEND_STRL("DEBUG_AUTO_BREAK_NEVER"), V8JS_DEBUG_AUTO_BREAK_NEVER TSRMLS_CC);
|
||||||
|
@ -40,6 +40,8 @@ struct v8js_ctx {
|
|||||||
int in_execution;
|
int in_execution;
|
||||||
v8::Isolate *isolate;
|
v8::Isolate *isolate;
|
||||||
|
|
||||||
|
long flags;
|
||||||
|
|
||||||
long time_limit;
|
long time_limit;
|
||||||
bool time_limit_hit;
|
bool time_limit_hit;
|
||||||
long memory_limit;
|
long memory_limit;
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| PHP Version 5 |
|
| PHP Version 5 |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| Copyright (c) 1997-2013 The PHP Group |
|
| Copyright (c) 1997-2015 The PHP Group |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| http://www.opensource.org/licenses/mit-license.php MIT License |
|
| http://www.opensource.org/licenses/mit-license.php MIT License |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| Author: Jani Taskinen <jani.taskinen@iki.fi> |
|
| Author: Jani Taskinen <jani.taskinen@iki.fi> |
|
||||||
| Author: Patrick Reilly <preilly@php.net> |
|
| Author: Patrick Reilly <preilly@php.net> |
|
||||||
|
| Author: Stefan Siegl <stesie@php.net> |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -38,7 +39,7 @@ zend_class_entry *php_ce_v8js_memory_limit_exception;
|
|||||||
|
|
||||||
/* {{{ Class: V8JsScriptException */
|
/* {{{ Class: V8JsScriptException */
|
||||||
|
|
||||||
void v8js_create_script_exception(zval *return_value, v8::TryCatch *try_catch TSRMLS_DC) /* {{{ */
|
void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8::TryCatch *try_catch TSRMLS_DC) /* {{{ */
|
||||||
{
|
{
|
||||||
v8::String::Utf8Value exception(try_catch->Exception());
|
v8::String::Utf8Value exception(try_catch->Exception());
|
||||||
const char *exception_string = ToCString(exception);
|
const char *exception_string = ToCString(exception);
|
||||||
@ -81,6 +82,21 @@ void v8js_create_script_exception(zval *return_value, v8::TryCatch *try_catch TS
|
|||||||
const char* stacktrace_string = ToCString(stacktrace);
|
const char* stacktrace_string = ToCString(stacktrace);
|
||||||
PHPV8_EXPROP(_string, JsTrace, stacktrace_string);
|
PHPV8_EXPROP(_string, JsTrace, stacktrace_string);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if(try_catch->Exception()->IsObject()) {
|
||||||
|
v8::Local<v8::Value> php_ref = try_catch->Exception()->ToObject()->GetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY));
|
||||||
|
|
||||||
|
if(!php_ref.IsEmpty()) {
|
||||||
|
assert(php_ref->IsExternal());
|
||||||
|
zval *php_exception = reinterpret_cast<zval *>(v8::External::Cast(*php_ref)->Value());
|
||||||
|
|
||||||
|
zend_class_entry *exception_ce = zend_exception_get_default(TSRMLS_C);
|
||||||
|
if (Z_TYPE_P(php_exception) == IS_OBJECT && instanceof_function(Z_OBJCE_P(php_exception), exception_ce TSRMLS_CC)) {
|
||||||
|
zend_exception_set_previous(return_value, php_exception TSRMLS_CC);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
PHPV8_EXPROP(_string, message, message_string);
|
PHPV8_EXPROP(_string, message, message_string);
|
||||||
@ -89,7 +105,7 @@ void v8js_create_script_exception(zval *return_value, v8::TryCatch *try_catch TS
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
void v8js_throw_script_exception(v8::TryCatch *try_catch TSRMLS_DC) /* {{{ */
|
void v8js_throw_script_exception(v8::Isolate *isolate, v8::TryCatch *try_catch TSRMLS_DC) /* {{{ */
|
||||||
{
|
{
|
||||||
v8::String::Utf8Value exception(try_catch->Exception());
|
v8::String::Utf8Value exception(try_catch->Exception());
|
||||||
const char *exception_string = ToCString(exception);
|
const char *exception_string = ToCString(exception);
|
||||||
@ -99,7 +115,7 @@ void v8js_throw_script_exception(v8::TryCatch *try_catch TSRMLS_DC) /* {{{ */
|
|||||||
zend_throw_exception(php_ce_v8js_script_exception, (char *) exception_string, 0 TSRMLS_CC);
|
zend_throw_exception(php_ce_v8js_script_exception, (char *) exception_string, 0 TSRMLS_CC);
|
||||||
} else {
|
} else {
|
||||||
MAKE_STD_ZVAL(zexception);
|
MAKE_STD_ZVAL(zexception);
|
||||||
v8js_create_script_exception(zexception, try_catch TSRMLS_CC);
|
v8js_create_script_exception(zexception, isolate, try_catch TSRMLS_CC);
|
||||||
zend_throw_exception_object(zexception TSRMLS_CC);
|
zend_throw_exception_object(zexception TSRMLS_CC);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,12 +2,13 @@
|
|||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| PHP Version 5 |
|
| PHP Version 5 |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| Copyright (c) 1997-2013 The PHP Group |
|
| Copyright (c) 1997-2015 The PHP Group |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| http://www.opensource.org/licenses/mit-license.php MIT License |
|
| http://www.opensource.org/licenses/mit-license.php MIT License |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| Author: Jani Taskinen <jani.taskinen@iki.fi> |
|
| Author: Jani Taskinen <jani.taskinen@iki.fi> |
|
||||||
| Author: Patrick Reilly <preilly@php.net> |
|
| Author: Patrick Reilly <preilly@php.net> |
|
||||||
|
| Author: Stefan Siegl <stesie@php.net> |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -19,8 +20,8 @@ extern zend_class_entry *php_ce_v8js_script_exception;
|
|||||||
extern zend_class_entry *php_ce_v8js_time_limit_exception;
|
extern zend_class_entry *php_ce_v8js_time_limit_exception;
|
||||||
extern zend_class_entry *php_ce_v8js_memory_limit_exception;
|
extern zend_class_entry *php_ce_v8js_memory_limit_exception;
|
||||||
|
|
||||||
void v8js_create_script_exception(zval *return_value, v8::TryCatch *try_catch TSRMLS_DC);
|
void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8::TryCatch *try_catch TSRMLS_DC);
|
||||||
void v8js_throw_script_exception(v8::TryCatch *try_catch TSRMLS_DC);
|
void v8js_throw_script_exception(v8::Isolate *isolate, v8::TryCatch *try_catch TSRMLS_DC);
|
||||||
|
|
||||||
PHP_MINIT_FUNCTION(v8js_exceptions);
|
PHP_MINIT_FUNCTION(v8js_exceptions);
|
||||||
|
|
||||||
|
@ -26,20 +26,7 @@ extern "C" {
|
|||||||
V8JS_METHOD(exit) /* {{{ */
|
V8JS_METHOD(exit) /* {{{ */
|
||||||
{
|
{
|
||||||
v8::Isolate *isolate = info.GetIsolate();
|
v8::Isolate *isolate = info.GetIsolate();
|
||||||
|
v8js_terminate_execution(isolate);
|
||||||
/* Unfortunately just calling TerminateExecution on the isolate is not
|
|
||||||
* enough, since v8 just marks the thread as "to be aborted" and doesn't
|
|
||||||
* immediately do so. Hence we enter an endless loop after signalling
|
|
||||||
* termination, so we definitely don't execute JS code after the exit()
|
|
||||||
* statement. */
|
|
||||||
v8::Locker locker(isolate);
|
|
||||||
v8::Isolate::Scope isolate_scope(isolate);
|
|
||||||
v8::HandleScope handle_scope(isolate);
|
|
||||||
|
|
||||||
v8::Local<v8::String> source = V8JS_STR("for(;;);");
|
|
||||||
v8::Local<v8::Script> script = v8::Script::Compile(source);
|
|
||||||
v8::V8::TerminateExecution(isolate);
|
|
||||||
script->Run();
|
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -21,6 +21,7 @@ extern "C" {
|
|||||||
#include "ext/standard/php_string.h"
|
#include "ext/standard/php_string.h"
|
||||||
#include "zend_interfaces.h"
|
#include "zend_interfaces.h"
|
||||||
#include "zend_closures.h"
|
#include "zend_closures.h"
|
||||||
|
#include "zend_exceptions.h"
|
||||||
}
|
}
|
||||||
|
|
||||||
#include "php_v8js_macros.h"
|
#include "php_v8js_macros.h"
|
||||||
@ -33,13 +34,13 @@ static void v8js_weak_object_callback(const v8::WeakCallbackData<v8::Object, zva
|
|||||||
/* Callback for PHP methods and functions */
|
/* Callback for PHP methods and functions */
|
||||||
static void v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function *method_ptr, v8::Isolate *isolate, const v8::FunctionCallbackInfo<v8::Value>& info TSRMLS_DC) /* {{{ */
|
static void v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function *method_ptr, v8::Isolate *isolate, const v8::FunctionCallbackInfo<v8::Value>& info TSRMLS_DC) /* {{{ */
|
||||||
{
|
{
|
||||||
v8::Handle<v8::Value> return_value;
|
v8::Handle<v8::Value> return_value = V8JS_NULL;
|
||||||
zend_fcall_info fci;
|
zend_fcall_info fci;
|
||||||
zend_fcall_info_cache fcc;
|
zend_fcall_info_cache fcc;
|
||||||
zval fname, *retval_ptr = NULL, **argv = NULL;
|
zval fname, *retval_ptr = NULL, **argv = NULL;
|
||||||
zend_uint argc = info.Length(), min_num_args = 0, max_num_args = 0;
|
zend_uint argc = info.Length(), min_num_args = 0, max_num_args = 0;
|
||||||
char *error;
|
char *error;
|
||||||
int error_len, i, flags = V8JS_FLAG_NONE;
|
int error_len, i;
|
||||||
|
|
||||||
v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0);
|
v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0);
|
||||||
|
|
||||||
@ -84,7 +85,6 @@ static void v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function
|
|||||||
|
|
||||||
/* Convert parameters passed from V8 */
|
/* Convert parameters passed from V8 */
|
||||||
if (argc) {
|
if (argc) {
|
||||||
flags = V8JS_GLOBAL_GET_FLAGS(isolate);
|
|
||||||
fci.params = (zval ***) safe_emalloc(argc, sizeof(zval **), 0);
|
fci.params = (zval ***) safe_emalloc(argc, sizeof(zval **), 0);
|
||||||
argv = (zval **) safe_emalloc(argc, sizeof(zval *), 0);
|
argv = (zval **) safe_emalloc(argc, sizeof(zval *), 0);
|
||||||
for (i = 0; i < argc; i++) {
|
for (i = 0; i < argc; i++) {
|
||||||
@ -98,7 +98,7 @@ static void v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function
|
|||||||
Z_ADDREF_P(argv[i]);
|
Z_ADDREF_P(argv[i]);
|
||||||
} else {
|
} else {
|
||||||
MAKE_STD_ZVAL(argv[i]);
|
MAKE_STD_ZVAL(argv[i]);
|
||||||
if (v8js_to_zval(info[i], argv[i], flags, isolate TSRMLS_CC) == FAILURE) {
|
if (v8js_to_zval(info[i], argv[i], ctx->flags, isolate TSRMLS_CC) == FAILURE) {
|
||||||
fci.param_count++;
|
fci.param_count++;
|
||||||
error_len = spprintf(&error, 0, "converting parameter #%d passed to %s() failed", i + 1, method_ptr->common.function_name);
|
error_len = spprintf(&error, 0, "converting parameter #%d passed to %s() failed", i + 1, method_ptr->common.function_name);
|
||||||
return_value = V8JS_THROW(isolate, Error, error, error_len);
|
return_value = V8JS_THROW(isolate, Error, error, error_len);
|
||||||
@ -134,7 +134,7 @@ static void v8js_call_php_func(zval *value, zend_class_entry *ce, zend_function
|
|||||||
isolate->Enter();
|
isolate->Enter();
|
||||||
}
|
}
|
||||||
zend_catch {
|
zend_catch {
|
||||||
v8::V8::TerminateExecution(isolate);
|
v8js_terminate_execution(isolate);
|
||||||
V8JSG(fatal_error_abort) = 1;
|
V8JSG(fatal_error_abort) = 1;
|
||||||
}
|
}
|
||||||
zend_end_try();
|
zend_end_try();
|
||||||
@ -149,11 +149,19 @@ failure:
|
|||||||
efree(fci.params);
|
efree(fci.params);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (retval_ptr != NULL) {
|
if(EG(exception) && !V8JSG(compat_php_exceptions)) {
|
||||||
|
if(ctx->flags & V8JS_FLAG_PROPAGATE_PHP_EXCEPTIONS) {
|
||||||
|
return_value = isolate->ThrowException(zval_to_v8js(EG(exception), isolate TSRMLS_CC));
|
||||||
|
zend_clear_exception(TSRMLS_C);
|
||||||
|
} else {
|
||||||
|
v8js_terminate_execution(isolate);
|
||||||
|
}
|
||||||
|
} else if (retval_ptr != NULL) {
|
||||||
return_value = zval_to_v8js(retval_ptr, isolate TSRMLS_CC);
|
return_value = zval_to_v8js(retval_ptr, isolate TSRMLS_CC);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (retval_ptr != NULL) {
|
||||||
zval_ptr_dtor(&retval_ptr);
|
zval_ptr_dtor(&retval_ptr);
|
||||||
} else {
|
|
||||||
return_value = V8JS_NULL;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
info.GetReturnValue().Set(return_value);
|
info.GetReturnValue().Set(return_value);
|
||||||
@ -526,6 +534,8 @@ inline v8::Local<v8::Value> v8js_named_property_callback(v8::Local<v8::String> p
|
|||||||
const char *method_name;
|
const char *method_name;
|
||||||
uint method_name_len;
|
uint method_name_len;
|
||||||
|
|
||||||
|
v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0);
|
||||||
|
|
||||||
v8::Local<v8::Object> self = info.Holder();
|
v8::Local<v8::Object> self = info.Holder();
|
||||||
v8::Local<v8::Value> ret_value;
|
v8::Local<v8::Value> ret_value;
|
||||||
v8::Local<v8::Function> cb;
|
v8::Local<v8::Function> cb;
|
||||||
@ -669,9 +679,8 @@ inline v8::Local<v8::Value> v8js_named_property_callback(v8::Local<v8::String> p
|
|||||||
zval_ptr_dtor(&php_value);
|
zval_ptr_dtor(&php_value);
|
||||||
}
|
}
|
||||||
} else if (callback_type == V8JS_PROP_SETTER) {
|
} else if (callback_type == V8JS_PROP_SETTER) {
|
||||||
int flags = V8JS_GLOBAL_GET_FLAGS(isolate);
|
|
||||||
MAKE_STD_ZVAL(php_value);
|
MAKE_STD_ZVAL(php_value);
|
||||||
if (v8js_to_zval(set_value, php_value, flags, isolate TSRMLS_CC) != SUCCESS) {
|
if (v8js_to_zval(set_value, php_value, ctx->flags, isolate TSRMLS_CC) != SUCCESS) {
|
||||||
ret_value = v8::Handle<v8::Value>();
|
ret_value = v8::Handle<v8::Value>();
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
|
@ -55,7 +55,7 @@ static void v8js_timer_interrupt_handler(v8::Isolate *isolate, void *data) { /*
|
|||||||
|
|
||||||
if (timer_ctx->memory_limit > 0 && hs.used_heap_size() > timer_ctx->memory_limit) {
|
if (timer_ctx->memory_limit > 0 && hs.used_heap_size() > timer_ctx->memory_limit) {
|
||||||
timer_ctx->killed = true;
|
timer_ctx->killed = true;
|
||||||
v8js_terminate_execution(c TSRMLS_CC);
|
v8::V8::TerminateExecution(c->isolate);
|
||||||
c->memory_limit_hit = true;
|
c->memory_limit_hit = true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -80,7 +80,7 @@ void v8js_timer_thread(TSRMLS_D) /* {{{ */
|
|||||||
}
|
}
|
||||||
else if(timer_ctx->time_limit > 0 && now > timer_ctx->time_point) {
|
else if(timer_ctx->time_limit > 0 && now > timer_ctx->time_point) {
|
||||||
timer_ctx->killed = true;
|
timer_ctx->killed = true;
|
||||||
v8js_terminate_execution(c TSRMLS_CC);
|
v8::V8::TerminateExecution(c->isolate);
|
||||||
c->time_limit_hit = true;
|
c->time_limit_hit = true;
|
||||||
}
|
}
|
||||||
else if (timer_ctx->memory_limit > 0) {
|
else if (timer_ctx->memory_limit > 0) {
|
||||||
|
33
v8js_v8.cc
33
v8js_v8.cc
@ -2,12 +2,13 @@
|
|||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| PHP Version 5 |
|
| PHP Version 5 |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| Copyright (c) 1997-2013 The PHP Group |
|
| Copyright (c) 1997-2015 The PHP Group |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| http://www.opensource.org/licenses/mit-license.php MIT License |
|
| http://www.opensource.org/licenses/mit-license.php MIT License |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
| Author: Jani Taskinen <jani.taskinen@iki.fi> |
|
| Author: Jani Taskinen <jani.taskinen@iki.fi> |
|
||||||
| Author: Patrick Reilly <preilly@php.net> |
|
| Author: Patrick Reilly <preilly@php.net> |
|
||||||
|
| Author: Stefan Siegl <stesie@php.net> |
|
||||||
+----------------------------------------------------------------------+
|
+----------------------------------------------------------------------+
|
||||||
*/
|
*/
|
||||||
|
|
||||||
@ -77,7 +78,7 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value,
|
|||||||
v8::TryCatch try_catch;
|
v8::TryCatch try_catch;
|
||||||
|
|
||||||
/* Set flags for runtime use */
|
/* Set flags for runtime use */
|
||||||
V8JS_GLOBAL_SET_FLAGS(isolate, flags);
|
c->flags = flags;
|
||||||
|
|
||||||
/* Check if timezone has been changed and notify V8 */
|
/* Check if timezone has been changed and notify V8 */
|
||||||
tz = getenv("TZ");
|
tz = getenv("TZ");
|
||||||
@ -175,14 +176,14 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value,
|
|||||||
|
|
||||||
/* Report immediately if report_uncaught is true */
|
/* Report immediately if report_uncaught is true */
|
||||||
if (c->report_uncaught) {
|
if (c->report_uncaught) {
|
||||||
v8js_throw_script_exception(&try_catch TSRMLS_CC);
|
v8js_throw_script_exception(c->isolate, &try_catch TSRMLS_CC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Exception thrown from JS, preserve it for future execution */
|
/* Exception thrown from JS, preserve it for future execution */
|
||||||
if (result.IsEmpty()) {
|
if (result.IsEmpty()) {
|
||||||
MAKE_STD_ZVAL(c->pending_exception);
|
MAKE_STD_ZVAL(c->pending_exception);
|
||||||
v8js_create_script_exception(c->pending_exception, &try_catch TSRMLS_CC);
|
v8js_create_script_exception(c->pending_exception, c->isolate, &try_catch TSRMLS_CC);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -199,10 +200,28 @@ void v8js_v8_call(v8js_ctx *c, zval **return_value,
|
|||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
void v8js_terminate_execution(v8js_ctx *c TSRMLS_DC) /* {{{ */
|
void v8js_terminate_execution(v8::Isolate *isolate) /* {{{ */
|
||||||
{
|
{
|
||||||
// Forcefully terminate the current thread of V8 execution in the isolate
|
if(v8::V8::IsExecutionTerminating(isolate)) {
|
||||||
v8::V8::TerminateExecution(c->isolate);
|
/* Execution already terminating, needn't trigger it again and
|
||||||
|
* especially must not execute the spinning loop (which would cause
|
||||||
|
* crashes in V8 itself, at least with 4.2 and 4.3 version lines). */
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Unfortunately just calling TerminateExecution on the isolate is not
|
||||||
|
* enough, since v8 just marks the thread as "to be aborted" and doesn't
|
||||||
|
* immediately do so. Hence we enter an endless loop after signalling
|
||||||
|
* termination, so we definitely don't execute JS code after the exit()
|
||||||
|
* statement. */
|
||||||
|
v8::Locker locker(isolate);
|
||||||
|
v8::Isolate::Scope isolate_scope(isolate);
|
||||||
|
v8::HandleScope handle_scope(isolate);
|
||||||
|
|
||||||
|
v8::Local<v8::String> source = V8JS_STR("for(;;);");
|
||||||
|
v8::Local<v8::Script> script = v8::Script::Compile(source);
|
||||||
|
v8::V8::TerminateExecution(isolate);
|
||||||
|
script->Run();
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
@ -45,7 +45,7 @@ void v8js_v8_init(TSRMLS_D);
|
|||||||
void v8js_v8_call(v8js_ctx *c, zval **return_value,
|
void v8js_v8_call(v8js_ctx *c, zval **return_value,
|
||||||
long flags, long time_limit, long memory_limit,
|
long flags, long time_limit, long memory_limit,
|
||||||
std::function< v8::Local<v8::Value>(v8::Isolate *) >& v8_call TSRMLS_DC);
|
std::function< v8::Local<v8::Value>(v8::Isolate *) >& v8_call TSRMLS_DC);
|
||||||
void v8js_terminate_execution(v8js_ctx *c TSRMLS_DC);
|
void v8js_terminate_execution(v8::Isolate *isolate);
|
||||||
|
|
||||||
/* Fetch V8 object properties */
|
/* Fetch V8 object properties */
|
||||||
int v8js_get_properties_hash(v8::Handle<v8::Value> jsValue, HashTable *retval, int flags, v8::Isolate *isolate TSRMLS_DC);
|
int v8js_get_properties_hash(v8::Handle<v8::Value> jsValue, HashTable *retval, int flags, v8::Isolate *isolate TSRMLS_DC);
|
||||||
|
Loading…
Reference in New Issue
Block a user