Skip to content

Commit 0aa03c5

Browse files
committed
Better way to deal with remain of leading numeric strings
1 parent a6edb99 commit 0aa03c5

File tree

4 files changed

+56
-51
lines changed

4 files changed

+56
-51
lines changed

Zend/zend_execute.c

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1346,11 +1346,11 @@ static zend_never_inline zend_long zend_check_string_offset(zval *dim, int type
13461346
switch(Z_TYPE_P(dim)) {
13471347
case IS_STRING:
13481348
{
1349-
/* allow errors in string offset for BC reasons */
1350-
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, true)) {
1351-
/* emit Illegal string warning on leading numerical string */
1352-
if (0 == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)
1353-
&& type != BP_VAR_UNSET) {
1349+
bool trailing_data = false;
1350+
/* For BC reasons we allow errors so that we can warn on leading numeric string */
1351+
if (IS_LONG == is_numeric_string_ex(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL,
1352+
/* allow errors */ true, NULL, &trailing_data)) {
1353+
if (UNEXPECTED(trailing_data) && type != BP_VAR_UNSET) {
13541354
zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
13551355
}
13561356
return offset;
@@ -2338,10 +2338,11 @@ static zend_always_inline void zend_fetch_dimension_address_read(zval *result, z
23382338
switch (Z_TYPE_P(dim)) {
23392339
case IS_STRING:
23402340
{
2341-
/* allow errors in string offset for BC reasons */
2342-
if (IS_LONG == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset, NULL, true)) {
2343-
/* emit Illegal string warning on leading numerical string */
2344-
if (0 == is_numeric_string(Z_STRVAL_P(dim), Z_STRLEN_P(dim), NULL, NULL, false)) {
2341+
bool trailing_data = false;
2342+
/* For BC reasons we allow errors so that we can warn on leading numeric string */
2343+
if (IS_LONG == is_numeric_string_ex(Z_STRVAL_P(dim), Z_STRLEN_P(dim), &offset,
2344+
NULL, /* allow errors */ true, NULL, &trailing_data)) {
2345+
if (UNEXPECTED(trailing_data)) {
23452346
zend_error(E_WARNING, "Illegal string offset \"%s\"", Z_STRVAL_P(dim));
23462347
}
23472348
goto out;

Zend/zend_ini_scanner.l

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,7 @@ static inline int convert_to_number(zval *retval, const char *str, const int str
158158
zend_long lval;
159159
double dval;
160160

161-
if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow)) != 0) {
161+
if ((type = is_numeric_string_ex(str, str_len, &lval, &dval, 0, &overflow, NULL)) != 0) {
162162
if (type == IS_LONG) {
163163
ZVAL_LONG(retval, lval);
164164
return SUCCESS;

Zend/zend_operators.c

Lines changed: 41 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -243,21 +243,22 @@ static zend_never_inline int ZEND_FASTCALL _zendi_try_convert_scalar_to_number(z
243243
ZVAL_LONG(holder, 1);
244244
return SUCCESS;
245245
case IS_STRING:
246-
if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op),
247-
&Z_LVAL_P(holder), &Z_DVAL_P(holder), false)) == 0) {
248-
/* Not strictly numeric
249-
* For BC reasons warn on leading numeric strings */
250-
if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op),
251-
&Z_LVAL_P(holder), &Z_DVAL_P(holder), /* allow errors */ true)) == 0) {
252-
/* Will lead to invalid OP type error */
253-
return FAILURE;
254-
}
246+
{
247+
bool trailing_data = false;
248+
/* For BC reasons we allow errors so that we can warn on leading numeric string */
249+
if (0 == (Z_TYPE_INFO_P(holder) = is_numeric_string_ex(Z_STRVAL_P(op), Z_STRLEN_P(op),
250+
&Z_LVAL_P(holder), &Z_DVAL_P(holder), /* allow errors */ true, NULL, &trailing_data))) {
251+
/* Will lead to invalid OP type error */
252+
return FAILURE;
253+
}
254+
if (UNEXPECTED(trailing_data)) {
255255
zend_error(E_WARNING, "A non-numeric value encountered");
256256
if (UNEXPECTED(EG(exception))) {
257257
return FAILURE;
258258
}
259259
}
260260
return SUCCESS;
261+
}
261262
case IS_OBJECT:
262263
if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), holder, _IS_NUMBER) == FAILURE
263264
|| EG(exception)) {
@@ -300,32 +301,29 @@ static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(zval *op, ze
300301
zend_uchar type;
301302
zend_long lval;
302303
double dval;
303-
if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, false))) {
304-
/* Not strictly numeric
305-
* For BC reasons warn on leading numeric strings */
306-
if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval,
307-
/* allow errors */ true))) {
308-
/* Will lead to invalid OP type error */
309-
*failed = 1;
310-
return 0;
311-
}
312-
zend_error(E_WARNING, "A non-numeric value encountered");
313-
if (UNEXPECTED(EG(exception))) {
314-
*failed = 1;
315-
}
316-
if (type == IS_LONG) {
317-
return lval;
318-
} else {
319-
/* Previously we used strtol here, not is_numeric_string,
320-
* and strtol gives you LONG_MAX/_MIN on overflow.
321-
* We use use saturating conversion to emulate strtol()'s
322-
* behaviour.
323-
*/
324-
return zend_dval_to_lval_cap(dval);
325-
}
304+
bool trailing_data = false;
305+
306+
/* For BC reasons we allow errors so that we can warn on leading numeric string */
307+
type = is_numeric_string_ex(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval,
308+
/* allow errors */ true, NULL, &trailing_data);
309+
if (type == 0) {
310+
*failed = 1;
311+
return 0;
326312
} else if (EXPECTED(type == IS_LONG)) {
313+
if (UNEXPECTED(trailing_data)) {
314+
zend_error(E_WARNING, "A non-numeric value encountered");
315+
if (UNEXPECTED(EG(exception))) {
316+
*failed = 1;
317+
}
318+
}
327319
return lval;
328320
} else {
321+
if (trailing_data) {
322+
zend_error(E_WARNING, "A non-numeric value encountered");
323+
if (UNEXPECTED(EG(exception))) {
324+
*failed = 1;
325+
}
326+
}
329327
/* Previously we used strtol here, not is_numeric_string,
330328
* and strtol gives you LONG_MAX/_MIN on overflow.
331329
* We use use saturating conversion to emulate strtol()'s
@@ -2831,8 +2829,8 @@ ZEND_API int ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2) /
28312829
zend_long lval1 = 0, lval2 = 0;
28322830
double dval1 = 0.0, dval2 = 0.0;
28332831

2834-
if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1)) &&
2835-
(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2))) {
2832+
if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
2833+
(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
28362834
#if ZEND_ULONG_MAX == 0xFFFFFFFF
28372835
if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
28382836
((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
@@ -2879,8 +2877,8 @@ ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2)
28792877
zend_long lval1 = 0, lval2 = 0;
28802878
double dval1 = 0.0, dval2 = 0.0;
28812879

2882-
if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1)) &&
2883-
(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2))) {
2880+
if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
2881+
(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
28842882
#if ZEND_ULONG_MAX == 0xFFFFFFFF
28852883
if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
28862884
((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
@@ -2982,7 +2980,7 @@ ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str
29822980
/* }}} */
29832981

29842982
ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval,
2985-
double *dval, bool allow_errors, int *oflow_info) /* {{{ */
2983+
double *dval, bool allow_errors, int *oflow_info, bool *trailing_data) /* {{{ */
29862984
{
29872985
const char *ptr;
29882986
int digits = 0, dp_or_e = 0;
@@ -2998,6 +2996,9 @@ ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t
29982996
if (oflow_info != NULL) {
29992997
*oflow_info = 0;
30002998
}
2999+
if (trailing_data != NULL) {
3000+
*trailing_data = false;
3001+
}
30013002

30023003
/* Skip any whitespace
30033004
* This is much faster than the isspace() function */
@@ -3077,6 +3078,9 @@ ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t
30773078
if (!allow_errors) {
30783079
return 0;
30793080
}
3081+
if (trailing_data != NULL) {
3082+
*trailing_data = true;
3083+
}
30803084
}
30813085
}
30823086

Zend/zend_operators.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ static zend_always_inline zend_bool instanceof_function(
8787
* if the integer is larger than ZEND_LONG_MAX and -1 if it's smaller than ZEND_LONG_MIN.
8888
*/
8989
ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval,
90-
double *dval, bool allow_errors, int *oflow_info);
90+
double *dval, bool allow_errors, int *oflow_info, bool *trailing_data);
9191

9292
ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end);
9393
ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end);
@@ -137,16 +137,16 @@ static zend_always_inline zend_long zend_dval_to_lval_cap(double d)
137137
#define ZEND_IS_XDIGIT(c) (((c) >= 'A' && (c) <= 'F') || ((c) >= 'a' && (c) <= 'f'))
138138

139139
static zend_always_inline zend_uchar is_numeric_string_ex(const char *str, size_t length, zend_long *lval,
140-
double *dval, bool allow_errors, int *oflow_info)
140+
double *dval, bool allow_errors, int *oflow_info, bool *trailing_data)
141141
{
142142
if (*str > '9') {
143143
return 0;
144144
}
145-
return _is_numeric_string_ex(str, length, lval, dval, allow_errors, oflow_info);
145+
return _is_numeric_string_ex(str, length, lval, dval, allow_errors, oflow_info, trailing_data);
146146
}
147147

148148
static zend_always_inline zend_uchar is_numeric_string(const char *str, size_t length, zend_long *lval, double *dval, bool allow_errors) {
149-
return is_numeric_string_ex(str, length, lval, dval, allow_errors, NULL);
149+
return is_numeric_string_ex(str, length, lval, dval, allow_errors, NULL, NULL);
150150
}
151151

152152
ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval);

0 commit comments

Comments
 (0)