Prechádzať zdrojové kódy

Merge pull request #296 from stesie/win64-precission-loss-fixes

Win64 precission loss fixes
Stefan Siegl 8 rokov pred
rodič
commit
6d5a3a2ea6
11 zmenil súbory, kde vykonal 321 pridanie a 75 odobranie
  1. 7 4
      php_v8js_macros.h
  2. 3 2
      v8js.cc
  3. 13 4
      v8js_array_access.cc
  4. 85 14
      v8js_class.cc
  5. 25 15
      v8js_convert.cc
  6. 13 6
      v8js_methods.cc
  7. 105 17
      v8js_object_export.cc
  8. 9 2
      v8js_v8.cc
  9. 6 0
      v8js_v8.h
  10. 41 7
      v8js_v8object_class.cc
  11. 14 4
      v8js_variables.cc

+ 7 - 4
php_v8js_macros.h

@@ -2,7 +2,7 @@
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2016 The PHP Group                                |
+  | Copyright (c) 1997-2017 The PHP Group                                |
   +----------------------------------------------------------------------+
   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
   +----------------------------------------------------------------------+
@@ -79,7 +79,10 @@ extern "C" {
 
 
 /* Convert zval into V8 value */
-v8::Handle<v8::Value> zval_to_v8js(zval *, v8::Isolate * TSRMLS_DC);
+v8::Handle<v8::Value> zval_to_v8js(zval *, v8::Isolate *);
+
+/* Convert zend_long into V8 value */
+v8::Handle<v8::Value> zend_long_to_v8js(zend_long, v8::Isolate *);
 
 /* Convert V8 value into zval */
 int v8js_to_zval(v8::Handle<v8::Value>, zval *, int, v8::Isolate * TSRMLS_DC);
@@ -102,7 +105,7 @@ struct v8js_timer_ctx;
 /* Module globals */
 ZEND_BEGIN_MODULE_GLOBALS(v8js)
   // Thread-local cache whether V8 has been initialized so far
-  int v8_initialized;
+  bool v8_initialized;
 
   /* Ini globals */
   bool use_date; /* Generate JS Date objects instead of PHP DateTime */
@@ -141,7 +144,7 @@ ZEND_EXTERN_MODULE_GLOBALS(v8js)
  */
 struct _v8js_process_globals {
 #ifdef ZTS
-	int v8_initialized;
+	bool v8_initialized;
 	std::mutex lock;
 #endif
 

+ 3 - 2
v8js.cc

@@ -2,12 +2,13 @@
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2013 The PHP Group                                |
+  | Copyright (c) 1997-2017 The PHP Group                                |
   +----------------------------------------------------------------------+
   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
   +----------------------------------------------------------------------+
   | Author: Jani Taskinen <[email protected]>                         |
   | Author: Patrick Reilly <[email protected]>                             |
+  | Author: Stefan Siegl <[email protected]>                                |
   +----------------------------------------------------------------------+
 */
 
@@ -77,7 +78,7 @@ static bool v8js_ini_to_bool(const zend_string *new_value) /* {{{ */
 	} else if (ZSTR_LEN(new_value) == 4 && strcasecmp("true", ZSTR_VAL(new_value)) == 0) {
 		return true;
 	} else {
-		return (bool) atoi(ZSTR_VAL(new_value));
+		return 0 != atoi(ZSTR_VAL(new_value));
 	}
 }
 /* }}} */

+ 13 - 4
v8js_array_access.cc

@@ -2,11 +2,11 @@
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2016 The PHP Group                                |
+  | Copyright (c) 1997-2017 The PHP Group                                |
   +----------------------------------------------------------------------+
   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
   +----------------------------------------------------------------------+
-  | Author: Stefan Siegl <stesie@brokenpipe.de>                          |
+  | Author: Stefan Siegl <stesie@php.net>                                |
   +----------------------------------------------------------------------+
 */
 
@@ -16,6 +16,7 @@
 
 #include "php_v8js_macros.h"
 #include "v8js_array_access.h"
+#include "v8js_exceptions.h"
 #include "v8js_object_export.h"
 
 extern "C" {
@@ -24,6 +25,7 @@ extern "C" {
 #include "ext/standard/php_string.h"
 #include "zend_interfaces.h"
 #include "zend_closures.h"
+#include "zend_exceptions.h"
 }
 
 static zval v8js_array_access_dispatch(zend_object *object, const char *method_name, int param_count,
@@ -123,8 +125,15 @@ static int v8js_array_access_get_count_result(zend_object *object TSRMLS_DC) /*
 		return 0;
 	}
 
-	int result = Z_LVAL(php_value);
-	return result;
+	zend_long result = Z_LVAL(php_value);
+	
+	if (result > std::numeric_limits<int>::max()) {
+		zend_throw_exception(php_ce_v8js_exception,
+			"Array size/offset exceeds maximum supported length", 0);
+		return 0;
+	}
+
+	return static_cast<int>(result);
 }
 /* }}} */
 

+ 85 - 14
v8js_class.cc

@@ -2,7 +2,7 @@
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2016 The PHP Group                                |
+  | Copyright (c) 1997-2017 The PHP Group                                |
   +----------------------------------------------------------------------+
   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
   +----------------------------------------------------------------------+
@@ -362,8 +362,14 @@ static PHP_METHOD(V8Js, __construct)
 		if (Z_TYPE_P(snapshot_blob) == IS_STRING) {
 			ZVAL_COPY(&c->zval_snapshot_blob, snapshot_blob);
 
+			if (Z_STRLEN_P(snapshot_blob) > std::numeric_limits<int>::max()) {
+				zend_throw_exception(php_ce_v8js_exception,
+					"Snapshot size exceeds maximum supported length", 0);
+				return;
+			}
+
 			c->snapshot_blob.data = Z_STRVAL_P(snapshot_blob);
-			c->snapshot_blob.raw_size = Z_STRLEN_P(snapshot_blob);
+			c->snapshot_blob.raw_size = static_cast<int>(Z_STRLEN_P(snapshot_blob));
 			c->create_params.snapshot_blob = &c->snapshot_blob;
 		} else {
 			php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument snapshot_blob expected to be of string type");
@@ -445,7 +451,14 @@ static PHP_METHOD(V8Js, __construct)
 
 	/* Set class name for PHP object */
 	zend_class_entry *ce = Z_OBJCE_P(getThis());
-	php_obj_t->SetClassName(V8JS_SYML(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name)));
+
+	if (ZSTR_LEN(ce->name) > std::numeric_limits<int>::max()) {
+		zend_throw_exception(php_ce_v8js_exception,
+			"PHP object class name exceeds maximum supported length", 0);
+		return;
+	}
+
+	php_obj_t->SetClassName(V8JS_SYML(ZSTR_VAL(ce->name), static_cast<int>(ZSTR_LEN(ce->name))));
 
 	/* Register Get accessor for passed variables */
 	if (vars_arr && zend_hash_num_elements(Z_ARRVAL_P(vars_arr)) > 0) {
@@ -453,9 +466,22 @@ static PHP_METHOD(V8Js, __construct)
 	}
 
 	/* Set name for the PHP JS object */
-	v8::Local<v8::String> object_name_js = (object_name && ZSTR_LEN(object_name))
-		? V8JS_ZSYM(object_name)
-		: V8JS_SYM("PHP");
+	v8::Local<v8::String> object_name_js;
+
+	if (object_name && ZSTR_LEN(object_name)) {
+		if (ZSTR_LEN(object_name) > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"PHP JS object class name exceeds maximum supported length", 0);
+			return;
+		}
+
+		object_name_js = v8::String::NewFromUtf8(isolate, ZSTR_VAL(object_name),
+			v8::String::kInternalizedString, static_cast<int>(ZSTR_LEN(object_name)));
+	}
+	else {
+		object_name_js = V8JS_SYM("PHP");
+	}
+
 	c->object_name.Reset(isolate, object_name_js);
 
 	/* Add the PHP object into global object */
@@ -473,9 +499,18 @@ static PHP_METHOD(V8Js, __construct)
 		if(property_info &&
 		   property_info != ZEND_WRONG_PROPERTY_INFO &&
 		   (property_info->flags & ZEND_ACC_PUBLIC)) {
+			if (ZSTR_LEN(member) > std::numeric_limits<int>::max()) {
+				zend_throw_exception(php_ce_v8js_exception,
+					"Property name exceeds maximum supported length", 0);
+				return;
+			}
+
+			v8::Local<v8::Value> key = v8::String::NewFromUtf8(isolate, ZSTR_VAL(member),
+				v8::String::kInternalizedString, static_cast<int>(ZSTR_LEN(member)));
+
 			/* Write value to PHP JS object */
 			value = OBJ_PROP(Z_OBJ_P(getThis()), property_info->offset);
-			php_obj->ForceSet(V8JS_ZSYM(member), zval_to_v8js(value, isolate TSRMLS_CC), v8::ReadOnly);
+			php_obj->ForceSet(key, zval_to_v8js(value, isolate TSRMLS_CC), v8::ReadOnly);
 		}
 	} ZEND_HASH_FOREACH_END();
 
@@ -527,7 +562,15 @@ static PHP_METHOD(V8Js, __construct)
 			continue;
 		}
 
-		v8::Local<v8::String> method_name = V8JS_ZSTR(method_ptr->common.function_name);
+		if (ZSTR_LEN(method_ptr->common.function_name) > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Method name exceeds maximum supported length", 0);
+			return;
+		}
+
+		v8::Local<v8::String> method_name = v8::String::NewFromUtf8(isolate,
+			ZSTR_VAL(method_ptr->common.function_name), v8::String::kInternalizedString,
+			static_cast<int>(ZSTR_LEN(method_ptr->common.function_name)));
 		v8::Local<v8::FunctionTemplate> ft;
 
 		/*try {
@@ -567,7 +610,7 @@ PHP_METHOD(V8Js, __wakeup)
 }
 /* }}} */
 
-static void v8js_compile_script(zval *this_ptr, zend_string *str, zend_string *identifier, v8js_script **ret TSRMLS_DC)
+static void v8js_compile_script(zval *this_ptr, const zend_string *str, const zend_string *identifier, v8js_script **ret TSRMLS_DC)
 {
 	v8js_script *res = NULL;
 
@@ -577,10 +620,24 @@ static void v8js_compile_script(zval *this_ptr, zend_string *str, zend_string *i
 	v8::TryCatch try_catch;
 
 	/* Set script identifier */
-	v8::Local<v8::String> sname = identifier ? V8JS_ZSTR(identifier) : V8JS_SYM("V8Js::compileString()");
+	if (identifier && ZSTR_LEN(identifier) > std::numeric_limits<int>::max()) {
+		zend_throw_exception(php_ce_v8js_exception,
+			"Script identifier exceeds maximum supported length", 0);
+		return;
+	}
+
+	v8::Local<v8::String> sname = identifier
+		? v8::String::NewFromUtf8(isolate, ZSTR_VAL(identifier), v8::String::kNormalString, static_cast<int>(ZSTR_LEN(identifier)))
+		: V8JS_SYM("V8Js::compileString()");
 
 	/* Compiles a string context independently. TODO: Add a php function which calls this and returns the result as resource which can be executed later. */
-	v8::Local<v8::String> source = V8JS_ZSTR(str);
+	if (ZSTR_LEN(str) > std::numeric_limits<int>::max()) {
+		zend_throw_exception(php_ce_v8js_exception,
+			"Script source exceeds maximum supported length", 0);
+		return;
+	}
+
+	v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, ZSTR_VAL(str), v8::String::kNormalString, static_cast<int>(ZSTR_LEN(str)));
 	v8::Local<v8::Script> script = v8::Script::Compile(source, sname);
 
 	/* Compile errors? */
@@ -1020,7 +1077,7 @@ static PHP_METHOD(V8Js, registerExtension)
 static PHP_METHOD(V8Js, getExtensions)
 {
 	v8js_jsext *jsext;
-	ulong index;
+	zend_ulong index;
 	zend_string *key;
 	zval *val, ext;
 
@@ -1209,8 +1266,15 @@ static void v8js_write_property(zval *object, zval *member, zval *value, void **
 		v8::Local<v8::String> object_name_js = v8::Local<v8::String>::New(isolate, c->object_name);
 		v8::Local<v8::Object> jsobj = V8JS_GLOBAL(isolate)->Get(object_name_js)->ToObject();
 
+		if (Z_STRLEN_P(member) > std::numeric_limits<int>::max()) {
+				zend_throw_exception(php_ce_v8js_exception,
+						"Property name exceeds maximum supported length", 0);
+				return;
+		}
+
 		/* Write value to PHP JS object */
-		jsobj->ForceSet(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)), zval_to_v8js(value, isolate TSRMLS_CC), v8::ReadOnly);
+		v8::Local<v8::Value> key = V8JS_SYML(Z_STRVAL_P(member), static_cast<int>(Z_STRLEN_P(member)));
+		jsobj->ForceSet(key, zval_to_v8js(value, isolate TSRMLS_CC), v8::ReadOnly);
 	}
 
 	/* Write value to PHP object */
@@ -1226,8 +1290,15 @@ static void v8js_unset_property(zval *object, zval *member, void **cache_slot TS
 	v8::Local<v8::String> object_name_js = v8::Local<v8::String>::New(isolate, c->object_name);
 	v8::Local<v8::Object> jsobj = V8JS_GLOBAL(isolate)->Get(object_name_js)->ToObject();
 
+	if (Z_STRLEN_P(member) > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+					"Property name exceeds maximum supported length", 0);
+			return;
+	}
+
 	/* Delete value from PHP JS object */
-	jsobj->Delete(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)));
+	v8::Local<v8::Value> key = V8JS_SYML(Z_STRVAL_P(member), static_cast<int>(Z_STRLEN_P(member)));
+	jsobj->Delete(key);
 
 	/* Unset from PHP object */
 	std_object_handlers.unset_property(object, member, NULL);

+ 25 - 15
v8js_convert.cc

@@ -2,7 +2,7 @@
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2016 The PHP Group                                |
+  | Copyright (c) 1997-2017 The PHP Group                                |
   +----------------------------------------------------------------------+
   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
   +----------------------------------------------------------------------+
@@ -20,6 +20,7 @@
 #include <limits>
 
 #include "php_v8js_macros.h"
+#include "v8js_exceptions.h"
 #include "v8js_object_export.h"
 #include "v8js_v8object_class.h"
 #include "v8js_v8.h"
@@ -30,12 +31,13 @@ extern "C" {
 #include "ext/standard/php_string.h"
 #include "zend_interfaces.h"
 #include "zend_closures.h"
+#include "zend_exceptions.h"
 }
 
 static int v8js_is_assoc_array(HashTable *myht TSRMLS_DC) /* {{{ */
 {
 	zend_string *key;
-	ulong index, idx = 0;
+	zend_ulong index, idx = 0;
 
 	ZEND_HASH_FOREACH_KEY(myht, index, key) {
 		if(key) {
@@ -98,10 +100,20 @@ static v8::Handle<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolat
 }
 /* }}} */
 
-v8::Handle<v8::Value> zval_to_v8js(zval *value, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
+v8::Handle<v8::Value> zend_long_to_v8js(zend_long v, v8::Isolate *isolate) /* {{{ */
+{
+	if (v < - std::numeric_limits<int32_t>::min() || v > std::numeric_limits<int32_t>::max()) {
+		return V8JS_FLOAT(static_cast<double>(v));
+	} else {
+		return V8JS_INT(static_cast<int32_t>(v));
+	}
+}
+/* }}} */
+
+v8::Handle<v8::Value> zval_to_v8js(zval *value, v8::Isolate *isolate) /* {{{ */
 {
 	v8::Handle<v8::Value> jsValue;
-	zend_long v;
+	zend_string *value_str;
 	zend_class_entry *ce;
 
 	switch (Z_TYPE_P(value))
@@ -133,20 +145,18 @@ v8::Handle<v8::Value> zval_to_v8js(zval *value, v8::Isolate *isolate TSRMLS_DC)
 			break;
 
 		case IS_STRING:
-			jsValue = V8JS_ZSTR(Z_STR_P(value));
+			value_str = Z_STR_P(value);
+			if (ZSTR_LEN(value_str) > std::numeric_limits<int>::max()) {
+				zend_throw_exception(php_ce_v8js_exception,
+					"String exceeds maximum string length", 0);
+				break;
+			}
+
+			jsValue = v8::String::NewFromUtf8(isolate, ZSTR_VAL(value_str), v8::String::kNormalString, static_cast<int>(ZSTR_LEN(value_str)));
 			break;
 
 		case IS_LONG:
-		    v = Z_LVAL_P(value);
-			/* On Windows there are max and min macros, which would clobber the
-			 * method names of std::numeric_limits< > otherwise. */
-#undef max
-#undef min
-			if (v < - std::numeric_limits<int32_t>::min() || v > std::numeric_limits<int32_t>::max()) {
-				jsValue = V8JS_FLOAT(static_cast<double>(v));
-			} else {
-				jsValue = V8JS_INT(static_cast<int32_t>(v));
-			}
+			jsValue = zend_long_to_v8js(Z_LVAL_P(value), isolate);
 			break;
 
 		case IS_DOUBLE:

+ 13 - 6
v8js_methods.cc

@@ -2,13 +2,13 @@
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2013 The PHP Group                                |
+  | Copyright (c) 1997-2017 The PHP Group                                |
   +----------------------------------------------------------------------+
   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
   +----------------------------------------------------------------------+
   | Author: Jani Taskinen <[email protected]>                         |
   | Author: Patrick Reilly <[email protected]>                             |
-  | Author: Stefan Siegl <stesie@brokenpipe.de>                          |
+  | Author: Stefan Siegl <stesie@php.net>                                |
   +----------------------------------------------------------------------+
 */
 
@@ -18,6 +18,7 @@
 
 #include "php_v8js_macros.h"
 #include "v8js_commonjs.h"
+#include "v8js_exceptions.h"
 
 extern "C" {
 #include "zend_exceptions.h"
@@ -42,15 +43,15 @@ V8JS_METHOD(sleep) /* {{{ */
 V8JS_METHOD(print) /* {{{ */
 {
 	v8::Isolate *isolate = info.GetIsolate();
-	int ret = 0;
-	V8JS_TSRMLS_FETCH();
+	zend_long ret = 0;
 
 	for (int i = 0; i < info.Length(); i++) {
 		v8::String::Utf8Value str(info[i]);
 		const char *cstr = ToCString(str);
 		ret = PHPWRITE(cstr, strlen(cstr));
 	}
-	info.GetReturnValue().Set(V8JS_INT(ret));
+
+	info.GetReturnValue().Set(zend_long_to_v8js(ret, isolate));
 }
 /* }}} */
 
@@ -433,7 +434,13 @@ V8JS_METHOD(require)
 	// Set script identifier
 	v8::Local<v8::String> sname = V8JS_STR(normalised_module_id);
 
-	v8::Local<v8::String> source = V8JS_ZSTR(Z_STR(module_code));
+	if (Z_STRLEN(module_code) > std::numeric_limits<int>::max()) {
+		zend_throw_exception(php_ce_v8js_exception,
+			"Module code size exceeds maximum supported length", 0);
+		return;
+	}
+
+	v8::Local<v8::String> source = V8JS_STRL(Z_STRVAL(module_code), static_cast<int>(Z_STRLEN(module_code)));
 	zval_ptr_dtor(&module_code);
 
 	// Create and compile script

+ 105 - 17
v8js_object_export.cc

@@ -2,7 +2,7 @@
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2016 The PHP Group                                |
+  | Copyright (c) 1997-2017 The PHP Group                                |
   +----------------------------------------------------------------------+
   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
   +----------------------------------------------------------------------+
@@ -18,6 +18,7 @@
 
 #include "php_v8js_macros.h"
 #include "v8js_array_access.h"
+#include "v8js_exceptions.h"
 #include "v8js_generator_export.h"
 #include "v8js_object_export.h"
 #include "v8js_v8object_class.h"
@@ -42,7 +43,7 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, v
 	zval fname, retval;
 	unsigned int argc = info.Length(), min_num_args = 0, max_num_args = 0;
 	char *error;
-	int error_len;
+	zend_ulong error_len;
 	unsigned int i;
 
 	v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0);
@@ -77,7 +78,14 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, v
 				(argc < min_num_args ? min_num_args : max_num_args) == 1 ? "" : "s",
 				argc);
 
-		return_value = V8JS_THROW(isolate, TypeError, error, error_len);
+		if (error_len > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Generated error message length exceeds maximum supported length", 0);
+		}
+		else {
+			return_value = V8JS_THROW(isolate, TypeError, error, static_cast<int>(error_len));
+		}
+
 		if (object->ce == zend_ce_closure) {
 			zend_string_release(method_ptr->internal_function.function_name);
 			efree(method_ptr);
@@ -100,7 +108,15 @@ static void v8js_call_php_func(zend_object *object, zend_function *method_ptr, v
 			} else {
 				if (v8js_to_zval(info[i], &fci.params[i], ctx->flags, isolate TSRMLS_CC) == FAILURE) {
 					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);
+
+					if (error_len > std::numeric_limits<int>::max()) {
+						zend_throw_exception(php_ce_v8js_exception,
+							"Generated error message length exceeds maximum supported length", 0);
+					}
+					else {
+						return_value = V8JS_THROW(isolate, Error, error, static_cast<int>(error_len));
+					}
+
 					efree(error);
 					goto failure;
 				}
@@ -311,7 +327,7 @@ static void v8js_named_property_enumerator(const v8::PropertyCallbackInfo<v8::Ar
 	void *ptr;
 	HashTable *proptable;
 	zend_string *key;
-	ulong index;
+	zend_ulong index;
 
 	zend_object *object = reinterpret_cast<zend_object *>(self->GetAlignedPointerFromInternalField(1));
 	ce = object->ce;
@@ -340,11 +356,23 @@ static void v8js_named_property_enumerator(const v8::PropertyCallbackInfo<v8::Ar
 			IS_MAGIC_FUNC(ZEND_ISSET_FUNC_NAME)) {
 			continue;
 		}
-		v8::Local<v8::String> method_name = V8JS_ZSTR(method_ptr->common.function_name);
+
+		v8::Local<v8::String> method_name;
+
 		// rename PHP special method names to JS equivalents.
 		if (IS_MAGIC_FUNC(ZEND_TOSTRING_FUNC_NAME)) {
 			method_name = V8JS_SYM("toString");
 		}
+		else {
+			if (ZSTR_LEN(method_ptr->common.function_name) > std::numeric_limits<int>::max()) {
+				zend_throw_exception(php_ce_v8js_exception,
+					"Method name length exceeds maximum supported length", 0);
+				return;
+			}
+
+			method_name = V8JS_STRL(ZSTR_VAL(method_ptr->common.function_name), static_cast<int>(ZSTR_LEN(method_ptr->common.function_name)));
+		}
+
 		result->Set(result_len++, method_name);
 	} ZEND_HASH_FOREACH_END();
 
@@ -362,13 +390,20 @@ static void v8js_named_property_enumerator(const v8::PropertyCallbackInfo<v8::Ar
 			if(ZSTR_VAL(key)[0] == '\0') {
 				continue;
 			}
+
+			if (ZSTR_LEN(key) + 1 > std::numeric_limits<int>::max()) {
+				zend_throw_exception(php_ce_v8js_exception,
+					"Object key length exceeds maximum supported length", 0);
+				continue;
+			}
+
 			// prefix enumerated property names with '$' so they can be
 			// dereferenced unambiguously (ie, don't conflict with method
 			// names)
 			char *prefixed = static_cast<char *>(emalloc(ZSTR_LEN(key) + 2));
 			prefixed[0] = '$';
 			strncpy(prefixed + 1, ZSTR_VAL(key), ZSTR_LEN(key) + 1);
-			result->Set(result_len++, V8JS_STRL(prefixed, ZSTR_LEN(key) + 1));
+			result->Set(result_len++, V8JS_STRL(prefixed, static_cast<int>(ZSTR_LEN(key) + 1)));
 			efree(prefixed);
 		} else {
 			// even numeric indices are enumerated as strings in JavaScript
@@ -425,10 +460,10 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo<v8::Value>& info)
 {
 	v8::Isolate *isolate = info.GetIsolate();
 	v8::Local<v8::Object> self = info.Holder();
-	v8::Handle<v8::Value> return_value;
+	v8::Handle<v8::Value> return_value = V8JS_NULL;
 
 	char *error;
-	int error_len;
+	size_t error_len;
 
 	V8JS_TSRMLS_FETCH();
 	zend_class_entry *ce;
@@ -440,16 +475,33 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo<v8::Value>& info)
 		error_len = spprintf(&error, 0,
 			"%s::__call expects 2 parameters, %d given",
 			ce->name, (int) info.Length());
-		return_value = V8JS_THROW(isolate, TypeError, error, error_len);
+
+		if (error_len > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Generated error message length exceeds maximum supported length", 0);
+		}
+		else {
+			return_value = V8JS_THROW(isolate, TypeError, error, static_cast<int>(error_len));
+		}
+
 		efree(error);
 		info.GetReturnValue().Set(return_value);
 		return;
 	}
+
 	if (!info[1]->IsArray()) {
 		error_len = spprintf(&error, 0,
 			"%s::__call expects 2nd parameter to be an array",
 			ce->name);
-		return_value = V8JS_THROW(isolate, TypeError, error, error_len);
+
+		if (error_len > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Generated error message length exceeds maximum supported length", 0);
+		}
+		else {
+			return_value = V8JS_THROW(isolate, TypeError, error, static_cast<int>(error_len));
+		}
+
 		efree(error);
 		info.GetReturnValue().Set(return_value);
 		return;
@@ -462,7 +514,15 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo<v8::Value>& info)
 		error_len = spprintf(&error, 0,
 			"%s::__call expects fewer than a million arguments",
 			ce->name);
-		return_value = V8JS_THROW(isolate, TypeError, error, error_len);
+
+		if (error_len > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Generated error message length exceeds maximum supported length", 0);
+		}
+		else {
+			return_value = V8JS_THROW(isolate, TypeError, error, static_cast<int>(error_len));
+		}
+
 		efree(error);
 		info.GetReturnValue().Set(return_value);
 		return;
@@ -484,7 +544,15 @@ static void v8js_fake_call_impl(const v8::FunctionCallbackInfo<v8::Value>& info)
 		error_len = spprintf(&error, 0,
 			"%s::__call to %s method %s", ce->name,
 			(method_ptr == NULL) ? "undefined" : "non-public", method_name);
-		return_value = V8JS_THROW(isolate, TypeError, error, error_len);
+
+		if (error_len > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Generated error message length exceeds maximum supported length", 0);
+		}
+		else {
+			return_value = V8JS_THROW(isolate, TypeError, error, static_cast<int>(error_len));
+		}
+
 		efree(error);
 		info.GetReturnValue().Set(return_value);
 		return;
@@ -759,7 +827,13 @@ static v8::Handle<v8::Object> v8js_wrap_object(v8::Isolate *isolate, zend_class_
 		/* No cached v8::FunctionTemplate available as of yet, create one. */
 		new_tpl = v8::FunctionTemplate::New(isolate, 0);
 
-		new_tpl->SetClassName(V8JS_ZSTR(ce->name));
+		if (ZSTR_LEN(ce->name) > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Class name length exceeds maximum supported length", 0);
+			return v8::Local<v8::Object>();
+		}
+
+		new_tpl->SetClassName(V8JS_STRL(ZSTR_VAL(ce->name), static_cast<int>(ZSTR_LEN(ce->name))));
 		new_tpl->InstanceTemplate()->SetInternalFieldCount(2);
 
 		if (ce == zend_ce_closure) {
@@ -855,7 +929,7 @@ static v8::Handle<v8::Object> v8js_wrap_array_to_object(v8::Isolate *isolate, zv
 {
 	int i;
 	zend_string *key;
-	ulong index;
+	zend_ulong index;
 
 	v8js_ctx *ctx = (v8js_ctx *) isolate->GetData(0);
 	v8::Local<v8::FunctionTemplate> new_tpl;
@@ -899,9 +973,23 @@ static v8::Handle<v8::Object> v8js_wrap_array_to_object(v8::Isolate *isolate, zv
 					}
 					continue;
 				}
-				newobj->Set(V8JS_ZSTR(key), zval_to_v8js(data, isolate TSRMLS_CC));
+
+				if (ZSTR_LEN(key) > std::numeric_limits<int>::max()) {
+					zend_throw_exception(php_ce_v8js_exception,
+						"Object key length exceeds maximum supported length", 0);
+					continue;
+				}
+
+				newobj->Set(V8JS_STRL(ZSTR_VAL(key), static_cast<int>(ZSTR_LEN(key))),
+					zval_to_v8js(data, isolate));
 			} else {
-				newobj->Set(index, zval_to_v8js(data, isolate TSRMLS_CC));
+				if (index > std::numeric_limits<uint32_t>::max()) {
+					zend_throw_exception(php_ce_v8js_exception,
+						"Array index exceeds maximum supported bound", 0);
+					continue;
+				}
+
+				newobj->Set(static_cast<uint32_t>(index), zval_to_v8js(data, isolate));
 			}
 
 			if (tmp_ht) {

+ 9 - 2
v8js_v8.cc

@@ -65,8 +65,15 @@ void v8js_v8_init(TSRMLS_D) /* {{{ */
 
 	/* Set V8 command line flags (must be done before V8::Initialize()!) */
 	if (v8js_process_globals.v8_flags) {
-		v8::V8::SetFlagsFromString(v8js_process_globals.v8_flags,
-								   strlen(v8js_process_globals.v8_flags));
+		size_t flags_len = strlen(v8js_process_globals.v8_flags);
+
+		if (flags_len > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Length of V8 flags exceeds maximum supported length", 0);
+		}
+		else {
+			v8::V8::SetFlagsFromString(v8js_process_globals.v8_flags, static_cast<int>(flags_len));
+		}
 	}
 
 	/* Initialize V8 */

+ 6 - 0
v8js_v8.h

@@ -36,6 +36,12 @@
 #define V8JS_GLOBAL(isolate)			((isolate)->GetCurrentContext()->Global())
 
 
+/* On Windows there are max and min macros, which would clobber the
+ * method names of std::numeric_limits< > otherwise. */
+#undef max
+#undef min
+
+
 /* Extracts a C string from a V8 Utf8Value. */
 static inline const char * ToCString(const v8::String::Utf8Value &value) /* {{{ */
 {

+ 41 - 7
v8js_v8object_class.cc

@@ -2,7 +2,7 @@
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2016 The PHP Group                                |
+  | Copyright (c) 1997-2017 The PHP Group                                |
   +----------------------------------------------------------------------+
   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
   +----------------------------------------------------------------------+
@@ -67,9 +67,14 @@ static int v8js_v8object_has_property(zval *object, zval *member, int has_set_ex
 
 	if (Z_TYPE_P(member) == IS_STRING && v8obj->IsObject())
 	{
+		if (Z_STRLEN_P(member) > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Member name length exceeds maximum supported length", 0);
+			return retval;
+		}
 
 		v8::Local<v8::Object> jsObj = v8obj->ToObject();
-		v8::Local<v8::String> jsKey = V8JS_ZSTR(Z_STR_P(member));
+		v8::Local<v8::String> jsKey = V8JS_STRL(Z_STRVAL_P(member), static_cast<int>(Z_STRLEN_P(member)));
 		v8::Local<v8::Value> jsVal;
 
 		/* Skip any prototype properties */
@@ -126,9 +131,14 @@ static zval *v8js_v8object_read_property(zval *object, zval *member, int type, v
 
 	if (Z_TYPE_P(member) == IS_STRING && v8obj->IsObject())
 	{
+		if (Z_STRLEN_P(member) > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Member name length exceeds maximum supported length", 0);
+			return retval;
+		}
 
 		v8::Local<v8::Object> jsObj = v8obj->ToObject();
-		v8::Local<v8::String> jsKey = V8JS_ZSTR(Z_STR_P(member));
+		v8::Local<v8::String> jsKey = V8JS_STRL(Z_STRVAL_P(member), static_cast<int>(Z_STRLEN_P(member)));
 		v8::Local<v8::Value> jsVal;
 
 		/* Skip any prototype properties */
@@ -158,8 +168,14 @@ static void v8js_v8object_write_property(zval *object, zval *member, zval *value
 	V8JS_CTX_PROLOGUE(obj->ctx);
 	v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(isolate, obj->v8obj);
 
+	if (Z_STRLEN_P(member) > std::numeric_limits<int>::max()) {
+		zend_throw_exception(php_ce_v8js_exception,
+			"Member name length exceeds maximum supported length", 0);
+		return;
+	}
+
 	if (v8obj->IsObject()) {
-		v8obj->ToObject()->ForceSet(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)), zval_to_v8js(value, isolate TSRMLS_CC));
+		v8obj->ToObject()->ForceSet(V8JS_SYML(Z_STRVAL_P(member), static_cast<int>(Z_STRLEN_P(member))), zval_to_v8js(value, isolate));
 	}
 }
 /* }}} */
@@ -177,8 +193,14 @@ static void v8js_v8object_unset_property(zval *object, zval *member, void **cach
 	V8JS_CTX_PROLOGUE(obj->ctx);
 	v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(isolate, obj->v8obj);
 
+	if (Z_STRLEN_P(member) > std::numeric_limits<int>::max()) {
+		zend_throw_exception(php_ce_v8js_exception,
+			"Member name length exceeds maximum supported length", 0);
+		return;
+	}
+
 	if (v8obj->IsObject()) {
-		v8obj->ToObject()->Delete(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)));
+		v8obj->ToObject()->Delete(V8JS_SYML(Z_STRVAL_P(member), static_cast<int>(Z_STRLEN_P(member))));
 	}
 }
 /* }}} */
@@ -241,8 +263,14 @@ static zend_function *v8js_v8object_get_method(zend_object **object_ptr, zend_st
 		return NULL;
 	}
 
+	if (ZSTR_LEN(method) > std::numeric_limits<int>::max()) {
+		zend_throw_exception(php_ce_v8js_exception,
+			"Method name length exceeds maximum supported length", 0);
+		return NULL;
+	}
+
 	V8JS_CTX_PROLOGUE_EX(obj->ctx, NULL);
-	v8::Local<v8::String> jsKey = V8JS_ZSTR(method);
+	v8::Local<v8::String> jsKey = V8JS_STRL(ZSTR_VAL(method), static_cast<int>(ZSTR_LEN(method)));
 	v8::Local<v8::Value> v8obj = v8::Local<v8::Value>::New(isolate, obj->v8obj);
 
 	if (!obj->v8obj.IsEmpty() && v8obj->IsObject() && !v8obj->IsFunction()) {
@@ -277,6 +305,12 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I
 		return FAILURE;
 	}
 
+	if (ZSTR_LEN(method) > std::numeric_limits<int>::max()) {
+		zend_throw_exception(php_ce_v8js_exception,
+			"Method name length exceeds maximum supported length", 0);
+		return FAILURE;
+	}
+
 	if (argc > 0) {
 		argv = (zval*)safe_emalloc(sizeof(zval), argc, 0);
 		zend_get_parameters_array_ex(argc, argv);
@@ -288,7 +322,7 @@ static int v8js_v8object_call_method(zend_string *method, zend_object *object, I
 		std::function< v8::Local<v8::Value>(v8::Isolate *) > v8_call = [obj, method, argc, argv, object, &return_value TSRMLS_CC](v8::Isolate *isolate) {
 			int i = 0;
 
-			v8::Local<v8::String> method_name = V8JS_ZSYM(method);
+			v8::Local<v8::String> method_name = V8JS_SYML(ZSTR_VAL(method), static_cast<int>(ZSTR_LEN(method)));
 			v8::Local<v8::Object> v8obj = v8::Local<v8::Value>::New(isolate, obj->v8obj)->ToObject();
 			v8::Local<v8::Object> thisObj;
 			v8::Local<v8::Function> cb;

+ 14 - 4
v8js_variables.cc

@@ -2,17 +2,16 @@
   +----------------------------------------------------------------------+
   | PHP Version 5                                                        |
   +----------------------------------------------------------------------+
-  | Copyright (c) 1997-2013 The PHP Group                                |
+  | Copyright (c) 1997-2017 The PHP Group                                |
   +----------------------------------------------------------------------+
   | http://www.opensource.org/licenses/mit-license.php  MIT License      |
   +----------------------------------------------------------------------+
   | Author: Jani Taskinen <[email protected]>                         |
   | Author: Patrick Reilly <[email protected]>                             |
+  | Author: Stefan Siegl <[email protected]>                                |
   +----------------------------------------------------------------------+
 */
 
-/* $Id:$ */
-
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #endif
@@ -20,6 +19,11 @@
 #include <string>
 
 #include "php_v8js_macros.h"
+#include "v8js_exceptions.h"
+
+extern "C" {
+#include "zend_exceptions.h"
+}
 
 static void v8js_fetch_php_variable(v8::Local<v8::String> name, const v8::PropertyCallbackInfo<v8::Value>& info) /* {{{ */
 {
@@ -66,13 +70,19 @@ void v8js_register_accessors(std::vector<v8js_accessor_ctx*> *accessor_list, v8:
 				continue; /* Ignore invalid values */
 		}
 
+		if (ZSTR_LEN(property_name) > std::numeric_limits<int>::max()) {
+			zend_throw_exception(php_ce_v8js_exception,
+				"Property name length exceeds maximum supported length", 0);
+			continue;
+		}
+
         // Create context to store accessor data
         v8js_accessor_ctx *ctx = (v8js_accessor_ctx *)emalloc(sizeof(v8js_accessor_ctx));
         ctx->variable_name = zend_string_copy(Z_STR_P(item));
         ctx->isolate = isolate;
 
 		/* Set the variable fetch callback for given symbol on named property */
-		php_obj->SetAccessor(V8JS_ZSTR(property_name), v8js_fetch_php_variable, NULL, v8::External::New(isolate, ctx), v8::PROHIBITS_OVERWRITING, v8::ReadOnly, v8::AccessorSignature::New(isolate, php_obj_t));
+		php_obj->SetAccessor(V8JS_STRL(ZSTR_VAL(property_name), static_cast<int>(ZSTR_LEN(property_name))), v8js_fetch_php_variable, NULL, v8::External::New(isolate, ctx), v8::PROHIBITS_OVERWRITING, v8::ReadOnly, v8::AccessorSignature::New(isolate, php_obj_t));
 
 		/* record the context so we can free it later */
 		accessor_list->push_back(ctx);