Skip to content

Commit 6d5a3a2

Browse files
authored
Merge pull request #296 from stesie/win64-precission-loss-fixes
Win64 precission loss fixes
2 parents 299aa6a + 3761657 commit 6d5a3a2

File tree

11 files changed

+321
-75
lines changed

11 files changed

+321
-75
lines changed

php_v8js_macros.h

Lines changed: 7 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
+----------------------------------------------------------------------+
33
| PHP Version 5 |
44
+----------------------------------------------------------------------+
5-
| Copyright (c) 1997-2016 The PHP Group |
5+
| Copyright (c) 1997-2017 The PHP Group |
66
+----------------------------------------------------------------------+
77
| http://www.opensource.org/licenses/mit-license.php MIT License |
88
+----------------------------------------------------------------------+
@@ -79,7 +79,10 @@ extern "C" {
7979

8080

8181
/* Convert zval into V8 value */
82-
v8::Handle<v8::Value> zval_to_v8js(zval *, v8::Isolate * TSRMLS_DC);
82+
v8::Handle<v8::Value> zval_to_v8js(zval *, v8::Isolate *);
83+
84+
/* Convert zend_long into V8 value */
85+
v8::Handle<v8::Value> zend_long_to_v8js(zend_long, v8::Isolate *);
8386

8487
/* Convert V8 value into zval */
8588
int v8js_to_zval(v8::Handle<v8::Value>, zval *, int, v8::Isolate * TSRMLS_DC);
@@ -102,7 +105,7 @@ struct v8js_timer_ctx;
102105
/* Module globals */
103106
ZEND_BEGIN_MODULE_GLOBALS(v8js)
104107
// Thread-local cache whether V8 has been initialized so far
105-
int v8_initialized;
108+
bool v8_initialized;
106109

107110
/* Ini globals */
108111
bool use_date; /* Generate JS Date objects instead of PHP DateTime */
@@ -141,7 +144,7 @@ ZEND_EXTERN_MODULE_GLOBALS(v8js)
141144
*/
142145
struct _v8js_process_globals {
143146
#ifdef ZTS
144-
int v8_initialized;
147+
bool v8_initialized;
145148
std::mutex lock;
146149
#endif
147150

v8js.cc

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
+----------------------------------------------------------------------+
33
| PHP Version 5 |
44
+----------------------------------------------------------------------+
5-
| Copyright (c) 1997-2013 The PHP Group |
5+
| Copyright (c) 1997-2017 The PHP Group |
66
+----------------------------------------------------------------------+
77
| http://www.opensource.org/licenses/mit-license.php MIT License |
88
+----------------------------------------------------------------------+
99
| Author: Jani Taskinen <[email protected]> |
1010
| Author: Patrick Reilly <[email protected]> |
11+
| Author: Stefan Siegl <[email protected]> |
1112
+----------------------------------------------------------------------+
1213
*/
1314

@@ -77,7 +78,7 @@ static bool v8js_ini_to_bool(const zend_string *new_value) /* {{{ */
7778
} else if (ZSTR_LEN(new_value) == 4 && strcasecmp("true", ZSTR_VAL(new_value)) == 0) {
7879
return true;
7980
} else {
80-
return (bool) atoi(ZSTR_VAL(new_value));
81+
return 0 != atoi(ZSTR_VAL(new_value));
8182
}
8283
}
8384
/* }}} */

v8js_array_access.cc

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,11 @@
22
+----------------------------------------------------------------------+
33
| PHP Version 5 |
44
+----------------------------------------------------------------------+
5-
| Copyright (c) 1997-2016 The PHP Group |
5+
| Copyright (c) 1997-2017 The PHP Group |
66
+----------------------------------------------------------------------+
77
| http://www.opensource.org/licenses/mit-license.php MIT License |
88
+----------------------------------------------------------------------+
9-
| Author: Stefan Siegl <stesie@brokenpipe.de> |
9+
| Author: Stefan Siegl <stesie@php.net> |
1010
+----------------------------------------------------------------------+
1111
*/
1212

@@ -16,6 +16,7 @@
1616

1717
#include "php_v8js_macros.h"
1818
#include "v8js_array_access.h"
19+
#include "v8js_exceptions.h"
1920
#include "v8js_object_export.h"
2021

2122
extern "C" {
@@ -24,6 +25,7 @@ extern "C" {
2425
#include "ext/standard/php_string.h"
2526
#include "zend_interfaces.h"
2627
#include "zend_closures.h"
28+
#include "zend_exceptions.h"
2729
}
2830

2931
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) /*
123125
return 0;
124126
}
125127

126-
int result = Z_LVAL(php_value);
127-
return result;
128+
zend_long result = Z_LVAL(php_value);
129+
130+
if (result > std::numeric_limits<int>::max()) {
131+
zend_throw_exception(php_ce_v8js_exception,
132+
"Array size/offset exceeds maximum supported length", 0);
133+
return 0;
134+
}
135+
136+
return static_cast<int>(result);
128137
}
129138
/* }}} */
130139

v8js_class.cc

Lines changed: 85 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
+----------------------------------------------------------------------+
33
| PHP Version 5 |
44
+----------------------------------------------------------------------+
5-
| Copyright (c) 1997-2016 The PHP Group |
5+
| Copyright (c) 1997-2017 The PHP Group |
66
+----------------------------------------------------------------------+
77
| http://www.opensource.org/licenses/mit-license.php MIT License |
88
+----------------------------------------------------------------------+
@@ -362,8 +362,14 @@ static PHP_METHOD(V8Js, __construct)
362362
if (Z_TYPE_P(snapshot_blob) == IS_STRING) {
363363
ZVAL_COPY(&c->zval_snapshot_blob, snapshot_blob);
364364

365+
if (Z_STRLEN_P(snapshot_blob) > std::numeric_limits<int>::max()) {
366+
zend_throw_exception(php_ce_v8js_exception,
367+
"Snapshot size exceeds maximum supported length", 0);
368+
return;
369+
}
370+
365371
c->snapshot_blob.data = Z_STRVAL_P(snapshot_blob);
366-
c->snapshot_blob.raw_size = Z_STRLEN_P(snapshot_blob);
372+
c->snapshot_blob.raw_size = static_cast<int>(Z_STRLEN_P(snapshot_blob));
367373
c->create_params.snapshot_blob = &c->snapshot_blob;
368374
} else {
369375
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Argument snapshot_blob expected to be of string type");
@@ -445,17 +451,37 @@ static PHP_METHOD(V8Js, __construct)
445451

446452
/* Set class name for PHP object */
447453
zend_class_entry *ce = Z_OBJCE_P(getThis());
448-
php_obj_t->SetClassName(V8JS_SYML(ZSTR_VAL(ce->name), ZSTR_LEN(ce->name)));
454+
455+
if (ZSTR_LEN(ce->name) > std::numeric_limits<int>::max()) {
456+
zend_throw_exception(php_ce_v8js_exception,
457+
"PHP object class name exceeds maximum supported length", 0);
458+
return;
459+
}
460+
461+
php_obj_t->SetClassName(V8JS_SYML(ZSTR_VAL(ce->name), static_cast<int>(ZSTR_LEN(ce->name))));
449462

450463
/* Register Get accessor for passed variables */
451464
if (vars_arr && zend_hash_num_elements(Z_ARRVAL_P(vars_arr)) > 0) {
452465
v8js_register_accessors(&c->accessor_list, php_obj_t, vars_arr, isolate TSRMLS_CC);
453466
}
454467

455468
/* Set name for the PHP JS object */
456-
v8::Local<v8::String> object_name_js = (object_name && ZSTR_LEN(object_name))
457-
? V8JS_ZSYM(object_name)
458-
: V8JS_SYM("PHP");
469+
v8::Local<v8::String> object_name_js;
470+
471+
if (object_name && ZSTR_LEN(object_name)) {
472+
if (ZSTR_LEN(object_name) > std::numeric_limits<int>::max()) {
473+
zend_throw_exception(php_ce_v8js_exception,
474+
"PHP JS object class name exceeds maximum supported length", 0);
475+
return;
476+
}
477+
478+
object_name_js = v8::String::NewFromUtf8(isolate, ZSTR_VAL(object_name),
479+
v8::String::kInternalizedString, static_cast<int>(ZSTR_LEN(object_name)));
480+
}
481+
else {
482+
object_name_js = V8JS_SYM("PHP");
483+
}
484+
459485
c->object_name.Reset(isolate, object_name_js);
460486

461487
/* Add the PHP object into global object */
@@ -473,9 +499,18 @@ static PHP_METHOD(V8Js, __construct)
473499
if(property_info &&
474500
property_info != ZEND_WRONG_PROPERTY_INFO &&
475501
(property_info->flags & ZEND_ACC_PUBLIC)) {
502+
if (ZSTR_LEN(member) > std::numeric_limits<int>::max()) {
503+
zend_throw_exception(php_ce_v8js_exception,
504+
"Property name exceeds maximum supported length", 0);
505+
return;
506+
}
507+
508+
v8::Local<v8::Value> key = v8::String::NewFromUtf8(isolate, ZSTR_VAL(member),
509+
v8::String::kInternalizedString, static_cast<int>(ZSTR_LEN(member)));
510+
476511
/* Write value to PHP JS object */
477512
value = OBJ_PROP(Z_OBJ_P(getThis()), property_info->offset);
478-
php_obj->ForceSet(V8JS_ZSYM(member), zval_to_v8js(value, isolate TSRMLS_CC), v8::ReadOnly);
513+
php_obj->ForceSet(key, zval_to_v8js(value, isolate TSRMLS_CC), v8::ReadOnly);
479514
}
480515
} ZEND_HASH_FOREACH_END();
481516

@@ -527,7 +562,15 @@ static PHP_METHOD(V8Js, __construct)
527562
continue;
528563
}
529564

530-
v8::Local<v8::String> method_name = V8JS_ZSTR(method_ptr->common.function_name);
565+
if (ZSTR_LEN(method_ptr->common.function_name) > std::numeric_limits<int>::max()) {
566+
zend_throw_exception(php_ce_v8js_exception,
567+
"Method name exceeds maximum supported length", 0);
568+
return;
569+
}
570+
571+
v8::Local<v8::String> method_name = v8::String::NewFromUtf8(isolate,
572+
ZSTR_VAL(method_ptr->common.function_name), v8::String::kInternalizedString,
573+
static_cast<int>(ZSTR_LEN(method_ptr->common.function_name)));
531574
v8::Local<v8::FunctionTemplate> ft;
532575

533576
/*try {
@@ -567,7 +610,7 @@ PHP_METHOD(V8Js, __wakeup)
567610
}
568611
/* }}} */
569612

570-
static void v8js_compile_script(zval *this_ptr, zend_string *str, zend_string *identifier, v8js_script **ret TSRMLS_DC)
613+
static void v8js_compile_script(zval *this_ptr, const zend_string *str, const zend_string *identifier, v8js_script **ret TSRMLS_DC)
571614
{
572615
v8js_script *res = NULL;
573616

@@ -577,10 +620,24 @@ static void v8js_compile_script(zval *this_ptr, zend_string *str, zend_string *i
577620
v8::TryCatch try_catch;
578621

579622
/* Set script identifier */
580-
v8::Local<v8::String> sname = identifier ? V8JS_ZSTR(identifier) : V8JS_SYM("V8Js::compileString()");
623+
if (identifier && ZSTR_LEN(identifier) > std::numeric_limits<int>::max()) {
624+
zend_throw_exception(php_ce_v8js_exception,
625+
"Script identifier exceeds maximum supported length", 0);
626+
return;
627+
}
628+
629+
v8::Local<v8::String> sname = identifier
630+
? v8::String::NewFromUtf8(isolate, ZSTR_VAL(identifier), v8::String::kNormalString, static_cast<int>(ZSTR_LEN(identifier)))
631+
: V8JS_SYM("V8Js::compileString()");
581632

582633
/* Compiles a string context independently. TODO: Add a php function which calls this and returns the result as resource which can be executed later. */
583-
v8::Local<v8::String> source = V8JS_ZSTR(str);
634+
if (ZSTR_LEN(str) > std::numeric_limits<int>::max()) {
635+
zend_throw_exception(php_ce_v8js_exception,
636+
"Script source exceeds maximum supported length", 0);
637+
return;
638+
}
639+
640+
v8::Local<v8::String> source = v8::String::NewFromUtf8(isolate, ZSTR_VAL(str), v8::String::kNormalString, static_cast<int>(ZSTR_LEN(str)));
584641
v8::Local<v8::Script> script = v8::Script::Compile(source, sname);
585642

586643
/* Compile errors? */
@@ -1020,7 +1077,7 @@ static PHP_METHOD(V8Js, registerExtension)
10201077
static PHP_METHOD(V8Js, getExtensions)
10211078
{
10221079
v8js_jsext *jsext;
1023-
ulong index;
1080+
zend_ulong index;
10241081
zend_string *key;
10251082
zval *val, ext;
10261083

@@ -1209,8 +1266,15 @@ static void v8js_write_property(zval *object, zval *member, zval *value, void **
12091266
v8::Local<v8::String> object_name_js = v8::Local<v8::String>::New(isolate, c->object_name);
12101267
v8::Local<v8::Object> jsobj = V8JS_GLOBAL(isolate)->Get(object_name_js)->ToObject();
12111268

1269+
if (Z_STRLEN_P(member) > std::numeric_limits<int>::max()) {
1270+
zend_throw_exception(php_ce_v8js_exception,
1271+
"Property name exceeds maximum supported length", 0);
1272+
return;
1273+
}
1274+
12121275
/* Write value to PHP JS object */
1213-
jsobj->ForceSet(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)), zval_to_v8js(value, isolate TSRMLS_CC), v8::ReadOnly);
1276+
v8::Local<v8::Value> key = V8JS_SYML(Z_STRVAL_P(member), static_cast<int>(Z_STRLEN_P(member)));
1277+
jsobj->ForceSet(key, zval_to_v8js(value, isolate TSRMLS_CC), v8::ReadOnly);
12141278
}
12151279

12161280
/* Write value to PHP object */
@@ -1226,8 +1290,15 @@ static void v8js_unset_property(zval *object, zval *member, void **cache_slot TS
12261290
v8::Local<v8::String> object_name_js = v8::Local<v8::String>::New(isolate, c->object_name);
12271291
v8::Local<v8::Object> jsobj = V8JS_GLOBAL(isolate)->Get(object_name_js)->ToObject();
12281292

1293+
if (Z_STRLEN_P(member) > std::numeric_limits<int>::max()) {
1294+
zend_throw_exception(php_ce_v8js_exception,
1295+
"Property name exceeds maximum supported length", 0);
1296+
return;
1297+
}
1298+
12291299
/* Delete value from PHP JS object */
1230-
jsobj->Delete(V8JS_SYML(Z_STRVAL_P(member), Z_STRLEN_P(member)));
1300+
v8::Local<v8::Value> key = V8JS_SYML(Z_STRVAL_P(member), static_cast<int>(Z_STRLEN_P(member)));
1301+
jsobj->Delete(key);
12311302

12321303
/* Unset from PHP object */
12331304
std_object_handlers.unset_property(object, member, NULL);

v8js_convert.cc

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
+----------------------------------------------------------------------+
33
| PHP Version 5 |
44
+----------------------------------------------------------------------+
5-
| Copyright (c) 1997-2016 The PHP Group |
5+
| Copyright (c) 1997-2017 The PHP Group |
66
+----------------------------------------------------------------------+
77
| http://www.opensource.org/licenses/mit-license.php MIT License |
88
+----------------------------------------------------------------------+
@@ -20,6 +20,7 @@
2020
#include <limits>
2121

2222
#include "php_v8js_macros.h"
23+
#include "v8js_exceptions.h"
2324
#include "v8js_object_export.h"
2425
#include "v8js_v8object_class.h"
2526
#include "v8js_v8.h"
@@ -30,12 +31,13 @@ extern "C" {
3031
#include "ext/standard/php_string.h"
3132
#include "zend_interfaces.h"
3233
#include "zend_closures.h"
34+
#include "zend_exceptions.h"
3335
}
3436

3537
static int v8js_is_assoc_array(HashTable *myht TSRMLS_DC) /* {{{ */
3638
{
3739
zend_string *key;
38-
ulong index, idx = 0;
40+
zend_ulong index, idx = 0;
3941

4042
ZEND_HASH_FOREACH_KEY(myht, index, key) {
4143
if(key) {
@@ -98,10 +100,20 @@ static v8::Handle<v8::Value> v8js_hash_to_jsarr(zval *value, v8::Isolate *isolat
98100
}
99101
/* }}} */
100102

101-
v8::Handle<v8::Value> zval_to_v8js(zval *value, v8::Isolate *isolate TSRMLS_DC) /* {{{ */
103+
v8::Handle<v8::Value> zend_long_to_v8js(zend_long v, v8::Isolate *isolate) /* {{{ */
104+
{
105+
if (v < - std::numeric_limits<int32_t>::min() || v > std::numeric_limits<int32_t>::max()) {
106+
return V8JS_FLOAT(static_cast<double>(v));
107+
} else {
108+
return V8JS_INT(static_cast<int32_t>(v));
109+
}
110+
}
111+
/* }}} */
112+
113+
v8::Handle<v8::Value> zval_to_v8js(zval *value, v8::Isolate *isolate) /* {{{ */
102114
{
103115
v8::Handle<v8::Value> jsValue;
104-
zend_long v;
116+
zend_string *value_str;
105117
zend_class_entry *ce;
106118

107119
switch (Z_TYPE_P(value))
@@ -133,20 +145,18 @@ v8::Handle<v8::Value> zval_to_v8js(zval *value, v8::Isolate *isolate TSRMLS_DC)
133145
break;
134146

135147
case IS_STRING:
136-
jsValue = V8JS_ZSTR(Z_STR_P(value));
148+
value_str = Z_STR_P(value);
149+
if (ZSTR_LEN(value_str) > std::numeric_limits<int>::max()) {
150+
zend_throw_exception(php_ce_v8js_exception,
151+
"String exceeds maximum string length", 0);
152+
break;
153+
}
154+
155+
jsValue = v8::String::NewFromUtf8(isolate, ZSTR_VAL(value_str), v8::String::kNormalString, static_cast<int>(ZSTR_LEN(value_str)));
137156
break;
138157

139158
case IS_LONG:
140-
v = Z_LVAL_P(value);
141-
/* On Windows there are max and min macros, which would clobber the
142-
* method names of std::numeric_limits< > otherwise. */
143-
#undef max
144-
#undef min
145-
if (v < - std::numeric_limits<int32_t>::min() || v > std::numeric_limits<int32_t>::max()) {
146-
jsValue = V8JS_FLOAT(static_cast<double>(v));
147-
} else {
148-
jsValue = V8JS_INT(static_cast<int32_t>(v));
149-
}
159+
jsValue = zend_long_to_v8js(Z_LVAL_P(value), isolate);
150160
break;
151161

152162
case IS_DOUBLE:

0 commit comments

Comments
 (0)