0
0
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:
C. Scott Ananian 2013-10-26 23:35:51 -04:00
parent 57348c5f7d
commit 1c3a919ae8

View File

@ -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);