diff options
| -rw-r--r-- | PHPINFO | 13 | ||||
| -rw-r--r-- | php-pecl-v8js.spec | 17 | ||||
| -rw-r--r-- | v8js-upstream.patch | 1022 | 
3 files changed, 1048 insertions, 4 deletions
@@ -0,0 +1,13 @@ + +v8js + +V8 Javascript Engine => enabled +V8 Engine Compiled Version => 6.2.91 +V8 Engine Linked Version => 6.2.91 +Version => 2.1.0 + +Directive => Local Value => Master Value +v8js.flags => no value => no value +v8js.icudtl_dat_path => no value => no value +v8js.use_date => 0 => 0 +v8js.use_array_access => 0 => 0 diff --git a/php-pecl-v8js.spec b/php-pecl-v8js.spec index 9955bac..f23b7c2 100644 --- a/php-pecl-v8js.spec +++ b/php-pecl-v8js.spec @@ -20,19 +20,20 @@  Summary:        V8 Javascript Engine for PHP  Name:           %{?sub_prefix}php-pecl-%{pecl_name}  Version:        2.1.0 -Release:        2%{?dist}%{!?nophptag:%(%{__php} -r 'echo ".".PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')} +Release:        3%{?dist}%{!?nophptag:%(%{__php} -r 'echo ".".PHP_MAJOR_VERSION.".".PHP_MINOR_VERSION;')}  License:        PHP -Group:          Development/Languages  URL:            http://pecl.php.net/package/%{pecl_name}  Source0:        http://pecl.php.net/get/%{pecl_name}-%{version}.tgz +Patch0:         %{pecl_name}-upstream.patch +  # See http://pkgs.fedoraproject.org/cgit/rpms/v8.git/tree/v8.spec#n74  ExclusiveArch:	%{ix86} x86_64 %{arm} ppc mipsel mips64el  BuildRequires:  %{?dtsprefix}gcc  BuildRequires:  %{?scl_prefix}php-devel > 7  BuildRequires:  %{?scl_prefix}php-pear -# because of https://bugzilla.redhat.com/1378889 -BuildRequires:  v8-devel >= 5.2.258-7 +# from config.m4 for full features (else 4.6.76) +BuildRequires:  v8-devel >= 1:6.5.143  Requires:       %{?scl_prefix}php(zend-abi) = %{php_zend_api}  Requires:       %{?scl_prefix}php(api) = %{php_core_api} @@ -59,6 +60,10 @@ Obsoletes:     php71w-pecl-%{pecl_name} <= %{version}  Obsoletes:     php72u-pecl-%{pecl_name} <= %{version}  Obsoletes:     php72w-pecl-%{pecl_name} <= %{version}  %endif +%if "%{php_version}" > "7.3" +Obsoletes:     php73u-pecl-%{pecl_name} <= %{version} +Obsoletes:     php73w-pecl-%{pecl_name} <= %{version} +%endif  %endif  %if 0%{?fedora} < 20 && 0%{?rhel} < 7 @@ -86,6 +91,7 @@ sed -e 's/role="test"/role="src"/' \      -i package.xml  cd NTS +%patch0 -p1 -b .upstream  # Sanity check, really often broken  extver=$(sed -n '/#define PHP_V8JS_VERSION/{s/.* "//;s/".*$//;p}' php_v8js_macros.h) @@ -238,6 +244,9 @@ REPORT_EXIT_STATUS=1 \  %changelog +* Thu Oct 25 2018 Remi Collet <remi@remirepo.net> - 2.1.0-3 +- add upstream patches for PHP 7.3 +  * Fri Sep  7 2018 Remi Collet <remi@remirepo.net> - 2.1.0-2  - rebuild diff --git a/v8js-upstream.patch b/v8js-upstream.patch new file mode 100644 index 0000000..937915d --- /dev/null +++ b/v8js-upstream.patch @@ -0,0 +1,1022 @@ +Some selected patches from https://github.com/phpv8/v8js/compare/2.1.0...php7 +to fix compatibility with upcoming PHP 7.3 + + +From 48a763d6dbd0543ef49e275c6a5d4de4e25af24a Mon Sep 17 00:00:00 2001 +From: Stefan Siegl <stesie@brokenpipe.de> +Date: Thu, 1 Feb 2018 19:38:47 +0100 +Subject: [PATCH 02/18] pass module_base directly via FunctionTemplate, closes + #349 + +--- + tests/issue_349_basic.phpt | 82 ++++++++++++++++++++++++++++++++++++++ + v8js_methods.cc            | 34 +++++++++++----- + 2 files changed, 106 insertions(+), 10 deletions(-) + create mode 100644 tests/issue_349_basic.phpt + +diff --git a/tests/issue_349_basic.phpt b/tests/issue_349_basic.phpt +new file mode 100644 +index 0000000..f7a6d7d +--- /dev/null ++++ b/tests/issue_349_basic.phpt +@@ -0,0 +1,82 @@ ++--TEST-- ++Test V8Js::setModuleNormaliser : Custom normalisation #005 ++--SKIPIF-- ++<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?> ++--FILE-- ++<?php ++ ++$v8 = new V8Js(); ++ ++$v8->setModuleNormaliser(function ($base, $moduleName) { ++    var_dump($base, $moduleName); ++    if ($base == '' && $moduleName == './tags') { ++        return ['./tags', 'index.js']; ++    } ++    if ($base == './tags' && $moduleName == './if.js') { ++        return ['./tags', 'if.js']; ++    } ++    return [$base, $moduleName]; ++}); ++ ++$v8->setModuleLoader(function ($moduleName) { ++    print("setModuleLoader called for ".$moduleName."\n"); ++    switch ($moduleName) { ++        case './app.js': ++            return "require('./tags')"; ++        case './tags/index.js': ++            return "require('./if.js')"; ++    } ++}); ++ ++$v8->executeString("require('./app.js')"); ++ ++echo "------------------------------------------------\n"; ++ ++$v8 = new V8Js(); ++ ++$v8->setModuleNormaliser(function ($base, $moduleName) { ++    var_dump($base, $moduleName); ++    if ($base == '' && $moduleName == './tags') { ++        return ['./tags', 'index.js']; ++    } ++    if ($base == './tags' && $moduleName == './if.js') { ++        return ['./tags', 'if.js']; ++    } ++    return [$base, $moduleName]; ++}); ++ ++$v8->setModuleLoader(function ($moduleName) { ++    print("setModuleLoader called for ".$moduleName."\n"); ++    switch ($moduleName) { ++        case './app.js': ++            return "require('./tags')()"; // different ++        case './tags/index.js': ++            return "module.exports = function() {require('./if.js')}"; // different ++    } ++}); ++ ++$v8->executeString("require('./app.js')"); ++ ++?> ++===EOF=== ++--EXPECT-- ++string(0) "" ++string(8) "./app.js" ++setModuleLoader called for ./app.js ++string(0) "" ++string(6) "./tags" ++setModuleLoader called for ./tags/index.js ++string(6) "./tags" ++string(7) "./if.js" ++setModuleLoader called for ./tags/if.js ++------------------------------------------------ ++string(0) "" ++string(8) "./app.js" ++setModuleLoader called for ./app.js ++string(0) "" ++string(6) "./tags" ++setModuleLoader called for ./tags/index.js ++string(6) "./tags" ++string(7) "./if.js" ++setModuleLoader called for ./tags/if.js ++===EOF=== +diff --git a/v8js_methods.cc b/v8js_methods.cc +index 947d348..644c8c2 100644 +--- a/v8js_methods.cc ++++ b/v8js_methods.cc +@@ -205,10 +205,10 @@ V8JS_METHOD(var_dump) /* {{{ */ + V8JS_METHOD(require) + { + 	v8::Isolate *isolate = info.GetIsolate(); ++	v8js_ctx *c = (v8js_ctx *) isolate->GetData(0); +  +-	// Get the extension context +-	v8::Local<v8::External> data = v8::Local<v8::External>::Cast(info.Data()); +-	v8js_ctx *c = static_cast<v8js_ctx*>(data->Value()); ++	v8::String::Utf8Value module_base(info.Data()); ++	const char *module_base_cstr = ToCString(module_base); +  + 	// Check that we have a module loader + 	if(Z_TYPE(c->module_loader) == IS_NULL) { +@@ -225,7 +225,7 @@ V8JS_METHOD(require) + 		normalised_path = (char *)emalloc(PATH_MAX); + 		module_name = (char *)emalloc(PATH_MAX); +  +-		v8js_commonjs_normalise_identifier(c->modules_base.back(), module_id, normalised_path, module_name); ++		v8js_commonjs_normalise_identifier(module_base_cstr, module_id, normalised_path, module_name); + 	} + 	else { + 		// Call custom normaliser +@@ -238,7 +238,7 @@ V8JS_METHOD(require) + 				isolate->Exit(); + 				v8::Unlocker unlocker(isolate); +  +-				ZVAL_STRING(¶ms[0], c->modules_base.back()); ++				ZVAL_STRING(¶ms[0], module_base_cstr); + 				ZVAL_STRING(¶ms[1], module_id); +  + 				call_result = call_user_function_ex(EG(function_table), NULL, &c->module_normaliser, +@@ -445,7 +445,7 @@ V8JS_METHOD(require) + 	v8::Local<v8::String> source = V8JS_ZSTR(Z_STR(module_code)); + 	zval_ptr_dtor(&module_code); +  +-	source = v8::String::Concat(V8JS_SYM("(function (exports, module) {"), source); ++	source = v8::String::Concat(V8JS_SYM("(function (exports, module, require) {"), source); + 	source = v8::String::Concat(source, V8JS_SYM("\n});")); +  + 	// Create and compile script +@@ -459,6 +459,17 @@ V8JS_METHOD(require) + 		return; + 	} +  ++	v8::Local<v8::String> base_path = V8JS_STR(normalised_path); ++	v8::MaybeLocal<v8::Function> require_fn = v8::FunctionTemplate::New(isolate, V8JS_MN(require), base_path)->GetFunction(); ++ ++	if (require_fn.IsEmpty()) { ++		efree(normalised_path); ++		efree(normalised_module_id); ++		info.GetReturnValue().Set(isolate->ThrowException(V8JS_SYM("Failed to create require method"))); ++		return; ++	} ++ ++ + 	// Add this module and path to the stack + 	c->modules_stack.push_back(normalised_module_id); + 	c->modules_base.push_back(normalised_path); +@@ -474,15 +485,18 @@ V8JS_METHOD(require) + 	module->Set(V8JS_SYM("exports"), exports); +  + 	if (module_function->IsFunction()) { +-		v8::Local<v8::Value> *jsArgv = static_cast<v8::Local<v8::Value> *>(alloca(2 * sizeof(v8::Local<v8::Value>))); ++		v8::Local<v8::Value> *jsArgv = static_cast<v8::Local<v8::Value> *>(alloca(3 * sizeof(v8::Local<v8::Value>))); + 		new(&jsArgv[0]) v8::Local<v8::Value>; + 		jsArgv[0] = exports; +  + 		new(&jsArgv[1]) v8::Local<v8::Value>; + 		jsArgv[1] = module; +  ++		new(&jsArgv[2]) v8::Local<v8::Value>; ++		jsArgv[2] = require_fn.ToLocalChecked(); ++ + 		// actually call the module +-		v8::Local<v8::Function>::Cast(module_function)->Call(exports, 2, jsArgv); ++		v8::Local<v8::Function>::Cast(module_function)->Call(exports, 3, jsArgv); + 	} +  + 	// Remove this module and path from the stack +@@ -532,8 +546,8 @@ void v8js_register_methods(v8::Local<v8::ObjectTemplate> global, v8js_ctx *c) /* + 	global->Set(V8JS_SYM("print"), v8::FunctionTemplate::New(isolate, V8JS_MN(print)), v8::ReadOnly); + 	global->Set(V8JS_SYM("var_dump"), v8::FunctionTemplate::New(isolate, V8JS_MN(var_dump)), v8::ReadOnly); +  +-	c->modules_base.push_back(""); +-	global->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(isolate, V8JS_MN(require), v8::External::New(isolate, c)), v8::ReadOnly); ++	v8::Local<v8::String> base_path = V8JS_STRL("", 0); ++	global->Set(V8JS_SYM("require"), v8::FunctionTemplate::New(isolate, V8JS_MN(require), base_path), v8::ReadOnly); + } + /* }}} */ +  + +From 313ad1e258542e2db64a0a38f64eb789c963bd03 Mon Sep 17 00:00:00 2001 +From: Stefan Siegl <stesie@brokenpipe.de> +Date: Thu, 1 Feb 2018 19:43:36 +0100 +Subject: [PATCH 04/18] cleanup: remove no longer needed modules_base from ctx, + refs #349 + +--- + v8js_class.cc   | 2 -- + v8js_class.h    | 1 - + v8js_methods.cc | 2 -- + 3 files changed, 5 deletions(-) + +diff --git a/v8js_class.cc b/v8js_class.cc +index a572864..dc366aa 100644 +--- a/v8js_class.cc ++++ b/v8js_class.cc +@@ -200,7 +200,6 @@ static void v8js_free_storage(zend_object *object) /* {{{ */ + 	} +  + 	c->modules_stack.~vector(); +-	c->modules_base.~vector(); +  + 	zval_ptr_dtor(&c->zval_snapshot_blob); +  +@@ -226,7 +225,6 @@ static zend_object* v8js_new(zend_class_entry *ce) /* {{{ */ + 	new(&c->array_tmpl) v8::Persistent<v8::FunctionTemplate>(); +  + 	new(&c->modules_stack) std::vector<char*>(); +-	new(&c->modules_base) std::vector<char*>(); + 	new(&c->modules_loaded) std::map<char *, v8js_persistent_value_t, cmp_str>; +  + 	new(&c->template_cache) std::map<const zend_string *,v8js_function_tmpl_t>(); +diff --git a/v8js_class.h b/v8js_class.h +index 4886754..cd06fc5 100644 +--- a/v8js_class.h ++++ b/v8js_class.h +@@ -57,7 +57,6 @@ struct v8js_ctx { +   zval module_loader; +  +   std::vector<char *> modules_stack; +-  std::vector<char *> modules_base; +   std::map<char *, v8js_persistent_value_t, cmp_str> modules_loaded; +   std::map<const zend_string *,v8js_function_tmpl_t> template_cache; +  +diff --git a/v8js_methods.cc b/v8js_methods.cc +index 644c8c2..4bee095 100644 +--- a/v8js_methods.cc ++++ b/v8js_methods.cc +@@ -472,7 +472,6 @@ V8JS_METHOD(require) +  + 	// Add this module and path to the stack + 	c->modules_stack.push_back(normalised_module_id); +-	c->modules_base.push_back(normalised_path); +  + 	// Run script to evaluate closure + 	v8::Local<v8::Value> module_function = script->Run(); +@@ -501,7 +500,6 @@ V8JS_METHOD(require) +  + 	// Remove this module and path from the stack + 	c->modules_stack.pop_back(); +-	c->modules_base.pop_back(); +  + 	efree(normalised_path); +  + +From c7019e3c1a311e6ed2cccda01445e21fa5a17969 Mon Sep 17 00:00:00 2001 +From: Jan-E <github@ehrhardt.nl> +Date: Thu, 5 Jul 2018 11:22:17 +0200 +Subject: [PATCH 05/18] Remove GC_G(gc_active) check + +--- + v8js_v8object_class.cc | 2 ++ + 1 file changed, 2 insertions(+) + +diff --git a/v8js_v8object_class.cc b/v8js_v8object_class.cc +index 49669ac..abc32d3 100644 +--- a/v8js_v8object_class.cc ++++ b/v8js_v8object_class.cc +@@ -210,10 +210,12 @@ static HashTable *v8js_v8object_get_properties(zval *object) /* {{{ */ + 	v8js_v8object *obj = Z_V8JS_V8OBJECT_OBJ_P(object); +  + 	if (obj->properties == NULL) { ++#if PHP_VERSION_ID < 70300 + 		if (GC_G(gc_active)) { + 			/* the garbage collector is running, don't create more zvals */ + 			return NULL; + 		} ++#endif +  + 		ALLOC_HASHTABLE(obj->properties); + 		zend_hash_init(obj->properties, 0, NULL, ZVAL_PTR_DTOR, 0); + +From 826aaa689cd420d1ea0961109607a8641de31031 Mon Sep 17 00:00:00 2001 +From: Jan-E <github@ehrhardt.nl> +Date: Thu, 5 Jul 2018 11:30:20 +0200 +Subject: [PATCH 06/18] Change to GC_IS_RECURSIVE for PHP 7.3 + +--- + v8js_convert.cc       | 4 ++++ + v8js_exceptions.cc    | 4 ++++ + v8js_object_export.cc | 6 ++++++ + 3 files changed, 14 insertions(+) + +diff --git a/v8js_convert.cc b/v8js_convert.cc +index 056e31b..4091cf0 100644 +--- a/v8js_convert.cc ++++ b/v8js_convert.cc +@@ -70,7 +70,11 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate + 	v8::Local<v8::Array> newarr; +  + 	/* Prevent recursion */ ++#if PHP_VERSION_ID >= 70300 ++	if (myht && GC_IS_RECURSIVE(myht)) { ++#else + 	if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) { ++#endif + 		return V8JS_NULL; + 	} +  +diff --git a/v8js_exceptions.cc b/v8js_exceptions.cc +index 42fe7b1..967cae8 100644 +--- a/v8js_exceptions.cc ++++ b/v8js_exceptions.cc +@@ -88,7 +88,11 @@ void v8js_create_script_exception(zval *return_value, v8::Isolate *isolate, v8:: +  + 			zend_class_entry *exception_ce = zend_exception_get_default(); + 			if (instanceof_function(php_exception->ce, exception_ce)) { ++#ifdef GC_ADDREF ++				GC_ADDREF(php_exception); ++#else + 				++GC_REFCOUNT(php_exception); ++#endif + 				zend_exception_set_previous(Z_OBJ_P(return_value), php_exception); + 			} + 		} +diff --git a/v8js_object_export.cc b/v8js_object_export.cc +index 4d61e76..85bd701 100644 +--- a/v8js_object_export.cc ++++ b/v8js_object_export.cc +@@ -137,7 +137,9 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, v +  + 		zend_try { + 			/* zend_fcall_info_cache */ ++#if PHP_VERSION_ID < 70300 + 			fcc.initialized = 1; ++#endif + 			fcc.function_handler = method_ptr; + 			fcc.calling_scope = object->ce; + 			fcc.called_scope = object->ce; +@@ -1013,7 +1015,11 @@ v8::Local<v8::Value> v8js_hash_to_jsobj(zval *value, v8::Isolate *isolate) /* {{ + 	} +  + 	/* Prevent recursion */ ++#if PHP_VERSION_ID >= 70300 ++	if (myht && GC_IS_RECURSIVE(myht)) { ++#else + 	if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) { ++#endif + 		return V8JS_NULL; + 	} +  + +From 0c2b55d8028cbdc603a84136a883edee277fed99 Mon Sep 17 00:00:00 2001 +From: Jan-E <github@ehrhardt.nl> +Date: Thu, 5 Jul 2018 11:41:32 +0200 +Subject: [PATCH 07/18] Add GC_(UN)PROTECT_RECURSION, move (un)protecting + outside loops + +--- + php_v8js_macros.h     | 11 +++++++++++ + v8js_convert.cc       | 27 ++++++++++++++++----------- + v8js_object_export.cc | 29 +++++++++++++++++------------ + 3 files changed, 44 insertions(+), 23 deletions(-) + +diff --git a/php_v8js_macros.h b/php_v8js_macros.h +index e95ca55..2503663 100644 +--- a/php_v8js_macros.h ++++ b/php_v8js_macros.h +@@ -166,6 +166,17 @@ extern struct _v8js_process_globals v8js_process_globals; + /* Register builtin methods into passed object */ + void v8js_register_methods(v8::Local<v8::ObjectTemplate>, v8js_ctx *c); +  ++#ifdef ZEND_HASH_INC_APPLY_COUNT ++#ifndef GC_PROTECT_RECURSION ++#	define GC_PROTECT_RECURSION(ht) ZEND_HASH_INC_APPLY_COUNT(ht) ++#endif ++#endif ++#ifdef ZEND_HASH_DEC_APPLY_COUNT ++#ifndef GC_UNPROTECT_RECURSION ++#	define GC_UNPROTECT_RECURSION(ht) ZEND_HASH_DEC_APPLY_COUNT(ht) ++#endif ++#endif ++ + #endif	/* PHP_V8JS_MACROS_H */ +  + /* +diff --git a/v8js_convert.cc b/v8js_convert.cc +index 4091cf0..b701154 100644 +--- a/v8js_convert.cc ++++ b/v8js_convert.cc +@@ -84,21 +84,26 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate + 	{ + 		zval *data; + 		ulong index = 0; +-		HashTable *tmp_ht; +  +-		ZEND_HASH_FOREACH_VAL(myht, data) { +-			tmp_ht = HASH_OF(data); +- +-			if (tmp_ht) { +-				ZEND_HASH_INC_APPLY_COUNT(myht); +-			} ++#if PHP_VERSION_ID >= 70300 ++		if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { ++#else ++		if (myht) { ++#endif ++			GC_PROTECT_RECURSION(myht); ++		} +  ++		ZEND_HASH_FOREACH_VAL(myht, data) { + 			newarr->Set(index++, zval_to_v8js(data, isolate)); +- +-			if (tmp_ht) { +-				ZEND_HASH_DEC_APPLY_COUNT(myht); +-			} + 		} ZEND_HASH_FOREACH_END(); ++ ++#if PHP_VERSION_ID >= 70300 ++		if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { ++#else ++		if (myht) { ++#endif ++			GC_UNPROTECT_RECURSION(myht); ++		} + 	} + 	return newarr; + } +diff --git a/v8js_object_export.cc b/v8js_object_export.cc +index 85bd701..3568871 100644 +--- a/v8js_object_export.cc ++++ b/v8js_object_export.cc +@@ -955,21 +955,20 @@ static v8::Local<v8::Object> v8js_wrap_array_to_object(v8::Isolate *isolate, zva + 	if (i > 0) + 	{ + 		zval *data; +-		HashTable *tmp_ht; +  +-		ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, data) { +-			tmp_ht = HASH_OF(data); ++#if PHP_VERSION_ID >= 70300 ++		if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { ++#else ++		if (myht) { ++#endif ++			GC_PROTECT_RECURSION(myht); ++		} +  +-			if (tmp_ht) { +-				ZEND_HASH_INC_APPLY_COUNT(tmp_ht); +-			} ++		ZEND_HASH_FOREACH_KEY_VAL(myht, index, key, data) { +  + 			if (key) { + 				if (ZSTR_VAL(key)[0] == '\0' && Z_TYPE_P(value) == IS_OBJECT) { + 					/* Skip protected and private members. */ +-					if (tmp_ht) { +-						ZEND_HASH_DEC_APPLY_COUNT(tmp_ht); +-					} + 					continue; + 				} +  +@@ -991,10 +990,16 @@ static v8::Local<v8::Object> v8js_wrap_array_to_object(v8::Isolate *isolate, zva + 				newobj->Set(static_cast<uint32_t>(index), zval_to_v8js(data, isolate)); + 			} +  +-			if (tmp_ht) { +-				ZEND_HASH_DEC_APPLY_COUNT(tmp_ht); +-			} + 		} ZEND_HASH_FOREACH_END(); ++ ++#if PHP_VERSION_ID >= 70300 ++		if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { ++#else ++		if (myht) { ++#endif ++			GC_UNPROTECT_RECURSION(myht); ++		} ++ + 	} +  + 	return newobj; + +From c87ddb8ebf9b249663f32b9e94b6fad698b3e2c1 Mon Sep 17 00:00:00 2001 +From: Jan-E <github@ehrhardt.nl> +Date: Thu, 5 Jul 2018 11:45:03 +0200 +Subject: [PATCH 08/18] Fix tests for added method + DateTime::createFromImmutable() + +--- + tests/var_dump.phpt    |   5 +- + tests/var_dump_73.phpt | 322 +++++++++++++++++++++++++++++++++++++++++ + 2 files changed, 326 insertions(+), 1 deletion(-) + create mode 100644 tests/var_dump_73.phpt + +diff --git a/tests/var_dump.phpt b/tests/var_dump.phpt +index 9ce0896..7a5d7d8 100644 +--- a/tests/var_dump.phpt ++++ b/tests/var_dump.phpt +@@ -1,7 +1,10 @@ + --TEST-- + Test V8::executeString() : var_dump + --SKIPIF-- +-<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?> ++<?php ++require_once(dirname(__FILE__) . '/skipif.inc'); ++if (PHP_VERSION_ID >= 70300) die('skip Only for php version < 7.3'); ++?> + --INI-- + date.timezone=UTC + --FILE-- +diff --git a/tests/var_dump_73.phpt b/tests/var_dump_73.phpt +new file mode 100644 +index 0000000..553febb +--- /dev/null ++++ b/tests/var_dump_73.phpt +@@ -0,0 +1,322 @@ ++--TEST-- ++Test V8::executeString() : var_dump ++--SKIPIF-- ++<?php ++require_once(dirname(__FILE__) . '/skipif.inc'); ++if (PHP_VERSION_ID < 70300) die('skip Only for php version >= 7.3'); ++?> ++--INI-- ++date.timezone=UTC ++--FILE-- ++<?php ++# Test var_dump of various types ++ ++$JS = <<< EOT ++ ++print("--- JS var_dump of PHP object ----\\n"); ++var_dump(PHP.phptypes); ++ ++print("--- JS var_dump of JS object ----\\n"); ++var types = { ++	undefined: undefined, ++	null: null, ++	bool: true, ++	string: "string", ++	uint: 1, ++	int: -1, ++	number: 3.141592654, ++	// XXX this gets parsed with local timezone, ++	//     which is bad for test repeatability. ++	//date: new Date('September 27, 1976 09:00:00 GMT'), ++	regexp: /regexp/, ++	array: [1,2,3], ++	object: { field: "foo" }, ++	function: function id(x) { return x; }, ++	phpobject: PHP.obj ++}; ++ ++var_dump(types); ++print("--- PHP var_dump of JS object ----\\n"); ++types; ++EOT; ++ ++class Foo { ++	  var $field = "php"; ++} ++ ++$v8 = new V8Js(); ++$v8->obj = new Foo; ++ ++$phptypes = $v8->phptypes = array( ++	"null" => NULL, ++	"bool" => true, ++	"string" => "string", ++	"uint" => 1, ++	"int" => -1, ++	"number" => 3.141592654, ++	"date" => new DateTime('September 27, 1976 09:00:00 UTC', new DateTimeZone('UTC')), ++	//"regexp" => new Regexp('/regexp/'), /* no native PHP regex type */ ++	"array" => array(1,2,3), ++	"object" => array( "field" => "foo" ), ++	"function" => (function ($x) { return $x; }), ++	"phpobject" => new Foo ++); ++ ++echo "---- PHP var_dump of PHP object ----\n"; ++var_dump($phptypes); ++ ++try { ++	var_dump($v8->executeString($JS, 'var_dump.js')); ++} catch (V8JsScriptException $e) { ++	echo "Error!\n"; ++	var_dump($e); ++} ++?> ++===EOF=== ++--EXPECTF-- ++---- PHP var_dump of PHP object ---- ++array(11) { ++  ["null"]=> ++  NULL ++  ["bool"]=> ++  bool(true) ++  ["string"]=> ++  string(6) "string" ++  ["uint"]=> ++  int(1) ++  ["int"]=> ++  int(-1) ++  ["number"]=> ++  float(3.141592654) ++  ["date"]=> ++  object(DateTime)#%d (3) { ++    ["date"]=> ++    string(%d) "1976-09-27 09:00:00%r(\.0+)?%r" ++    ["timezone_type"]=> ++    int(3) ++    ["timezone"]=> ++    string(3) "UTC" ++  } ++  ["array"]=> ++  array(3) { ++    [0]=> ++    int(1) ++    [1]=> ++    int(2) ++    [2]=> ++    int(3) ++  } ++  ["object"]=> ++  array(1) { ++    ["field"]=> ++    string(3) "foo" ++  } ++  ["function"]=> ++  object(Closure)#%d (1) { ++    ["parameter"]=> ++    array(1) { ++      ["$x"]=> ++      string(10) "<required>" ++    } ++  } ++  ["phpobject"]=> ++  object(Foo)#%d (1) { ++    ["field"]=> ++    string(3) "php" ++  } ++} ++--- JS var_dump of PHP object ---- ++array (11) { ++  ["null"] => ++  NULL ++  ["bool"] => ++  bool(true) ++  ["string"] => ++  string(6) "string" ++  ["uint"] => ++  int(1) ++  ["int"] => ++  int(-1) ++  ["number"] => ++  float(3.141593) ++  ["date"] => ++  object(DateTime)#%d (19) { ++    ["createFromImmutable"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["createFromFormat"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["getLastErrors"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["format"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["modify"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["add"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["sub"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["getTimezone"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["setTimezone"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["getOffset"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["setTime"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["setDate"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["setISODate"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["setTimestamp"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["getTimestamp"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["diff"] => ++    object(Closure)#%d { ++        function () { [native code] } ++    } ++    ["$date"] => ++    string(%d) "1976-09-27 09:00:00%r(\.0+)?%r" ++    ["$timezone_type"] => ++    int(3) ++    ["$timezone"] => ++    string(3) "UTC" ++  } ++  ["array"] => ++  array(3) { ++    [0] => ++    int(1) ++    [1] => ++    int(2) ++    [2] => ++    int(3) ++  } ++  ["object"] => ++  array (1) { ++    ["field"] => ++    string(3) "foo" ++  } ++  ["function"] => ++  object(Closure)#%d (0) { ++  } ++  ["phpobject"] => ++  object(Foo)#%d (1) { ++    ["$field"] => ++    string(3) "php" ++  } ++} ++--- JS var_dump of JS object ---- ++object(Object)#%d (12) { ++  ["undefined"] => ++  NULL ++  ["null"] => ++  NULL ++  ["bool"] => ++  bool(true) ++  ["string"] => ++  string(6) "string" ++  ["uint"] => ++  int(1) ++  ["int"] => ++  int(-1) ++  ["number"] => ++  float(3.141593) ++  ["regexp"] => ++  regexp(/regexp/) ++  ["array"] => ++  array(3) { ++    [0] => ++    int(1) ++    [1] => ++    int(2) ++    [2] => ++    int(3) ++  } ++  ["object"] => ++  object(Object)#%d (1) { ++    ["field"] => ++    string(3) "foo" ++  } ++  ["function"] => ++  object(Closure)#%d { ++      function id(x) { return x; } ++  } ++  ["phpobject"] => ++  object(Foo)#%d (1) { ++    ["$field"] => ++    string(3) "php" ++  } ++} ++--- PHP var_dump of JS object ---- ++object(V8Object)#%d (12) { ++  ["undefined"]=> ++  NULL ++  ["null"]=> ++  NULL ++  ["bool"]=> ++  bool(true) ++  ["string"]=> ++  string(6) "string" ++  ["uint"]=> ++  int(1) ++  ["int"]=> ++  int(-1) ++  ["number"]=> ++  float(3.141592654) ++  ["regexp"]=> ++  object(V8Object)#%d (0) { ++  } ++  ["array"]=> ++  array(3) { ++    [0]=> ++    int(1) ++    [1]=> ++    int(2) ++    [2]=> ++    int(3) ++  } ++  ["object"]=> ++  object(V8Object)#%d (1) { ++    ["field"]=> ++    string(3) "foo" ++  } ++  ["function"]=> ++  object(V8Function)#%d (0) { ++  } ++  ["phpobject"]=> ++  object(Foo)#%d (1) { ++    ["field"]=> ++    string(3) "php" ++  } ++} ++===EOF=== + +From 61f98e2a4a01ae429390768e92c7af1cb2418f4d Mon Sep 17 00:00:00 2001 +From: Jan-E <github@ehrhardt.nl> +Date: Sat, 7 Jul 2018 05:18:31 +0200 +Subject: [PATCH 11/18] extensions_error.phpt runs fine on Windows + +--- + tests/extensions_error.phpt | 6 ------ + 1 file changed, 6 deletions(-) + +diff --git a/tests/extensions_error.phpt b/tests/extensions_error.phpt +index f59b0b7..b11054a 100644 +--- a/tests/extensions_error.phpt ++++ b/tests/extensions_error.phpt +@@ -9,12 +9,6 @@ phpinfo(INFO_MODULES); + $minfo = ob_get_contents(); + ob_end_clean(); +  +-if(strtoupper(substr(PHP_OS, 0, 3)) == 'WIN') { +-	// On Windows the "Fatal error" happens to appear before the error +-	// message output by V8 itself. +-	echo "skip Windows"; +-} +- + if(preg_match("/V8 Engine Linked Version => (.*)/", $minfo, $matches)) { +     $version = explode('.', $matches[1]); +     if($version[0] < 5 || ($version[0] == 5 && $version[1] < 7)) { + +From 4762dd1f0ae799add559f18307032d697b05497e Mon Sep 17 00:00:00 2001 +From: Stefan Siegl <stesie@brokenpipe.de> +Date: Fri, 13 Jul 2018 14:21:45 +0200 +Subject: [PATCH 13/18] fix null-ptr deref + +--- + v8js_class.cc | 9 +++++++-- + 1 file changed, 7 insertions(+), 2 deletions(-) + +diff --git a/v8js_class.cc b/v8js_class.cc +index 8f66f7c..524e55e 100644 +--- a/v8js_class.cc ++++ b/v8js_class.cc +@@ -273,9 +273,14 @@ static void v8js_jsext_free_storage(v8js_jsext *jsext) /* {{{ */ + 		v8js_free_ext_strarr(jsext->deps, jsext->deps_count); + 	} + 	delete jsext->extension; ++ + 	// Free the persisted non-interned strings we allocated. +-	zend_string_release(jsext->name); +-	zend_string_release(jsext->source); ++	if (jsext->name) { ++		zend_string_release(jsext->name); ++	} ++	if (jsext->source) { ++		zend_string_release(jsext->source); ++	} +  + 	free(jsext); + } + +From 90b6b31f06a7ff990c462d6ec012b28c54a31faf Mon Sep 17 00:00:00 2001 +From: Stefan Siegl <stesie@brokenpipe.de> +Date: Fri, 13 Jul 2018 15:41:41 +0200 +Subject: [PATCH 14/18] break recursion immediately on PHP <= 7.2 as well + +--- + tests/array_recursive.phpt | 25 +++++++++++++++++++++++++ + v8js_convert.cc            | 15 +++++++++------ + 2 files changed, 34 insertions(+), 6 deletions(-) + create mode 100644 tests/array_recursive.phpt + +diff --git a/tests/array_recursive.phpt b/tests/array_recursive.phpt +new file mode 100644 +index 0000000..47df7ea +--- /dev/null ++++ b/tests/array_recursive.phpt +@@ -0,0 +1,25 @@ ++--TEST-- ++Test V8::executeString() : export of recursive array ++--SKIPIF-- ++<?php require_once(dirname(__FILE__) . '/skipif.inc'); ?> ++--FILE-- ++<?php ++ ++$a = []; ++$a[] = &$a; ++$a[] = 23; ++ ++$v8 = new V8Js(); ++$v8->foo = $a; ++$v8->executeString('var_dump(PHP.foo);'); ++ ++?> ++===EOF=== ++--EXPECT-- ++array(2) { ++  [0] => ++  NULL ++  [1] => ++  int(23) ++} ++===EOF=== +diff --git a/v8js_convert.cc b/v8js_convert.cc +index b701154..3f91dd1 100644 +--- a/v8js_convert.cc ++++ b/v8js_convert.cc +@@ -71,10 +71,11 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate +  + 	/* Prevent recursion */ + #if PHP_VERSION_ID >= 70300 +-	if (myht && GC_IS_RECURSIVE(myht)) { ++	if (myht && GC_IS_RECURSIVE(myht)) + #else +-	if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 1) { ++	if (myht && ZEND_HASH_GET_APPLY_COUNT(myht) > 0) + #endif ++	{ + 		return V8JS_NULL; + 	} +  +@@ -86,10 +87,11 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate + 		ulong index = 0; +  + #if PHP_VERSION_ID >= 70300 +-		if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { ++		if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) + #else +-		if (myht) { ++		if (myht) + #endif ++		{ + 			GC_PROTECT_RECURSION(myht); + 		} +  +@@ -98,10 +100,11 @@ static v8::Local<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolate + 		} ZEND_HASH_FOREACH_END(); +  + #if PHP_VERSION_ID >= 70300 +-		if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) { ++		if (myht && !(GC_FLAGS(myht) & GC_IMMUTABLE)) + #else +-		if (myht) { ++		if (myht) + #endif ++		{ + 			GC_UNPROTECT_RECURSION(myht); + 		} + 	} + +From 18b79d90046a63209cedf58ef24e2f4f0281f7a1 Mon Sep 17 00:00:00 2001 +From: Stefan Siegl <stesie@brokenpipe.de> +Date: Wed, 18 Jul 2018 23:36:13 +0200 +Subject: [PATCH 18/18] don't free interned strings, only persistent ones + +--- + v8js_class.cc | 5 ++++- + 1 file changed, 4 insertions(+), 1 deletion(-) + +diff --git a/v8js_class.cc b/v8js_class.cc +index a9cda70..9f67992 100644 +--- a/v8js_class.cc ++++ b/v8js_class.cc +@@ -991,7 +991,10 @@ static void v8js_persistent_zval_ctor(zval *p) /* {{{ */ + static void v8js_persistent_zval_dtor(zval *p) /* {{{ */ + { + 	assert(Z_TYPE_P(p) == IS_STRING); +-	free(Z_STR_P(p)); ++ ++	if (!ZSTR_IS_INTERNED(Z_STR_P(p))) { ++		free(Z_STR_P(p)); ++	} + } + /* }}} */ +   | 
