mirror of
https://github.com/phpv8/v8js.git
synced 2024-12-23 00:51:51 +00:00
Don't leak if PHP constructor is called from JavaScript.
Register the weak reference callback to deref and do memory limit accounting for wrapped PHP objects created from within JavaScript.
This commit is contained in:
parent
57348c5f7d
commit
1c3a919ae8
@ -29,6 +29,8 @@ extern "C" {
|
|||||||
#include <v8.h>
|
#include <v8.h>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
static void php_v8js_weak_object_callback(const v8::WeakCallbackData<v8::Object, zval> &data);
|
||||||
|
|
||||||
/* Callback for PHP methods and functions */
|
/* Callback for PHP methods and functions */
|
||||||
static void php_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 php_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) /* {{{ */
|
||||||
{
|
{
|
||||||
@ -178,6 +180,7 @@ static void php_v8js_construct_callback(const v8::FunctionCallbackInfo<v8::Value
|
|||||||
// @todo assert constructor call
|
// @todo assert constructor call
|
||||||
v8::Handle<v8::Object> newobj = info.This();
|
v8::Handle<v8::Object> newobj = info.This();
|
||||||
v8::Local<v8::External> php_object;
|
v8::Local<v8::External> php_object;
|
||||||
|
zval *value;
|
||||||
|
|
||||||
if (!info.IsConstructCall()) {
|
if (!info.IsConstructCall()) {
|
||||||
return;
|
return;
|
||||||
@ -190,6 +193,10 @@ static void php_v8js_construct_callback(const v8::FunctionCallbackInfo<v8::Value
|
|||||||
if (info[0]->IsExternal()) {
|
if (info[0]->IsExternal()) {
|
||||||
// Object created by v8js in php_v8js_hash_to_jsobj, PHP object passed as v8::External.
|
// Object created by v8js in php_v8js_hash_to_jsobj, PHP object passed as v8::External.
|
||||||
php_object = v8::Local<v8::External>::Cast(info[0]);
|
php_object = v8::Local<v8::External>::Cast(info[0]);
|
||||||
|
value = reinterpret_cast<zval *>(php_object->Value());
|
||||||
|
// Increase the reference count of this value because we're storing it internally for use later
|
||||||
|
// See https://github.com/preillyme/v8js/issues/6
|
||||||
|
Z_ADDREF_P(value);
|
||||||
} else {
|
} else {
|
||||||
// Object created from JavaScript context. Need to create PHP object first.
|
// Object created from JavaScript context. Need to create PHP object first.
|
||||||
V8JS_TSRMLS_FETCH();
|
V8JS_TSRMLS_FETCH();
|
||||||
@ -202,7 +209,6 @@ static void php_v8js_construct_callback(const v8::FunctionCallbackInfo<v8::Value
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
zval *value;
|
|
||||||
MAKE_STD_ZVAL(value);
|
MAKE_STD_ZVAL(value);
|
||||||
object_init_ex(value, ce);
|
object_init_ex(value, ce);
|
||||||
|
|
||||||
@ -215,6 +221,16 @@ static void php_v8js_construct_callback(const v8::FunctionCallbackInfo<v8::Value
|
|||||||
|
|
||||||
newobj->SetAlignedPointerInInternalField(0, ext_tmpl->Value());
|
newobj->SetAlignedPointerInInternalField(0, ext_tmpl->Value());
|
||||||
newobj->SetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY), php_object);
|
newobj->SetHiddenValue(V8JS_SYM(PHPJS_OBJECT_KEY), php_object);
|
||||||
|
|
||||||
|
// Since we got to decrease the reference count again, in case v8 garbage collector
|
||||||
|
// decides to dispose the JS object, we add a weak persistent handle and register
|
||||||
|
// a callback function that removes the reference.
|
||||||
|
v8::Persistent<v8::Object> persist_newobj(isolate, newobj);
|
||||||
|
persist_newobj.SetWeak(value, php_v8js_weak_object_callback);
|
||||||
|
|
||||||
|
// Just tell v8 that we're allocating some external memory
|
||||||
|
// (for the moment we just always tell 1k instead of trying to find out actual values)
|
||||||
|
v8::V8::AdjustAmountOfExternalAllocatedMemory(1024);
|
||||||
}
|
}
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
@ -734,20 +750,6 @@ static v8::Handle<v8::Value> php_v8js_hash_to_jsobj(zval *value, v8::Isolate *is
|
|||||||
v8::Handle<v8::Value> external = v8::External::New(value);
|
v8::Handle<v8::Value> external = v8::External::New(value);
|
||||||
newobj = new_tpl->GetFunction()->NewInstance(1, &external);
|
newobj = new_tpl->GetFunction()->NewInstance(1, &external);
|
||||||
|
|
||||||
// Increase the reference count of this value because we're storing it internally for use later
|
|
||||||
// See https://github.com/preillyme/v8js/issues/6
|
|
||||||
Z_ADDREF_P(value);
|
|
||||||
|
|
||||||
// Since we got to decrease the reference count again, in case v8 garbage collector
|
|
||||||
// decides to dispose the JS object, we add a weak persistent handle and register
|
|
||||||
// a callback function that removes the reference.
|
|
||||||
v8::Persistent<v8::Object> persist_newobj(isolate, newobj);
|
|
||||||
persist_newobj.SetWeak(value, php_v8js_weak_object_callback);
|
|
||||||
|
|
||||||
// Just tell v8 that we're allocating some external memory
|
|
||||||
// (for the moment we just always tell 1k instead of trying to find out actual values)
|
|
||||||
v8::V8::AdjustAmountOfExternalAllocatedMemory(1024);
|
|
||||||
|
|
||||||
if (ce == zend_ce_closure) {
|
if (ce == zend_ce_closure) {
|
||||||
// free uncached function template when object is freed
|
// free uncached function template when object is freed
|
||||||
v8::Persistent<v8::Object> persist_newobj2(isolate, newobj);
|
v8::Persistent<v8::Object> persist_newobj2(isolate, newobj);
|
||||||
|
Loading…
Reference in New Issue
Block a user