php-src/Zend/zend_operators.c

3288 lines
82 KiB
C
Raw Normal View History

1999-04-08 02:10:10 +08:00
/*
+----------------------------------------------------------------------+
| Zend Engine |
+----------------------------------------------------------------------+
2019-01-30 17:23:29 +08:00
| Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
2001-12-11 23:16:21 +08:00
| This source file is subject to version 2.00 of the Zend license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
2001-12-11 23:16:21 +08:00
| http://www.zend.com/license/2_00.txt. |
1999-07-16 22:58:16 +08:00
| If you did not receive a copy of the Zend license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@zend.com so we can mail you a copy immediately. |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
| Authors: Andi Gutmans <andi@php.net> |
| Zeev Suraski <zeev@php.net> |
| Dmitry Stogov <dmitry@php.net> |
1999-04-08 02:10:10 +08:00
+----------------------------------------------------------------------+
*/
#include <ctype.h>
1999-04-08 02:10:10 +08:00
#include "zend.h"
#include "zend_operators.h"
#include "zend_variables.h"
#include "zend_globals.h"
#include "zend_list.h"
2001-07-11 19:35:11 +08:00
#include "zend_API.h"
#include "zend_strtod.h"
#include "zend_exceptions.h"
#include "zend_closures.h"
1999-04-08 02:10:10 +08:00
#if ZEND_USE_TOLOWER_L
#include <locale.h>
static _locale_t current_locale = NULL;
2009-05-11 07:08:52 +08:00
/* this is true global! may lead to strange effects on ZTS, but so may setlocale() */
#define zend_tolower(c) _tolower_l(c, current_locale)
#else
#define zend_tolower(c) tolower(c)
#endif
#define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
2012-07-15 12:06:40 +08:00
static const unsigned char tolower_map[256] = {
0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
};
2012-07-15 12:06:40 +08:00
#define zend_tolower_ascii(c) (tolower_map[(unsigned char)(c)])
/**
* Functions using locale lowercase:
zend_binary_strncasecmp_l
zend_binary_strcasecmp_l
zend_binary_zval_strcasecmp
zend_binary_zval_strncasecmp
string_compare_function_ex
string_case_compare_function
* Functions using ascii lowercase:
zend_str_tolower_copy
zend_str_tolower_dup
zend_str_tolower
zend_binary_strcasecmp
zend_binary_strncasecmp
*/
ZEND_API int ZEND_FASTCALL zend_atoi(const char *str, size_t str_len) /* {{{ */
{
int retval;
if (!str_len) {
str_len = strlen(str);
}
2014-08-26 02:22:49 +08:00
retval = ZEND_STRTOL(str, NULL, 0);
if (str_len>0) {
switch (str[str_len-1]) {
case 'g':
case 'G':
retval *= 1024;
/* break intentionally missing */
case 'm':
case 'M':
retval *= 1024;
/* break intentionally missing */
case 'k':
case 'K':
retval *= 1024;
break;
}
}
return retval;
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len) /* {{{ */
2008-03-19 20:41:23 +08:00
{
2014-08-26 01:24:55 +08:00
zend_long retval;
2008-03-19 20:41:23 +08:00
if (!str_len) {
str_len = strlen(str);
2008-03-19 20:41:23 +08:00
}
2014-08-26 02:22:49 +08:00
retval = ZEND_STRTOL(str, NULL, 0);
2008-03-19 20:41:23 +08:00
if (str_len>0) {
switch (str[str_len-1]) {
case 'g':
case 'G':
retval *= 1024;
/* break intentionally missing */
case 'm':
case 'M':
retval *= 1024;
/* break intentionally missing */
case 'k':
case 'K':
retval *= 1024;
break;
}
}
return retval;
}
2009-05-11 07:08:52 +08:00
/* }}} */
2008-03-19 20:41:23 +08:00
/* {{{ convert_object_to_type: dst will be either ctype or UNDEF */
#define convert_object_to_type(op, dst, ctype, conv_func) \
ZVAL_UNDEF(dst); \
if (Z_OBJ_HT_P(op)->cast_object) { \
if (Z_OBJ_HT_P(op)->cast_object(op, dst, ctype) == FAILURE) { \
zend_error(E_RECOVERABLE_ERROR, \
"Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
zend_get_type_by_const(ctype)); \
} \
} else if (Z_OBJ_HT_P(op)->get) { \
zval *newop = Z_OBJ_HT_P(op)->get(op, dst); \
if (Z_TYPE_P(newop) != IS_OBJECT) { \
/* for safety - avoid loop */ \
ZVAL_COPY_VALUE(dst, newop); \
conv_func(dst); \
} \
}
/* }}} */
static void ZEND_FASTCALL _convert_scalar_to_number(zval *op, zend_bool silent, zend_bool check) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-03-14 02:07:14 +08:00
try_again:
switch (Z_TYPE_P(op)) {
2014-03-14 02:07:14 +08:00
case IS_REFERENCE:
zend_unwrap_reference(op);
2014-03-14 02:07:14 +08:00
goto try_again;
2001-04-29 02:20:46 +08:00
case IS_STRING:
{
zend_string *str;
2001-04-29 02:20:46 +08:00
str = Z_STR_P(op);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
if ((Z_TYPE_INFO_P(op)=is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &Z_LVAL_P(op), &Z_DVAL_P(op), silent ? 1 : -1)) == 0) {
ZVAL_LONG(op, 0);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
if (!silent) {
zend_error(E_WARNING, "A non-numeric value encountered");
}
2001-04-29 02:20:46 +08:00
}
zend_string_release_ex(str, 0);
1999-04-08 02:10:10 +08:00
break;
2001-04-29 02:20:46 +08:00
}
case IS_NULL:
case IS_FALSE:
ZVAL_LONG(op, 0);
break;
case IS_TRUE:
ZVAL_LONG(op, 1);
2001-04-29 02:20:46 +08:00
break;
case IS_RESOURCE:
{
2014-08-26 01:24:55 +08:00
zend_long l = Z_RES_HANDLE_P(op);
zval_ptr_dtor(op);
ZVAL_LONG(op, l);
}
2001-04-29 02:20:46 +08:00
break;
case IS_OBJECT:
{
zval dst;
convert_object_to_type(op, &dst, _IS_NUMBER, convert_scalar_to_number);
if (check && UNEXPECTED(EG(exception))) {
return;
}
zval_ptr_dtor(op);
if (Z_TYPE(dst) == IS_LONG || Z_TYPE(dst) == IS_DOUBLE) {
ZVAL_COPY_VALUE(op, &dst);
} else {
ZVAL_LONG(op, 1);
}
}
break;
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */
{
_convert_scalar_to_number(op, 1, 0);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
}
/* }}} */
/* {{{ _zendi_convert_scalar_to_number_ex */
static zend_always_inline zval* _zendi_convert_scalar_to_number_ex(zval *op, zval *holder, zend_bool silent) /* {{{ */
{
switch (Z_TYPE_P(op)) {
case IS_NULL:
case IS_FALSE:
ZVAL_LONG(holder, 0);
return holder;
case IS_TRUE:
ZVAL_LONG(holder, 1);
return holder;
case IS_STRING:
if ((Z_TYPE_INFO_P(holder) = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &Z_LVAL_P(holder), &Z_DVAL_P(holder), silent ? 1 : -1)) == 0) {
ZVAL_LONG(holder, 0);
if (!silent) {
zend_error(E_WARNING, "A non-numeric value encountered");
}
}
return holder;
case IS_RESOURCE:
ZVAL_LONG(holder, Z_RES_HANDLE_P(op));
return holder;
case IS_OBJECT:
convert_object_to_type(op, holder, _IS_NUMBER, convert_scalar_to_number);
if (UNEXPECTED(EG(exception)) ||
UNEXPECTED(Z_TYPE_P(holder) != IS_LONG && Z_TYPE_P(holder) != IS_DOUBLE)) {
ZVAL_LONG(holder, 1);
}
return holder;
case IS_LONG:
case IS_DOUBLE:
default:
return op;
1999-04-08 02:10:10 +08:00
}
}
/* }}} */
1999-04-08 02:10:10 +08:00
/* {{{ _zendi_convert_scalar_to_number */
static zend_never_inline zval* ZEND_FASTCALL _zendi_convert_scalar_to_number(zval *op, zval *holder) /* {{{ */
{
return _zendi_convert_scalar_to_number_ex(op, holder, 1);
}
/* }}} */
/* {{{ _zendi_convert_scalar_to_number_noisy */
static zend_never_inline zval* ZEND_FASTCALL _zendi_convert_scalar_to_number_noisy(zval *op, zval *holder) /* {{{ */
{
return _zendi_convert_scalar_to_number_ex(op, holder, 0);
}
2009-05-11 07:08:52 +08:00
/* }}} */
2007-12-25 02:09:50 +08:00
#define zendi_convert_scalar_to_number(op, holder, result, silent) \
((Z_TYPE_P(op) == IS_LONG || Z_TYPE_P(op) == IS_DOUBLE) ? (op) : \
(((op) == result) ? (_convert_scalar_to_number((op), silent, 1), (op)) : \
(silent ? _zendi_convert_scalar_to_number((op), holder) : \
_zendi_convert_scalar_to_number_noisy((op), holder))))
#define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, op, op_func) \
2014-12-23 09:51:19 +08:00
do { \
if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) { \
if (Z_ISREF_P(op1)) { \
op1 = Z_REFVAL_P(op1); \
if (Z_TYPE_P(op1) == IS_LONG) { \
op1_lval = Z_LVAL_P(op1); \
break; \
} \
} \
ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(op, op_func); \
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
op1_lval = _zval_get_long_func_noisy(op1); \
if (UNEXPECTED(EG(exception))) { \
if (result != op1) { \
ZVAL_UNDEF(result); \
} \
return FAILURE; \
} \
2014-12-23 09:51:19 +08:00
} else { \
op1_lval = Z_LVAL_P(op1); \
} \
} while (0); \
do { \
if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) { \
if (Z_ISREF_P(op2)) { \
op2 = Z_REFVAL_P(op2); \
if (Z_TYPE_P(op2) == IS_LONG) { \
op2_lval = Z_LVAL_P(op2); \
break; \
} \
} \
ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(op); \
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
op2_lval = _zval_get_long_func_noisy(op2); \
if (UNEXPECTED(EG(exception))) { \
if (result != op1) { \
ZVAL_UNDEF(result); \
} \
return FAILURE; \
} \
2014-12-23 09:51:19 +08:00
} else { \
op2_lval = Z_LVAL_P(op2); \
} \
} while (0);
2014-12-23 09:51:19 +08:00
ZEND_API void ZEND_FASTCALL convert_to_long(zval *op) /* {{{ */
1999-04-08 02:10:10 +08:00
{
if (Z_TYPE_P(op) != IS_LONG) {
convert_to_long_base(op, 10);
}
1999-04-08 02:10:10 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API void ZEND_FASTCALL convert_to_long_base(zval *op, int base) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-08-26 01:24:55 +08:00
zend_long tmp;
1999-04-08 02:10:10 +08:00
try_again:
switch (Z_TYPE_P(op)) {
2000-01-04 21:22:58 +08:00
case IS_NULL:
case IS_FALSE:
ZVAL_LONG(op, 0);
break;
case IS_TRUE:
ZVAL_LONG(op, 1);
break;
case IS_RESOURCE:
tmp = Z_RES_HANDLE_P(op);
zval_ptr_dtor(op);
ZVAL_LONG(op, tmp);
break;
1999-04-08 02:10:10 +08:00
case IS_LONG:
break;
1999-04-08 02:10:10 +08:00
case IS_DOUBLE:
ZVAL_LONG(op, zend_dval_to_lval(Z_DVAL_P(op)));
1999-04-08 02:10:10 +08:00
break;
case IS_STRING:
2009-05-11 15:52:49 +08:00
{
zend_string *str = Z_STR_P(op);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
if (base == 10) {
ZVAL_LONG(op, zval_get_long(op));
} else {
ZVAL_LONG(op, ZEND_STRTOL(ZSTR_VAL(str), NULL, base));
}
zend_string_release_ex(str, 0);
2009-05-11 15:52:49 +08:00
}
1999-04-08 02:10:10 +08:00
break;
case IS_ARRAY:
tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
zval_ptr_dtor(op);
ZVAL_LONG(op, tmp);
1999-04-08 02:10:10 +08:00
break;
case IS_OBJECT:
{
zval dst;
2015-01-03 17:22:58 +08:00
convert_object_to_type(op, &dst, IS_LONG, convert_to_long);
zval_ptr_dtor(op);
if (Z_TYPE(dst) == IS_LONG) {
2018-07-06 06:26:43 +08:00
ZVAL_LONG(op, Z_LVAL(dst));
} else {
ZVAL_LONG(op, 1);
}
return;
}
case IS_REFERENCE:
zend_unwrap_reference(op);
goto try_again;
EMPTY_SWITCH_DEFAULT_CASE()
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API void ZEND_FASTCALL convert_to_double(zval *op) /* {{{ */
1999-04-08 02:10:10 +08:00
{
double tmp;
try_again:
switch (Z_TYPE_P(op)) {
2000-01-04 21:22:58 +08:00
case IS_NULL:
case IS_FALSE:
ZVAL_DOUBLE(op, 0.0);
break;
case IS_TRUE:
ZVAL_DOUBLE(op, 1.0);
break;
2001-07-30 12:54:16 +08:00
case IS_RESOURCE: {
double d = (double) Z_RES_HANDLE_P(op);
zval_ptr_dtor(op);
ZVAL_DOUBLE(op, d);
2001-07-30 12:54:16 +08:00
}
break;
1999-04-08 02:10:10 +08:00
case IS_LONG:
ZVAL_DOUBLE(op, (double) Z_LVAL_P(op));
1999-04-08 02:10:10 +08:00
break;
case IS_DOUBLE:
break;
case IS_STRING:
2009-05-11 15:52:49 +08:00
{
zend_string *str = Z_STR_P(op);
1999-04-08 02:10:10 +08:00
ZVAL_DOUBLE(op, zend_strtod(ZSTR_VAL(str), NULL));
zend_string_release_ex(str, 0);
2009-05-11 15:52:49 +08:00
}
1999-04-08 02:10:10 +08:00
break;
case IS_ARRAY:
tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
zval_ptr_dtor(op);
ZVAL_DOUBLE(op, tmp);
1999-04-08 02:10:10 +08:00
break;
case IS_OBJECT:
{
zval dst;
2015-01-03 17:22:58 +08:00
convert_object_to_type(op, &dst, IS_DOUBLE, convert_to_double);
zval_ptr_dtor(op);
if (Z_TYPE(dst) == IS_DOUBLE) {
2018-07-06 06:26:43 +08:00
ZVAL_DOUBLE(op, Z_DVAL(dst));
} else {
ZVAL_DOUBLE(op, 1.0);
}
break;
}
case IS_REFERENCE:
zend_unwrap_reference(op);
goto try_again;
EMPTY_SWITCH_DEFAULT_CASE()
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API void ZEND_FASTCALL convert_to_null(zval *op) /* {{{ */
{
zval_ptr_dtor(op);
ZVAL_NULL(op);
1999-04-08 02:10:10 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op) /* {{{ */
1999-04-08 02:10:10 +08:00
{
int tmp;
try_again:
switch (Z_TYPE_P(op)) {
case IS_FALSE:
case IS_TRUE:
1999-04-08 02:10:10 +08:00
break;
2000-01-04 21:22:58 +08:00
case IS_NULL:
ZVAL_FALSE(op);
break;
2001-07-30 12:54:16 +08:00
case IS_RESOURCE: {
2014-08-26 01:24:55 +08:00
zend_long l = (Z_RES_HANDLE_P(op) ? 1 : 0);
2001-07-30 12:54:16 +08:00
zval_ptr_dtor(op);
ZVAL_BOOL(op, l);
2001-07-30 12:54:16 +08:00
}
break;
case IS_LONG:
ZVAL_BOOL(op, Z_LVAL_P(op) ? 1 : 0);
1999-04-08 02:10:10 +08:00
break;
case IS_DOUBLE:
ZVAL_BOOL(op, Z_DVAL_P(op) ? 1 : 0);
1999-04-08 02:10:10 +08:00
break;
case IS_STRING:
2009-05-11 15:52:49 +08:00
{
zend_string *str = Z_STR_P(op);
1999-04-08 02:10:10 +08:00
if (ZSTR_LEN(str) == 0
|| (ZSTR_LEN(str) == 1 && ZSTR_VAL(str)[0] == '0')) {
ZVAL_FALSE(op);
2009-05-11 15:52:49 +08:00
} else {
ZVAL_TRUE(op);
2009-05-11 15:52:49 +08:00
}
zend_string_release_ex(str, 0);
1999-04-08 02:10:10 +08:00
}
break;
case IS_ARRAY:
tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
zval_ptr_dtor(op);
ZVAL_BOOL(op, tmp);
1999-04-08 02:10:10 +08:00
break;
case IS_OBJECT:
{
zval dst;
2015-01-03 17:22:58 +08:00
convert_object_to_type(op, &dst, _IS_BOOL, convert_to_boolean);
zval_ptr_dtor(op);
2018-07-06 06:26:43 +08:00
if (Z_TYPE_INFO(dst) == IS_FALSE || Z_TYPE_INFO(dst) == IS_TRUE) {
Z_TYPE_INFO_P(op) = Z_TYPE_INFO(dst);
} else {
ZVAL_TRUE(op);
}
break;
}
case IS_REFERENCE:
zend_unwrap_reference(op);
goto try_again;
EMPTY_SWITCH_DEFAULT_CASE()
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API void ZEND_FASTCALL _convert_to_cstring(zval *op) /* {{{ */
{
if (Z_TYPE_P(op) == IS_DOUBLE) {
zend_string *str;
double dval = Z_DVAL_P(op);
str = zend_strpprintf_unchecked(0, "%.*H", (int) EG(precision), dval);
ZVAL_NEW_STR(op, str);
} else {
_convert_to_string(op);
}
}
/* }}} */
ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op) /* {{{ */
1999-04-08 02:10:10 +08:00
{
try_again:
switch (Z_TYPE_P(op)) {
case IS_UNDEF:
case IS_NULL:
case IS_FALSE: {
ZVAL_EMPTY_STRING(op);
break;
}
case IS_TRUE:
ZVAL_INTERNED_STR(op, ZSTR_CHAR('1'));
1999-04-08 02:10:10 +08:00
break;
case IS_STRING:
1999-04-08 02:10:10 +08:00
break;
case IS_RESOURCE: {
2018-03-07 02:58:40 +08:00
zend_string *str = zend_strpprintf(0, "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
zval_ptr_dtor(op);
2018-03-07 02:58:40 +08:00
ZVAL_NEW_STR(op, str);
break;
}
case IS_LONG: {
ZVAL_STR(op, zend_long_to_str(Z_LVAL_P(op)));
1999-04-08 02:10:10 +08:00
break;
}
1999-04-08 02:10:10 +08:00
case IS_DOUBLE: {
zend_string *str;
double dval = Z_DVAL_P(op);
2015-01-03 17:22:58 +08:00
str = zend_strpprintf(0, "%.*G", (int) EG(precision), dval);
1999-04-08 02:10:10 +08:00
/* %G already handles removing trailing zeros from the fractional part, yay */
ZVAL_NEW_STR(op, str);
1999-04-08 02:10:10 +08:00
break;
}
case IS_ARRAY:
zend_error(E_NOTICE, "Array to string conversion");
zval_ptr_dtor(op);
ZVAL_INTERNED_STR(op, ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED));
1999-04-08 02:10:10 +08:00
break;
case IS_OBJECT: {
zval tmp;
if (Z_OBJ_HT_P(op)->cast_object) {
if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) {
zval_ptr_dtor(op);
ZVAL_COPY_VALUE(op, &tmp);
return;
}
} else if (Z_OBJ_HT_P(op)->get) {
zval *z = Z_OBJ_HT_P(op)->get(op, &tmp);
if (Z_TYPE_P(z) != IS_OBJECT) {
zend_string *str = zval_get_string(z);
zval_ptr_dtor(z);
zval_ptr_dtor(op);
ZVAL_STR(op, str);
return;
}
zval_ptr_dtor(z);
}
if (!EG(exception)) {
zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
}
zval_ptr_dtor(op);
ZVAL_EMPTY_STRING(op);
1999-04-08 02:10:10 +08:00
break;
}
case IS_REFERENCE:
zend_unwrap_reference(op);
goto try_again;
EMPTY_SWITCH_DEFAULT_CASE()
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API zend_bool ZEND_FASTCALL _try_convert_to_string(zval *op)
{
zend_string *str;
ZEND_ASSERT(Z_TYPE_P(op) != IS_STRING);
str = zval_try_get_string_func(op);
if (UNEXPECTED(!str)) {
return 0;
}
zval_ptr_dtor(op);
ZVAL_STR(op, str);
return 1;
}
2014-12-14 06:06:14 +08:00
static void convert_scalar_to_array(zval *op) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2018-07-06 06:26:43 +08:00
HashTable *ht = zend_new_array(1);
zend_hash_index_add_new(ht, 0, op);
ZVAL_ARR(op, ht);
1999-04-08 02:10:10 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
1999-04-08 02:10:10 +08:00
{
try_again:
switch (Z_TYPE_P(op)) {
1999-04-08 02:10:10 +08:00
case IS_ARRAY:
break;
/* OBJECTS_OPTIMIZE */
1999-04-08 02:10:10 +08:00
case IS_OBJECT:
if (Z_OBJCE_P(op) == zend_ce_closure) {
2014-12-14 06:06:14 +08:00
convert_scalar_to_array(op);
} else {
HashTable *obj_ht = zend_get_properties_for(op, ZEND_PROP_PURPOSE_ARRAY_CAST);
if (obj_ht) {
HashTable *new_obj_ht = zend_proptable_to_symtable(obj_ht,
(Z_OBJCE_P(op)->default_properties_count ||
Z_OBJ_P(op)->handlers != &std_object_handlers ||
GC_IS_RECURSIVE(obj_ht)));
zval_ptr_dtor(op);
ZVAL_ARR(op, new_obj_ht);
zend_release_properties(obj_ht);
} else {
zval_ptr_dtor(op);
/*ZVAL_EMPTY_ARRAY(op);*/
array_init(op);
}
}
2009-05-11 15:52:49 +08:00
break;
case IS_NULL:
/*ZVAL_EMPTY_ARRAY(op);*/
array_init(op);
1999-04-08 02:10:10 +08:00
break;
case IS_REFERENCE:
zend_unwrap_reference(op);
goto try_again;
1999-04-08 02:10:10 +08:00
default:
2014-12-14 06:06:14 +08:00
convert_scalar_to_array(op);
1999-04-08 02:10:10 +08:00
break;
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
1999-04-08 02:10:10 +08:00
{
try_again:
switch (Z_TYPE_P(op)) {
1999-04-08 02:10:10 +08:00
case IS_ARRAY:
{
2018-07-06 06:26:43 +08:00
HashTable *ht = zend_symtable_to_proptable(Z_ARR_P(op));
zend_object *obj;
if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) {
2015-08-26 03:40:33 +08:00
/* TODO: try not to duplicate immutable arrays as well ??? */
ht = zend_array_dup(ht);
2018-07-06 06:26:43 +08:00
} else if (ht != Z_ARR_P(op)) {
zval_ptr_dtor(op);
2018-07-06 06:26:43 +08:00
} else {
GC_DELREF(ht);
2015-08-26 03:40:33 +08:00
}
2018-07-06 06:26:43 +08:00
obj = zend_objects_new(zend_standard_class_def);
obj->properties = ht;
ZVAL_OBJ(op, obj);
break;
}
1999-04-08 02:10:10 +08:00
case IS_OBJECT:
2009-05-11 15:52:49 +08:00
break;
case IS_NULL:
object_init(op);
break;
case IS_REFERENCE:
zend_unwrap_reference(op);
goto try_again;
default: {
zval tmp;
ZVAL_COPY_VALUE(&tmp, op);
object_init(op);
zend_hash_add_new(Z_OBJPROP_P(op), ZSTR_KNOWN(ZEND_STR_SCALAR), &tmp);
1999-04-08 02:10:10 +08:00
break;
}
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2009-05-11 07:08:52 +08:00
ZEND_API void multi_convert_to_long_ex(int argc, ...) /* {{{ */
{
zval *arg;
va_list ap;
va_start(ap, argc);
while (argc--) {
arg = va_arg(ap, zval *);
convert_to_long_ex(arg);
}
va_end(ap);
}
2009-05-11 07:08:52 +08:00
/* }}} */
2009-05-11 07:08:52 +08:00
ZEND_API void multi_convert_to_double_ex(int argc, ...) /* {{{ */
{
zval *arg;
va_list ap;
va_start(ap, argc);
while (argc--) {
arg = va_arg(ap, zval *);
convert_to_double_ex(arg);
}
va_end(ap);
}
2009-05-11 07:08:52 +08:00
/* }}} */
2009-05-11 07:08:52 +08:00
ZEND_API void multi_convert_to_string_ex(int argc, ...) /* {{{ */
{
zval *arg;
va_list ap;
va_start(ap, argc);
while (argc--) {
arg = va_arg(ap, zval *);
convert_to_string_ex(arg);
}
va_end(ap);
}
2009-05-11 07:08:52 +08:00
/* }}} */
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
static zend_always_inline zend_long ZEND_FASTCALL _zval_get_long_func_ex(zval *op, zend_bool silent) /* {{{ */
{
try_again:
switch (Z_TYPE_P(op)) {
case IS_UNDEF:
case IS_NULL:
case IS_FALSE:
return 0;
case IS_TRUE:
return 1;
case IS_RESOURCE:
return Z_RES_HANDLE_P(op);
case IS_LONG:
return Z_LVAL_P(op);
case IS_DOUBLE:
return zend_dval_to_lval(Z_DVAL_P(op));
case IS_STRING:
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
{
zend_uchar type;
zend_long lval;
double dval;
if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, silent ? 1 : -1))) {
if (!silent) {
zend_error(E_WARNING, "A non-numeric value encountered");
}
return 0;
} else if (EXPECTED(type == IS_LONG)) {
return lval;
} else {
/* Previously we used strtol here, not is_numeric_string,
* and strtol gives you LONG_MAX/_MIN on overflow.
* We use use saturating conversion to emulate strtol()'s
* behaviour.
*/
return zend_dval_to_lval_cap(dval);
}
}
case IS_ARRAY:
return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
case IS_OBJECT:
{
zval dst;
convert_object_to_type(op, &dst, IS_LONG, convert_to_long);
if (Z_TYPE(dst) == IS_LONG) {
return Z_LVAL(dst);
} else {
return 1;
}
}
case IS_REFERENCE:
op = Z_REFVAL_P(op);
goto try_again;
EMPTY_SWITCH_DEFAULT_CASE()
}
2014-08-15 03:53:27 +08:00
return 0;
}
/* }}} */
2017-11-16 22:09:01 +08:00
ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op) /* {{{ */
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
{
return _zval_get_long_func_ex(op, 1);
}
/* }}} */
static zend_long ZEND_FASTCALL _zval_get_long_func_noisy(zval *op) /* {{{ */
{
return _zval_get_long_func_ex(op, 0);
}
/* }}} */
2017-11-16 22:09:01 +08:00
ZEND_API double ZEND_FASTCALL zval_get_double_func(zval *op) /* {{{ */
{
try_again:
switch (Z_TYPE_P(op)) {
case IS_NULL:
case IS_FALSE:
return 0.0;
case IS_TRUE:
return 1.0;
case IS_RESOURCE:
return (double) Z_RES_HANDLE_P(op);
case IS_LONG:
return (double) Z_LVAL_P(op);
case IS_DOUBLE:
return Z_DVAL_P(op);
case IS_STRING:
return zend_strtod(Z_STRVAL_P(op), NULL);
case IS_ARRAY:
return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1.0 : 0.0;
case IS_OBJECT:
{
zval dst;
convert_object_to_type(op, &dst, IS_DOUBLE, convert_to_double);
if (Z_TYPE(dst) == IS_DOUBLE) {
return Z_DVAL(dst);
} else {
return 1.0;
}
}
case IS_REFERENCE:
op = Z_REFVAL_P(op);
goto try_again;
EMPTY_SWITCH_DEFAULT_CASE()
}
2014-08-15 03:53:27 +08:00
return 0.0;
}
/* }}} */
static zend_always_inline zend_string* __zval_get_string_func(zval *op, zend_bool try) /* {{{ */
{
try_again:
switch (Z_TYPE_P(op)) {
case IS_UNDEF:
case IS_NULL:
case IS_FALSE:
return ZSTR_EMPTY_ALLOC();
case IS_TRUE:
return ZSTR_CHAR('1');
case IS_RESOURCE: {
2018-03-07 02:58:40 +08:00
return zend_strpprintf(0, "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
}
case IS_LONG: {
return zend_long_to_str(Z_LVAL_P(op));
}
case IS_DOUBLE: {
return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op));
}
case IS_ARRAY:
zend_error(E_NOTICE, "Array to string conversion");
return (try && UNEXPECTED(EG(exception))) ?
NULL : ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
case IS_OBJECT: {
zval tmp;
if (Z_OBJ_HT_P(op)->cast_object) {
2014-12-14 06:06:14 +08:00
if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) {
return Z_STR(tmp);
}
} else if (Z_OBJ_HT_P(op)->get) {
2014-12-14 06:06:14 +08:00
zval *z = Z_OBJ_HT_P(op)->get(op, &tmp);
if (Z_TYPE_P(z) != IS_OBJECT) {
zend_string *str = try ? zval_try_get_string(z) : zval_get_string(z);
zval_ptr_dtor(z);
return str;
}
zval_ptr_dtor(z);
}
if (!EG(exception)) {
zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
}
return try ? NULL : ZSTR_EMPTY_ALLOC();
}
case IS_REFERENCE:
op = Z_REFVAL_P(op);
goto try_again;
2014-09-23 13:50:00 +08:00
case IS_STRING:
return zend_string_copy(Z_STR_P(op));
EMPTY_SWITCH_DEFAULT_CASE()
}
2014-08-15 03:53:27 +08:00
return NULL;
}
/* }}} */
ZEND_API zend_string* ZEND_FASTCALL zval_get_string_func(zval *op) /* {{{ */
{
return __zval_get_string_func(op, 0);
}
/* }}} */
ZEND_API zend_string* ZEND_FASTCALL zval_try_get_string_func(zval *op) /* {{{ */
{
return __zval_get_string_func(op, 1);
}
/* }}} */
static zend_never_inline void ZEND_FASTCALL add_function_array(zval *result, zval *op1, zval *op2) /* {{{ */
{
if ((result == op1) && (result == op2)) {
/* $a += $a */
return;
}
if (result != op1) {
ZVAL_ARR(result, zend_array_dup(Z_ARR_P(op1)));
} else {
SEPARATE_ARRAY(result);
}
zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
}
/* }}} */
static zend_always_inline int add_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
{
zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
fast_long_add_function(result, op1, op2);
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_ARRAY, IS_ARRAY))) {
add_function_array(result, op1, op2);
return SUCCESS;
} else {
return FAILURE;
}
} /* }}} */
static zend_never_inline int ZEND_FASTCALL add_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zval op1_copy, op2_copy;
int converted = 0;
1999-04-08 02:10:10 +08:00
while (1) {
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
} else if (Z_ISREF_P(op2)) {
op2 = Z_REFVAL_P(op2);
} else if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function);
if (EXPECTED(op1 != op2)) {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
} else {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
op2 = op1;
}
if (EG(exception)) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
converted = 1;
} else {
if (result != op1) {
ZVAL_UNDEF(result);
}
zend_throw_error(NULL, "Unsupported operand types");
return FAILURE; /* unknown datatype */
}
if (add_function_fast(result, op1, op2) == SUCCESS) {
return SUCCESS;
1999-04-08 02:10:10 +08:00
}
}
} /* }}} */
ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
if (add_function_fast(result, op1, op2) == SUCCESS) {
return SUCCESS;
} else {
return add_function_slow(result, op1, op2);
}
1999-04-08 02:10:10 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
static zend_always_inline int sub_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
{
zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
fast_long_sub_function(result, op1, op2);
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
return SUCCESS;
} else {
return FAILURE;
}
}
/* }}} */
static zend_never_inline int ZEND_FASTCALL sub_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zval op1_copy, op2_copy;
int converted = 0;
while (1) {
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
} else if (Z_ISREF_P(op2)) {
op2 = Z_REFVAL_P(op2);
} else if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB, sub_function);
if (EXPECTED(op1 != op2)) {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
} else {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
op2 = op1;
}
if (EG(exception)) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
converted = 1;
} else {
if (result != op1) {
ZVAL_UNDEF(result);
}
zend_throw_error(NULL, "Unsupported operand types");
return FAILURE; /* unknown datatype */
1999-04-08 02:10:10 +08:00
}
if (sub_function_fast(result, op1, op2) == SUCCESS) {
return SUCCESS;
}
}
}
/* }}} */
ZEND_API int ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
if (sub_function_fast(result, op1, op2) == SUCCESS) {
return SUCCESS;
} else {
return sub_function_slow(result, op1, op2);
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zval op1_copy, op2_copy;
int converted = 0;
1999-04-08 02:10:10 +08:00
while (1) {
zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
zend_long overflow;
ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
return SUCCESS;
} else {
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
} else if (Z_ISREF_P(op2)) {
op2 = Z_REFVAL_P(op2);
} else if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL, mul_function);
if (EXPECTED(op1 != op2)) {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
} else {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
op2 = op1;
}
if (EG(exception)) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
converted = 1;
} else {
if (result != op1) {
ZVAL_UNDEF(result);
}
zend_throw_error(NULL, "Unsupported operand types");
return FAILURE; /* unknown datatype */
}
}
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
zval op1_copy, op2_copy;
int converted = 0;
while (1) {
zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
if (Z_LVAL_P(op2) >= 0) {
zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
if (i == 0) {
ZVAL_LONG(result, 1L);
return SUCCESS;
} else if (l2 == 0) {
ZVAL_LONG(result, 0);
return SUCCESS;
}
while (i >= 1) {
zend_long overflow;
double dval = 0.0;
if (i % 2) {
--i;
ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
if (overflow) {
ZVAL_DOUBLE(result, dval * pow(l2, i));
return SUCCESS;
}
} else {
i /= 2;
ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
if (overflow) {
ZVAL_DOUBLE(result, (double)l1 * pow(dval, i));
return SUCCESS;
}
}
}
/* i == 0 */
ZVAL_LONG(result, l1);
} else {
ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
}
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
return SUCCESS;
} else {
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
} else if (Z_ISREF_P(op2)) {
op2 = Z_REFVAL_P(op2);
} else if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW, pow_function);
if (EXPECTED(op1 != op2)) {
if (Z_TYPE_P(op1) == IS_ARRAY) {
ZVAL_LONG(result, 0);
return SUCCESS;
} else {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
}
if (Z_TYPE_P(op2) == IS_ARRAY) {
ZVAL_LONG(result, 1L);
return SUCCESS;
} else {
op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
}
} else {
if (Z_TYPE_P(op1) == IS_ARRAY) {
ZVAL_LONG(result, 0);
return SUCCESS;
} else {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
}
op2 = op1;
}
if (EG(exception)) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
converted = 1;
} else {
if (result != op1) {
ZVAL_UNDEF(result);
}
zend_throw_error(NULL, "Unsupported operand types");
return FAILURE;
}
}
}
}
2014-05-24 21:19:34 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zval op1_copy, op2_copy;
int converted = 0;
while (1) {
zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1999-04-08 02:10:10 +08:00
if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
if (Z_LVAL_P(op2) == 0) {
zend_error(E_WARNING, "Division by zero");
ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2)));
return SUCCESS;
} else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
/* Prevent overflow error/crash */
ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
return SUCCESS;
}
if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
} else {
ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
}
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
if (Z_DVAL_P(op2) == 0) {
zend_error(E_WARNING, "Division by zero");
}
ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
if (Z_LVAL_P(op2) == 0) {
zend_error(E_WARNING, "Division by zero");
}
ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
return SUCCESS;
} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
if (Z_DVAL_P(op2) == 0) {
zend_error(E_WARNING, "Division by zero");
}
ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
return SUCCESS;
} else {
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
} else if (Z_ISREF_P(op2)) {
op2 = Z_REFVAL_P(op2);
} else if (!converted) {
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function);
if (EXPECTED(op1 != op2)) {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
} else {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
op2 = op1;
}
if (EG(exception)) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
converted = 1;
} else {
if (result != op1) {
ZVAL_UNDEF(result);
}
zend_throw_error(NULL, "Unsupported operand types");
return FAILURE; /* unknown datatype */
}
1999-04-08 02:10:10 +08:00
}
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_long op1_lval, op2_lval;
convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_MOD, mod_function);
2015-01-08 06:21:12 +08:00
if (op2_lval == 0) {
/* modulus by zero */
if (EG(current_execute_data) && !CG(in_compilation)) {
zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
} else {
2015-07-03 02:47:44 +08:00
zend_error_noreturn(E_ERROR, "Modulo by zero");
}
if (op1 != result) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
if (op1 == result) {
zval_ptr_dtor(result);
}
if (op2_lval == -1) {
/* Prevent overflow error/crash if op1==LONG_MIN */
ZVAL_LONG(result, 0);
return SUCCESS;
}
ZVAL_LONG(result, op1_lval % op2_lval);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL boolean_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
int op1_val, op2_val;
1999-04-08 02:10:10 +08:00
do {
if (Z_TYPE_P(op1) == IS_FALSE) {
op1_val = 0;
} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
op1_val = 1;
} else {
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
if (Z_TYPE_P(op1) == IS_FALSE) {
op1_val = 0;
break;
} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
op1_val = 1;
break;
}
}
ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BOOL_XOR, boolean_xor_function);
op1_val = zval_is_true(op1);
}
} while (0);
do {
if (Z_TYPE_P(op2) == IS_FALSE) {
op2_val = 0;
} else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
op2_val = 1;
} else {
if (Z_ISREF_P(op2)) {
op2 = Z_REFVAL_P(op2);
if (Z_TYPE_P(op2) == IS_FALSE) {
op2_val = 0;
break;
} else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
op2_val = 1;
break;
}
}
ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BOOL_XOR);
op2_val = zval_is_true(op2);
}
} while (0);
ZVAL_BOOL(result, op1_val ^ op2_val);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL boolean_not_function(zval *result, zval *op1) /* {{{ */
1999-04-08 02:10:10 +08:00
{
if (Z_TYPE_P(op1) < IS_TRUE) {
ZVAL_TRUE(result);
} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
ZVAL_FALSE(result);
} else {
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
if (Z_TYPE_P(op1) < IS_TRUE) {
ZVAL_TRUE(result);
return SUCCESS;
} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
ZVAL_FALSE(result);
return SUCCESS;
}
}
ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
ZVAL_BOOL(result, !zval_is_true(op1));
}
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{ */
1999-04-08 02:10:10 +08:00
{
try_again:
switch (Z_TYPE_P(op1)) {
case IS_LONG:
ZVAL_LONG(result, ~Z_LVAL_P(op1));
return SUCCESS;
case IS_DOUBLE:
ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
return SUCCESS;
case IS_STRING: {
2014-08-26 01:24:55 +08:00
size_t i;
if (Z_STRLEN_P(op1) == 1) {
zend_uchar not = (zend_uchar) ~*Z_STRVAL_P(op1);
ZVAL_INTERNED_STR(result, ZSTR_CHAR(not));
} else {
ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
for (i = 0; i < Z_STRLEN_P(op1); i++) {
Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
}
Z_STRVAL_P(result)[i] = 0;
}
return SUCCESS;
1999-04-08 02:10:10 +08:00
}
case IS_REFERENCE:
op1 = Z_REFVAL_P(op1);
goto try_again;
default:
ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
if (result != op1) {
ZVAL_UNDEF(result);
}
zend_throw_error(NULL, "Unsupported operand types");
return FAILURE;
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_long op1_lval, op2_lval;
if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
ZVAL_LONG(result, Z_LVAL_P(op1) | Z_LVAL_P(op2));
return SUCCESS;
}
2015-01-03 17:22:58 +08:00
ZVAL_DEREF(op1);
ZVAL_DEREF(op2);
if (Z_TYPE_P(op1) == IS_STRING && EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1999-04-08 02:10:10 +08:00
zval *longer, *shorter;
zend_string *str;
2014-08-26 01:24:55 +08:00
size_t i;
1999-04-08 02:10:10 +08:00
if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
zend_uchar or = (zend_uchar) (*Z_STRVAL_P(op1) | *Z_STRVAL_P(op2));
if (result==op1) {
zval_ptr_dtor_str(result);
}
ZVAL_INTERNED_STR(result, ZSTR_CHAR(or));
return SUCCESS;
}
1999-04-08 02:10:10 +08:00
longer = op1;
shorter = op2;
} else {
longer = op2;
shorter = op1;
}
2014-08-26 01:24:55 +08:00
str = zend_string_alloc(Z_STRLEN_P(longer), 0);
for (i = 0; i < Z_STRLEN_P(shorter); i++) {
ZSTR_VAL(str)[i] = Z_STRVAL_P(longer)[i] | Z_STRVAL_P(shorter)[i];
}
memcpy(ZSTR_VAL(str) + i, Z_STRVAL_P(longer) + i, Z_STRLEN_P(longer) - i + 1);
if (result==op1) {
zval_ptr_dtor_str(result);
1999-04-08 02:10:10 +08:00
}
ZVAL_NEW_STR(result, str);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR, bitwise_or_function);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
op1_lval = _zval_get_long_func_noisy(op1);
if (UNEXPECTED(EG(exception))) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
} else {
op1_lval = Z_LVAL_P(op1);
}
if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
op2_lval = _zval_get_long_func_noisy(op2);
if (UNEXPECTED(EG(exception))) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
} else {
op2_lval = Z_LVAL_P(op2);
}
1999-04-08 02:10:10 +08:00
if (op1 == result) {
zval_ptr_dtor(result);
}
ZVAL_LONG(result, op1_lval | op2_lval);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_long op1_lval, op2_lval;
if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
ZVAL_LONG(result, Z_LVAL_P(op1) & Z_LVAL_P(op2));
return SUCCESS;
}
2015-01-03 17:22:58 +08:00
ZVAL_DEREF(op1);
ZVAL_DEREF(op2);
if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1999-04-08 02:10:10 +08:00
zval *longer, *shorter;
zend_string *str;
2014-08-26 01:24:55 +08:00
size_t i;
1999-04-08 02:10:10 +08:00
if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
zend_uchar and = (zend_uchar) (*Z_STRVAL_P(op1) & *Z_STRVAL_P(op2));
if (result==op1) {
zval_ptr_dtor_str(result);
}
ZVAL_INTERNED_STR(result, ZSTR_CHAR(and));
return SUCCESS;
}
1999-04-08 02:10:10 +08:00
longer = op1;
shorter = op2;
} else {
longer = op2;
shorter = op1;
}
2014-08-26 01:24:55 +08:00
str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
for (i = 0; i < Z_STRLEN_P(shorter); i++) {
ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] & Z_STRVAL_P(longer)[i];
1999-04-08 02:10:10 +08:00
}
ZSTR_VAL(str)[i] = 0;
if (result==op1) {
zval_ptr_dtor_str(result);
}
ZVAL_NEW_STR(result, str);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
2015-06-04 22:09:22 +08:00
ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND, bitwise_and_function);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
op1_lval = _zval_get_long_func_noisy(op1);
if (UNEXPECTED(EG(exception))) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
} else {
op1_lval = Z_LVAL_P(op1);
}
if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
op2_lval = _zval_get_long_func_noisy(op2);
if (UNEXPECTED(EG(exception))) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
} else {
op2_lval = Z_LVAL_P(op2);
}
1999-04-08 02:10:10 +08:00
if (op1 == result) {
zval_ptr_dtor(result);
}
ZVAL_LONG(result, op1_lval & op2_lval);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_long op1_lval, op2_lval;
if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
ZVAL_LONG(result, Z_LVAL_P(op1) ^ Z_LVAL_P(op2));
return SUCCESS;
}
2015-01-03 17:22:58 +08:00
ZVAL_DEREF(op1);
ZVAL_DEREF(op2);
if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1999-04-08 02:10:10 +08:00
zval *longer, *shorter;
zend_string *str;
2014-08-26 01:24:55 +08:00
size_t i;
1999-04-08 02:10:10 +08:00
if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
zend_uchar xor = (zend_uchar) (*Z_STRVAL_P(op1) ^ *Z_STRVAL_P(op2));
if (result==op1) {
zval_ptr_dtor_str(result);
}
ZVAL_INTERNED_STR(result, ZSTR_CHAR(xor));
return SUCCESS;
}
1999-04-08 02:10:10 +08:00
longer = op1;
shorter = op2;
} else {
longer = op2;
shorter = op1;
}
2014-08-26 01:24:55 +08:00
str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
for (i = 0; i < Z_STRLEN_P(shorter); i++) {
ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] ^ Z_STRVAL_P(longer)[i];
}
ZSTR_VAL(str)[i] = 0;
if (result==op1) {
zval_ptr_dtor_str(result);
1999-04-08 02:10:10 +08:00
}
ZVAL_NEW_STR(result, str);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
2015-06-04 22:09:22 +08:00
ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR, bitwise_xor_function);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
op1_lval = _zval_get_long_func_noisy(op1);
if (UNEXPECTED(EG(exception))) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
} else {
op1_lval = Z_LVAL_P(op1);
}
if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR);
Warn about invalid strings in arithmetic Squashed commit of the following: commit e05d3b67325d4521418483ed924ac9211a188919 Author: Andrea Faulds <ajf@ajf.me> Date: Wed Mar 30 01:43:35 2016 +0100 UPGRADING and NEWS commit 6caf1d4585207d1b02fb06a216cd7da1a1f5e12d Author: Andrea Faulds <ajf@ajf.me> Date: Sun Mar 20 21:18:33 2016 +0000 Fixes commit 6dadb1b0efe5e2ed071e95a55c806519e61377ac Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 02:15:01 2016 +0000 Add test for numeric string errors in assignment commit bd5f04e8dd576f92a48d25546f4f9a0f57f374de Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 23:53:05 2016 +0000 Add test for numeric string errors commit c72e92f16d512bcae30cc9639c89bcb08d971742 Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:28:33 2016 +0000 Add test for scientific notation in integer operations commit d94c08852d405b3a7ef6c84d24bf7915c890ce78 Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:25:57 2016 +0000 Disable optimiser evaluation for numeric string errors commit 30ee954ed13d933e766c68605d683c8ebae3d8ee Author: Andrea Faulds <ajf@ajf.me> Date: Sun Feb 14 01:46:25 2016 +0000 fixup commit a6403b79e054c95e2b7345d787f3092b261eed27 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 22:00:27 2016 +0000 Do not convert error-causing numeric strings ahead-of-time commit f9dc35401471ef3035954cb6f171826769297548 Author: Andrea Faulds <ajf@ajf.me> Date: Sat Feb 13 19:15:38 2016 +0000 Disable compile-time evaluation for numeric string errors commit e05b0cc8496ea082c6db27efd8b8277ef1f785b5 Author: Andrea Faulds <ajf@ajf.me> Date: Fri Feb 5 11:42:26 2016 +0000 Make _zval_get_long_func_noisy function for inlining commit 84d66321a57e579759109650c8bb7e3d5002854a Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 23:10:00 2016 +0000 Update tests commit 5ac4a0cc4bff282e3a15eaa8ab44b67391881a6d Author: Andrea Faulds <ajf@ajf.me> Date: Tue Jan 26 22:08:19 2016 +0000 Use is_numeric_string_ex for zval_get_long etc. commit c21f08848533723331012a62a153de3577731d6a Author: Andrea Faulds <ajf@ajf.me> Date: Thu Jan 7 21:13:04 2016 +0000 Update tests commit 63e214cf8160420bfc51c6a2b4ae32f09ad8e8af Author: Andrea Faulds <ajf@ajf.me> Date: Wed Jan 6 00:28:01 2016 +0000 Warn on non-/bad numeric strings in arithmetic
2016-03-30 08:44:27 +08:00
op2_lval = _zval_get_long_func_noisy(op2);
if (UNEXPECTED(EG(exception))) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
} else {
op2_lval = Z_LVAL_P(op2);
}
1999-04-08 02:10:10 +08:00
if (op1 == result) {
zval_ptr_dtor(result);
}
ZVAL_LONG(result, op1_lval ^ op2_lval);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_long op1_lval, op2_lval;
convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SL, shift_left_function);
/* prevent wrapping quirkiness on some processors where << 64 + x == << x */
if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
if (EXPECTED(op2_lval > 0)) {
if (op1 == result) {
zval_ptr_dtor(result);
}
ZVAL_LONG(result, 0);
return SUCCESS;
} else {
if (EG(current_execute_data) && !CG(in_compilation)) {
2015-07-03 02:47:44 +08:00
zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
} else {
zend_error_noreturn(E_ERROR, "Bit shift by negative number");
}
if (op1 != result) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
}
if (op1 == result) {
zval_ptr_dtor(result);
}
2019-06-19 18:59:18 +08:00
/* Perform shift on unsigned numbers to get well-defined wrap behavior. */
ZVAL_LONG(result, (zend_long) ((zend_ulong) op1_lval << op2_lval));
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zend_long op1_lval, op2_lval;
convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SR, shift_right_function);
/* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */
if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
if (EXPECTED(op2_lval > 0)) {
if (op1 == result) {
zval_ptr_dtor(result);
}
2016-12-03 00:03:05 +08:00
ZVAL_LONG(result, (op1_lval < 0) ? -1 : 0);
return SUCCESS;
} else {
if (EG(current_execute_data) && !CG(in_compilation)) {
2015-07-03 02:47:44 +08:00
zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
} else {
zend_error_noreturn(E_ERROR, "Bit shift by negative number");
}
if (op1 != result) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
}
if (op1 == result) {
zval_ptr_dtor(result);
}
ZVAL_LONG(result, op1_lval >> op2_lval);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
zval *orig_op1 = op1;
zval op1_copy, op2_copy;
2018-07-04 17:05:51 +08:00
ZVAL_UNDEF(&op1_copy);
ZVAL_UNDEF(&op2_copy);
do {
if (UNEXPECTED(Z_TYPE_P(op1) != IS_STRING)) {
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
if (Z_TYPE_P(op1) == IS_STRING) break;
}
ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT, concat_function);
2018-07-04 17:05:51 +08:00
ZVAL_STR(&op1_copy, zval_get_string_func(op1));
if (UNEXPECTED(EG(exception))) {
zval_ptr_dtor_str(&op1_copy);
if (orig_op1 != result) {
ZVAL_UNDEF(result);
}
2018-07-04 17:05:51 +08:00
return FAILURE;
}
if (result == op1) {
if (UNEXPECTED(op1 == op2)) {
op2 = &op1_copy;
}
}
2018-07-04 17:05:51 +08:00
op1 = &op1_copy;
}
} while (0);
do {
if (UNEXPECTED(Z_TYPE_P(op2) != IS_STRING)) {
if (Z_ISREF_P(op2)) {
op2 = Z_REFVAL_P(op2);
if (Z_TYPE_P(op2) == IS_STRING) break;
}
ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT);
2018-07-04 17:05:51 +08:00
ZVAL_STR(&op2_copy, zval_get_string_func(op2));
if (UNEXPECTED(EG(exception))) {
zval_ptr_dtor_str(&op1_copy);
zval_ptr_dtor_str(&op2_copy);
if (orig_op1 != result) {
ZVAL_UNDEF(result);
}
2018-07-04 17:05:51 +08:00
return FAILURE;
}
2018-07-04 17:05:51 +08:00
op2 = &op2_copy;
}
} while (0);
if (UNEXPECTED(Z_STRLEN_P(op1) == 0)) {
if (EXPECTED(result != op2)) {
if (result == orig_op1) {
i_zval_ptr_dtor(result);
}
ZVAL_COPY(result, op2);
}
} else if (UNEXPECTED(Z_STRLEN_P(op2) == 0)) {
if (EXPECTED(result != op1)) {
ZVAL_COPY(result, op1);
}
} else {
2014-08-26 01:24:55 +08:00
size_t op1_len = Z_STRLEN_P(op1);
size_t op2_len = Z_STRLEN_P(op2);
size_t result_len = op1_len + op2_len;
zend_string *result_str;
if (UNEXPECTED(op1_len > SIZE_MAX - op2_len)) {
zend_throw_error(NULL, "String size overflow");
2018-07-04 17:05:51 +08:00
zval_ptr_dtor_str(&op1_copy);
zval_ptr_dtor_str(&op2_copy);
if (orig_op1 != result) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
if (result == op1 && Z_REFCOUNTED_P(result)) {
/* special case, perform operations on result */
result_str = zend_string_extend(Z_STR_P(result), result_len, 0);
} else {
result_str = zend_string_alloc(result_len, 0);
memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
if (result == orig_op1) {
i_zval_ptr_dtor(result);
}
}
/* This has to happen first to account for the cases where result == op1 == op2 and
* the realloc is done. In this case this line will also update Z_STRVAL_P(op2) to
* point to the new string. The first op2_len bytes of result will still be the same. */
ZVAL_NEW_STR(result, result_str);
memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
ZSTR_VAL(result_str)[result_len] = '\0';
2000-03-23 02:43:25 +08:00
}
2018-07-04 17:05:51 +08:00
zval_ptr_dtor_str(&op1_copy);
zval_ptr_dtor_str(&op2_copy);
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, zend_bool case_insensitive) /* {{{ */
{
zend_string *tmp_str1, *tmp_str2;
zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
int ret;
if (case_insensitive) {
ret = zend_binary_strcasecmp_l(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1));
} else {
ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
}
zend_tmp_string_release(tmp_str1);
zend_tmp_string_release(tmp_str2);
return ret;
}
2009-05-11 15:52:49 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL string_compare_function(zval *op1, zval *op2) /* {{{ */
{
2014-06-09 21:00:22 +08:00
if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
if (Z_STR_P(op1) == Z_STR_P(op2)) {
return 0;
2014-06-09 21:00:22 +08:00
} else {
return zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
2014-06-09 21:00:22 +08:00
}
} else {
zend_string *tmp_str1, *tmp_str2;
zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
int ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2014-06-09 21:00:22 +08:00
zend_tmp_string_release(tmp_str1);
zend_tmp_string_release(tmp_str2);
return ret;
2014-06-09 21:00:22 +08:00
}
}
/* }}} */
ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2) /* {{{ */
{
2014-06-09 21:00:22 +08:00
if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
if (Z_STR_P(op1) == Z_STR_P(op2)) {
return 0;
2014-06-09 21:00:22 +08:00
} else {
return zend_binary_strcasecmp_l(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
2014-06-09 21:00:22 +08:00
}
} else {
zend_string *tmp_str1, *tmp_str2;
zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
int ret = zend_binary_strcasecmp_l(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1));
2014-06-09 21:00:22 +08:00
zend_tmp_string_release(tmp_str1);
zend_tmp_string_release(tmp_str2);
return ret;
2014-06-09 21:00:22 +08:00
}
}
/* }}} */
#if HAVE_STRCOLL
ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2) /* {{{ */
{
zend_string *tmp_str1, *tmp_str2;
zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
int ret = strcoll(ZSTR_VAL(str1), ZSTR_VAL(str2));
zend_tmp_string_release(tmp_str1);
zend_tmp_string_release(tmp_str2);
return ret;
}
2009-05-11 15:52:49 +08:00
/* }}} */
#endif
ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{ */
{
2014-06-03 04:36:31 +08:00
double d1, d2;
2014-06-03 04:36:31 +08:00
d1 = zval_get_double(op1);
d2 = zval_get_double(op2);
return ZEND_NORMALIZE_BOOL(d1 - d2);
}
2009-05-11 07:08:52 +08:00
/* }}} */
static zend_always_inline void zend_free_obj_get_result(zval *op) /* {{{ */
{
ZEND_ASSERT(!Z_REFCOUNTED_P(op) || Z_REFCOUNT_P(op) != 0);
zval_ptr_dtor(op);
}
2009-05-11 07:08:52 +08:00
/* }}} */
2015-09-10 15:01:28 +08:00
static void ZEND_FASTCALL convert_compare_result_to_long(zval *result) /* {{{ */
2015-09-09 20:11:03 +08:00
{
if (Z_TYPE_P(result) == IS_DOUBLE) {
ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
} else {
convert_to_long(result);
}
}
2015-09-10 15:01:28 +08:00
/* }}} */
2015-09-09 20:11:03 +08:00
ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2009-05-11 15:52:49 +08:00
int ret;
int converted = 0;
1999-04-08 02:10:10 +08:00
zval op1_copy, op2_copy;
zval *op_free, tmp_free;
while (1) {
switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
case TYPE_PAIR(IS_LONG, IS_LONG):
ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_LONG):
Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
return SUCCESS;
1999-04-08 02:10:10 +08:00
case TYPE_PAIR(IS_LONG, IS_DOUBLE):
Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
return SUCCESS;
case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
ZVAL_LONG(result, 0);
} else {
Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
}
return SUCCESS;
case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2014-12-22 12:16:25 +08:00
ZVAL_LONG(result, zend_compare_arrays(op1, op2));
return SUCCESS;
case TYPE_PAIR(IS_NULL, IS_NULL):
case TYPE_PAIR(IS_NULL, IS_FALSE):
case TYPE_PAIR(IS_FALSE, IS_NULL):
case TYPE_PAIR(IS_FALSE, IS_FALSE):
case TYPE_PAIR(IS_TRUE, IS_TRUE):
ZVAL_LONG(result, 0);
return SUCCESS;
1999-04-08 02:10:10 +08:00
case TYPE_PAIR(IS_NULL, IS_TRUE):
ZVAL_LONG(result, -1);
return SUCCESS;
case TYPE_PAIR(IS_TRUE, IS_NULL):
ZVAL_LONG(result, 1);
return SUCCESS;
case TYPE_PAIR(IS_STRING, IS_STRING):
2014-06-05 23:14:47 +08:00
if (Z_STR_P(op1) == Z_STR_P(op2)) {
ZVAL_LONG(result, 0);
return SUCCESS;
}
ZVAL_LONG(result, zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2)));
return SUCCESS;
case TYPE_PAIR(IS_NULL, IS_STRING):
2014-06-05 23:14:47 +08:00
ZVAL_LONG(result, Z_STRLEN_P(op2) == 0 ? 0 : -1);
return SUCCESS;
case TYPE_PAIR(IS_STRING, IS_NULL):
2014-06-05 23:14:47 +08:00
ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1);
return SUCCESS;
case TYPE_PAIR(IS_OBJECT, IS_NULL):
ZVAL_LONG(result, 1);
return SUCCESS;
case TYPE_PAIR(IS_NULL, IS_OBJECT):
ZVAL_LONG(result, -1);
return SUCCESS;
default:
2014-08-14 19:07:39 +08:00
if (Z_ISREF_P(op1)) {
op1 = Z_REFVAL_P(op1);
continue;
} else if (Z_ISREF_P(op2)) {
op2 = Z_REFVAL_P(op2);
continue;
}
if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
2015-09-09 20:11:03 +08:00
ret = Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2);
if (UNEXPECTED(Z_TYPE_P(result) != IS_LONG)) {
convert_compare_result_to_long(result);
}
return ret;
} else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
2015-09-09 20:11:03 +08:00
ret = Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2);
if (UNEXPECTED(Z_TYPE_P(result) != IS_LONG)) {
convert_compare_result_to_long(result);
}
return ret;
}
if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
if (Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
/* object handles are identical, apparently this is the same object */
ZVAL_LONG(result, 0);
return SUCCESS;
}
if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
2014-12-14 06:06:14 +08:00
ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2));
return SUCCESS;
}
}
if (Z_TYPE_P(op1) == IS_OBJECT) {
if (Z_OBJ_HT_P(op1)->get) {
2014-04-15 11:05:03 +08:00
zval rv;
2014-12-14 06:06:14 +08:00
op_free = Z_OBJ_HT_P(op1)->get(op1, &rv);
ret = compare_function(result, op_free, op2);
zend_free_obj_get_result(op_free);
return ret;
2009-05-11 15:52:49 +08:00
} else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
2014-02-24 17:49:53 +08:00
ZVAL_UNDEF(&tmp_free);
2014-12-14 06:06:14 +08:00
if (Z_OBJ_HT_P(op1)->cast_object(op1, &tmp_free, ((Z_TYPE_P(op2) == IS_FALSE || Z_TYPE_P(op2) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op2))) == FAILURE) {
ZVAL_LONG(result, 1);
2014-12-14 06:06:14 +08:00
zend_free_obj_get_result(&tmp_free);
return SUCCESS;
}
2014-12-14 06:06:14 +08:00
ret = compare_function(result, &tmp_free, op2);
zend_free_obj_get_result(&tmp_free);
return ret;
}
}
if (Z_TYPE_P(op2) == IS_OBJECT) {
if (Z_OBJ_HT_P(op2)->get) {
2014-04-15 11:05:03 +08:00
zval rv;
2014-12-14 06:06:14 +08:00
op_free = Z_OBJ_HT_P(op2)->get(op2, &rv);
ret = compare_function(result, op1, op_free);
zend_free_obj_get_result(op_free);
return ret;
2009-05-11 15:52:49 +08:00
} else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
2014-02-24 17:49:53 +08:00
ZVAL_UNDEF(&tmp_free);
2014-12-14 06:06:14 +08:00
if (Z_OBJ_HT_P(op2)->cast_object(op2, &tmp_free, ((Z_TYPE_P(op1) == IS_FALSE || Z_TYPE_P(op1) == IS_TRUE) ? _IS_BOOL : Z_TYPE_P(op1))) == FAILURE) {
ZVAL_LONG(result, -1);
2014-12-14 06:06:14 +08:00
zend_free_obj_get_result(&tmp_free);
return SUCCESS;
}
2014-12-14 06:06:14 +08:00
ret = compare_function(result, op1, &tmp_free);
zend_free_obj_get_result(&tmp_free);
return ret;
} else if (Z_TYPE_P(op1) == IS_OBJECT) {
ZVAL_LONG(result, 1);
return SUCCESS;
}
}
2014-08-14 19:07:39 +08:00
if (!converted) {
if (Z_TYPE_P(op1) < IS_TRUE) {
ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0);
return SUCCESS;
} else if (Z_TYPE_P(op1) == IS_TRUE) {
ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1);
return SUCCESS;
} else if (Z_TYPE_P(op2) < IS_TRUE) {
ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0);
return SUCCESS;
} else if (Z_TYPE_P(op2) == IS_TRUE) {
ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1);
return SUCCESS;
} else {
op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 1);
op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 1);
if (EG(exception)) {
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
converted = 1;
}
} else if (Z_TYPE_P(op1)==IS_ARRAY) {
ZVAL_LONG(result, 1);
return SUCCESS;
} else if (Z_TYPE_P(op2)==IS_ARRAY) {
ZVAL_LONG(result, -1);
return SUCCESS;
} else {
ZEND_ASSERT(0);
zend_throw_error(NULL, "Unsupported operand types");
if (result != op1) {
ZVAL_UNDEF(result);
}
return FAILURE;
}
}
}
1999-04-08 02:10:10 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */
{
/* is_identical_function() returns 1 in case of identity and 0 in case
* of a difference;
* whereas this comparison function is expected to return 0 on identity,
* and non zero otherwise.
*/
ZVAL_DEREF(z1);
ZVAL_DEREF(z2);
return fast_is_not_identical_function(z1, z2);
}
/* }}} */
ZEND_API zend_bool ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2) /* {{{ */
{
if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
return 0;
}
switch (Z_TYPE_P(op1)) {
case IS_NULL:
case IS_FALSE:
case IS_TRUE:
return 1;
case IS_LONG:
return (Z_LVAL_P(op1) == Z_LVAL_P(op2));
case IS_RESOURCE:
return (Z_RES_P(op1) == Z_RES_P(op2));
case IS_DOUBLE:
return (Z_DVAL_P(op1) == Z_DVAL_P(op2));
case IS_STRING:
return zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
case IS_ARRAY:
return (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1) == 0);
case IS_OBJECT:
2018-07-10 16:04:10 +08:00
return (Z_OBJ_P(op1) == Z_OBJ_P(op2));
default:
return 0;
}
}
/* }}} */
ZEND_API int ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
{
ZVAL_BOOL(result, zend_is_identical(op1, op2));
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2000-03-30 06:05:19 +08:00
{
ZVAL_BOOL(result, !zend_is_identical(op1, op2));
2009-05-11 15:52:49 +08:00
return SUCCESS;
2000-03-30 06:05:19 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
2000-03-30 06:05:19 +08:00
ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-12-14 06:06:14 +08:00
if (compare_function(result, op1, op2) == FAILURE) {
1999-04-08 02:10:10 +08:00
return FAILURE;
}
ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-12-14 06:06:14 +08:00
if (compare_function(result, op1, op2) == FAILURE) {
1999-04-08 02:10:10 +08:00
return FAILURE;
}
ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
1999-04-08 02:10:10 +08:00
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-12-14 06:06:14 +08:00
if (compare_function(result, op1, op2) == FAILURE) {
1999-04-08 02:10:10 +08:00
return FAILURE;
}
ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
return SUCCESS;
1999-04-08 02:10:10 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-12-14 06:06:14 +08:00
if (compare_function(result, op1, op2) == FAILURE) {
1999-04-08 02:10:10 +08:00
return FAILURE;
}
ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
return SUCCESS;
1999-04-08 02:10:10 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
static zend_bool ZEND_FASTCALL instanceof_interface_only(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
{
2014-08-26 01:28:33 +08:00
uint32_t i;
2003-03-05 19:14:44 +08:00
if (instance_ce->num_interfaces) {
Support full variance if autoloading is used Keep track of delayed variance obligations and check them after linking a class is otherwise finished. Obligations may either be unresolved method compatibility (because the necessecary classes aren't available yet) or open parent/interface dependencies. The latter occur because we allow the use of not fully linked classes as parents/interfaces now. An important aspect of the implementation is we do not require classes involved in variance checks to be fully linked in order for the class to be fully linked. Because the involved types do have to exist in the class table (as partially linked classes) and we do check these for correct variance, we have the guarantee that either those classes will successfully link lateron or generate an error, but there is no way to actually use them until that point and as such no possibility of violating the variance contract. This is important because it ensures that a class declaration always either errors or will produce an immediately usable class afterwards -- there are no cases where the finalization of the class declaration has to be delayed until a later time, as earlier variants of this patch did. Because variance checks deal with classes in various stages of linking, we need to use a special instanceof implementation that supports this, and also introduce finer-grained flags that tell us which parts have been linked already and which haven't. Class autoloading for variance checks is delayed into a separate stage after the class is otherwise linked and before delayed variance obligations are processed. This separation is needed to handle cases like A extends B extends C, where B is the autoload root, but C is required to check variance. This could end up loading C while the class structure of B is in an inconsistent state.
2019-05-27 17:39:56 +08:00
ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
for (i = 0; i < instance_ce->num_interfaces; i++) {
if (instanceof_interface_only(instance_ce->interfaces[i], ce)) {
return 1;
}
}
}
return 0;
}
/* }}} */
static zend_always_inline zend_bool instanceof_class(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
{
while (instance_ce) {
if (instance_ce == ce) {
return 1;
}
instance_ce = instance_ce->parent;
}
return 0;
}
/* }}} */
static zend_bool ZEND_FASTCALL instanceof_interface(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
{
uint32_t i;
if (instance_ce->num_interfaces) {
Support full variance if autoloading is used Keep track of delayed variance obligations and check them after linking a class is otherwise finished. Obligations may either be unresolved method compatibility (because the necessecary classes aren't available yet) or open parent/interface dependencies. The latter occur because we allow the use of not fully linked classes as parents/interfaces now. An important aspect of the implementation is we do not require classes involved in variance checks to be fully linked in order for the class to be fully linked. Because the involved types do have to exist in the class table (as partially linked classes) and we do check these for correct variance, we have the guarantee that either those classes will successfully link lateron or generate an error, but there is no way to actually use them until that point and as such no possibility of violating the variance contract. This is important because it ensures that a class declaration always either errors or will produce an immediately usable class afterwards -- there are no cases where the finalization of the class declaration has to be delayed until a later time, as earlier variants of this patch did. Because variance checks deal with classes in various stages of linking, we need to use a special instanceof implementation that supports this, and also introduce finer-grained flags that tell us which parts have been linked already and which haven't. Class autoloading for variance checks is delayed into a separate stage after the class is otherwise linked and before delayed variance obligations are processed. This separation is needed to handle cases like A extends B extends C, where B is the autoload root, but C is required to check variance. This could end up loading C while the class structure of B is in an inconsistent state.
2019-05-27 17:39:56 +08:00
ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
for (i = 0; i < instance_ce->num_interfaces; i++) {
if (instanceof_interface(instance_ce->interfaces[i], ce)) {
return 1;
}
}
}
return instanceof_class(instance_ce, ce);
}
/* }}} */
ZEND_API zend_bool ZEND_FASTCALL instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool interfaces_only) /* {{{ */
{
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
if (!interfaces_only) {
2015-01-15 02:09:06 +08:00
if (instanceof_interface_only(instance_ce, ce)) {
return 1;
}
} else {
return instanceof_interface(instance_ce, ce);
2003-03-05 19:14:44 +08:00
}
}
if (!interfaces_only) {
return instanceof_class(instance_ce, ce);
}
2003-03-05 19:14:44 +08:00
return 0;
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API zend_bool ZEND_FASTCALL instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
{
if (ce->ce_flags & ZEND_ACC_INTERFACE) {
return instanceof_interface(instance_ce, ce);
} else {
return instanceof_class(instance_ce, ce);
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
#define LOWER_CASE 1
#define UPPER_CASE 2
#define NUMERIC 3
static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2009-05-11 15:52:49 +08:00
int carry=0;
2014-08-26 01:24:55 +08:00
size_t pos=Z_STRLEN_P(str)-1;
char *s;
zend_string *t;
2009-05-11 15:52:49 +08:00
int last=0; /* Shut up the compiler warning */
int ch;
if (Z_STRLEN_P(str) == 0) {
zval_ptr_dtor_str(str);
ZVAL_INTERNED_STR(str, ZSTR_CHAR('1'));
2000-10-14 00:24:00 +08:00
return;
}
if (!Z_REFCOUNTED_P(str)) {
2014-08-26 01:24:55 +08:00
Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
Z_TYPE_INFO_P(str) = IS_STRING_EX;
} else if (Z_REFCOUNT_P(str) > 1) {
Z_DELREF_P(str);
2014-08-26 01:24:55 +08:00
Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
} else {
2014-08-26 01:24:55 +08:00
zend_string_forget_hash_val(Z_STR_P(str));
}
s = Z_STRVAL_P(str);
2014-09-05 18:44:51 +08:00
do {
2009-05-11 15:52:49 +08:00
ch = s[pos];
if (ch >= 'a' && ch <= 'z') {
if (ch == 'z') {
s[pos] = 'a';
carry=1;
} else {
s[pos]++;
carry=0;
}
last=LOWER_CASE;
} else if (ch >= 'A' && ch <= 'Z') {
if (ch == 'Z') {
s[pos] = 'A';
carry=1;
} else {
s[pos]++;
carry=0;
}
last=UPPER_CASE;
} else if (ch >= '0' && ch <= '9') {
if (ch == '9') {
s[pos] = '0';
carry=1;
} else {
s[pos]++;
carry=0;
}
last = NUMERIC;
} else {
carry=0;
break;
}
if (carry == 0) {
break;
}
2014-09-05 18:44:51 +08:00
} while (pos-- > 0);
2009-05-11 15:52:49 +08:00
if (carry) {
2014-08-26 01:24:55 +08:00
t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
memcpy(ZSTR_VAL(t) + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
ZSTR_VAL(t)[Z_STRLEN_P(str) + 1] = '\0';
2009-05-11 15:52:49 +08:00
switch (last) {
case NUMERIC:
ZSTR_VAL(t)[0] = '1';
2009-05-11 15:52:49 +08:00
break;
case UPPER_CASE:
ZSTR_VAL(t)[0] = 'A';
2009-05-11 15:52:49 +08:00
break;
case LOWER_CASE:
ZSTR_VAL(t)[0] = 'a';
2009-05-11 15:52:49 +08:00
break;
}
2014-08-26 01:24:55 +08:00
zend_string_free(Z_STR_P(str));
ZVAL_NEW_STR(str, t);
2009-05-11 15:52:49 +08:00
}
1999-04-08 02:10:10 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL increment_function(zval *op1) /* {{{ */
1999-04-08 02:10:10 +08:00
{
try_again:
switch (Z_TYPE_P(op1)) {
1999-04-08 02:10:10 +08:00
case IS_LONG:
fast_long_increment_function(op1);
1999-04-08 02:10:10 +08:00
break;
case IS_DOUBLE:
Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
1999-04-08 02:10:10 +08:00
break;
2000-01-04 21:22:58 +08:00
case IS_NULL:
ZVAL_LONG(op1, 1);
break;
case IS_STRING: {
2014-08-26 01:24:55 +08:00
zend_long lval;
double dval;
2009-03-18 19:25:37 +08:00
switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
case IS_LONG:
zval_ptr_dtor_str(op1);
2014-08-26 02:22:49 +08:00
if (lval == ZEND_LONG_MAX) {
2001-09-05 17:29:28 +08:00
/* switch to double */
double d = (double)lval;
ZVAL_DOUBLE(op1, d+1);
} else {
ZVAL_LONG(op1, lval+1);
2001-09-05 17:29:28 +08:00
}
break;
case IS_DOUBLE:
zval_ptr_dtor_str(op1);
ZVAL_DOUBLE(op1, dval+1);
break;
default:
/* Perl style string increment */
increment_string(op1);
break;
}
}
1999-04-08 02:10:10 +08:00
break;
case IS_OBJECT:
if (Z_OBJ_HANDLER_P(op1, get)
&& Z_OBJ_HANDLER_P(op1, set)) {
/* proxy object */
zval rv;
2014-09-26 02:28:34 +08:00
zval *val;
2015-01-03 17:22:58 +08:00
2014-12-14 06:06:14 +08:00
val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
Z_TRY_ADDREF_P(val);
increment_function(val);
2014-12-14 06:06:14 +08:00
Z_OBJ_HANDLER_P(op1, set)(op1, val);
zval_ptr_dtor(val);
} else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
zval op2;
int res;
2015-01-03 17:22:58 +08:00
ZVAL_LONG(&op2, 1);
2014-12-14 06:06:14 +08:00
res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2);
return res;
}
return FAILURE;
case IS_REFERENCE:
op1 = Z_REFVAL_P(op1);
goto try_again;
1999-04-08 02:10:10 +08:00
default:
return FAILURE;
}
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2014-08-26 01:24:55 +08:00
zend_long lval;
double dval;
try_again:
switch (Z_TYPE_P(op1)) {
1999-04-08 02:10:10 +08:00
case IS_LONG:
fast_long_decrement_function(op1);
1999-04-08 02:10:10 +08:00
break;
case IS_DOUBLE:
Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
1999-04-08 02:10:10 +08:00
break;
case IS_STRING: /* Like perl we only support string increment */
if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
zval_ptr_dtor_str(op1);
ZVAL_LONG(op1, -1);
1999-04-08 02:10:10 +08:00
break;
}
switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
case IS_LONG:
zval_ptr_dtor_str(op1);
2014-08-26 02:22:49 +08:00
if (lval == ZEND_LONG_MIN) {
double d = (double)lval;
ZVAL_DOUBLE(op1, d-1);
} else {
ZVAL_LONG(op1, lval-1);
}
break;
case IS_DOUBLE:
zval_ptr_dtor_str(op1);
ZVAL_DOUBLE(op1, dval - 1);
break;
1999-04-08 02:10:10 +08:00
}
break;
case IS_OBJECT:
if (Z_OBJ_HANDLER_P(op1, get)
&& Z_OBJ_HANDLER_P(op1, set)) {
/* proxy object */
zval rv;
2014-09-26 02:28:34 +08:00
zval *val;
2015-01-03 17:22:58 +08:00
2014-12-14 06:06:14 +08:00
val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
Z_TRY_ADDREF_P(val);
decrement_function(val);
2014-12-14 06:06:14 +08:00
Z_OBJ_HANDLER_P(op1, set)(op1, val);
zval_ptr_dtor(val);
} else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
zval op2;
int res;
2015-01-03 17:22:58 +08:00
ZVAL_LONG(&op2, 1);
2014-12-14 06:06:14 +08:00
res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2);
return res;
}
return FAILURE;
case IS_REFERENCE:
op1 = Z_REFVAL_P(op1);
goto try_again;
1999-04-08 02:10:10 +08:00
default:
return FAILURE;
}
return SUCCESS;
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL zend_is_true(zval *op) /* {{{ */
{
2014-12-14 06:06:14 +08:00
return i_zend_is_true(op);
}
/* }}} */
ZEND_API int ZEND_FASTCALL zend_object_is_true(zval *op) /* {{{ */
1999-04-08 02:10:10 +08:00
{
if (Z_OBJ_HT_P(op)->cast_object) {
zval tmp;
2014-12-14 06:06:14 +08:00
if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, _IS_BOOL) == SUCCESS) {
return Z_TYPE(tmp) == IS_TRUE;
}
2018-02-06 21:21:01 +08:00
zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to bool", ZSTR_VAL(Z_OBJ_P(op)->ce->name));
} else if (Z_OBJ_HT_P(op)->get) {
int result;
zval rv;
2014-12-14 06:06:14 +08:00
zval *tmp = Z_OBJ_HT_P(op)->get(op, &rv);
if (Z_TYPE_P(tmp) != IS_OBJECT) {
/* for safety - avoid loop */
2014-12-14 06:06:14 +08:00
result = i_zend_is_true(tmp);
zval_ptr_dtor(tmp);
return result;
}
}
return 1;
1999-04-08 02:10:10 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
2009-05-11 15:52:49 +08:00
#ifdef ZEND_USE_TOLOWER_L
2015-03-14 20:11:55 +08:00
ZEND_API void zend_update_current_locale(void) /* {{{ */
{
current_locale = _get_current_locale();
}
2009-05-11 15:52:49 +08:00
/* }}} */
#endif
ZEND_API char* ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
{
register unsigned char *str = (unsigned char*)source;
2003-08-18 03:14:30 +08:00
register unsigned char *result = (unsigned char*)dest;
register unsigned char *end = str + length;
while (str < end) {
2012-07-15 12:06:40 +08:00
*result++ = zend_tolower_ascii(*str++);
}
*result = '\0';
return dest;
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2009-05-11 06:39:33 +08:00
{
return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
}
2009-05-11 07:08:52 +08:00
/* }}} */
2009-05-11 06:39:33 +08:00
ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length) /* {{{ */
1999-04-08 02:10:10 +08:00
{
register unsigned char *p = (unsigned char*)str;
register unsigned char *end = p + length;
while (p < end) {
2012-07-15 12:06:40 +08:00
*p = zend_tolower_ascii(*p);
p++;
}
2002-09-27 02:56:11 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length) /* {{{ */
{
register const unsigned char *p = (const unsigned char*)source;
register const unsigned char *end = p + length;
while (p < end) {
if (*p != zend_tolower_ascii(*p)) {
char *res = (char*)emalloc(length + 1);
register unsigned char *r;
if (p != (const unsigned char*)source) {
memcpy(res, source, p - (const unsigned char*)source);
}
r = (unsigned char*)p + (res - source);
while (p < end) {
*r = zend_tolower_ascii(*p);
p++;
r++;
}
*r = '\0';
return res;
}
p++;
}
return NULL;
}
/* }}} */
ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, int persistent) /* {{{ */
{
register unsigned char *p = (unsigned char*)ZSTR_VAL(str);
register unsigned char *end = p + ZSTR_LEN(str);
while (p < end) {
if (*p != zend_tolower_ascii(*p)) {
zend_string *res = zend_string_alloc(ZSTR_LEN(str), persistent);
register unsigned char *r;
if (p != (unsigned char*)ZSTR_VAL(str)) {
memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*)ZSTR_VAL(str));
}
r = p + (ZSTR_VAL(res) - ZSTR_VAL(str));
while (p < end) {
*r = zend_tolower_ascii(*p);
p++;
r++;
}
*r = '\0';
return res;
}
p++;
}
return zend_string_copy(str);
}
/* }}} */
ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
int retval;
if (s1 == s2) {
return 0;
}
retval = memcmp(s1, s2, MIN(len1, len2));
1999-04-08 02:10:10 +08:00
if (!retval) {
2014-08-16 23:31:40 +08:00
return (int)(len1 - len2);
1999-04-08 02:10:10 +08:00
} else {
return retval;
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
{
int retval;
if (s1 == s2) {
return 0;
}
retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
if (!retval) {
2014-08-16 23:31:40 +08:00
return (int)(MIN(length, len1) - MIN(length, len2));
} else {
return retval;
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
1999-06-16 06:32:51 +08:00
{
2014-08-26 01:24:55 +08:00
size_t len;
2001-08-11 23:44:24 +08:00
int c1, c2;
1999-06-16 06:32:51 +08:00
if (s1 == s2) {
return 0;
}
1999-06-16 06:32:51 +08:00
len = MIN(len1, len2);
while (len--) {
2012-07-15 12:06:40 +08:00
c1 = zend_tolower_ascii(*(unsigned char *)s1++);
c2 = zend_tolower_ascii(*(unsigned char *)s2++);
if (c1 != c2) {
return c1 - c2;
}
}
2014-08-16 23:31:40 +08:00
return (int)(len1 - len2);
}
/* }}} */
ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
{
2014-08-26 01:24:55 +08:00
size_t len;
int c1, c2;
if (s1 == s2) {
return 0;
}
len = MIN(length, MIN(len1, len2));
while (len--) {
2012-07-15 12:06:40 +08:00
c1 = zend_tolower_ascii(*(unsigned char *)s1++);
c2 = zend_tolower_ascii(*(unsigned char *)s2++);
if (c1 != c2) {
return c1 - c2;
}
}
2014-08-16 23:31:40 +08:00
return (int)(MIN(length, len1) - MIN(length, len2));
}
/* }}} */
ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
{
2014-08-26 01:24:55 +08:00
size_t len;
int c1, c2;
if (s1 == s2) {
return 0;
}
len = MIN(len1, len2);
while (len--) {
c1 = zend_tolower((int)*(unsigned char *)s1++);
c2 = zend_tolower((int)*(unsigned char *)s2++);
1999-06-16 06:32:51 +08:00
if (c1 != c2) {
return c1 - c2;
1999-06-16 06:32:51 +08:00
}
}
2014-08-16 23:31:40 +08:00
return (int)(len1 - len2);
1999-06-16 06:32:51 +08:00
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-06-16 06:32:51 +08:00
ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
{
2014-08-26 01:24:55 +08:00
size_t len;
2001-08-11 23:44:24 +08:00
int c1, c2;
if (s1 == s2) {
return 0;
}
len = MIN(length, MIN(len1, len2));
while (len--) {
c1 = zend_tolower((int)*(unsigned char *)s1++);
c2 = zend_tolower((int)*(unsigned char *)s2++);
if (c1 != c2) {
return c1 - c2;
}
}
2014-08-16 23:31:40 +08:00
return (int)(MIN(length, len1) - MIN(length, len2));
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
{
return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
{
return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
{
return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
{
return zend_binary_strncasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2) /* {{{ */
{
int ret1, ret2;
int oflow1, oflow2;
zend_long lval1 = 0, lval2 = 0;
double dval1 = 0.0, dval2 = 0.0;
if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, 0, &oflow1)) &&
(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, 0, &oflow2))) {
#if ZEND_ULONG_MAX == 0xFFFFFFFF
if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
|| (oflow1 == -1 && dval1 < -9007199254740991.))) {
#else
if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
#endif
/* both values are integers overflown to the same side, and the
* double comparison may have resulted in crucial accuracy lost */
goto string_cmp;
}
if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
if (ret1 != IS_DOUBLE) {
if (oflow2) {
/* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
return 0;
}
dval1 = (double) lval1;
} else if (ret2 != IS_DOUBLE) {
if (oflow1) {
return 0;
}
dval2 = (double) lval2;
} else if (dval1 == dval2 && !zend_finite(dval1)) {
/* Both values overflowed and have the same sign,
* so a numeric comparison would be inaccurate */
goto string_cmp;
}
return dval1 == dval2;
} else { /* they both have to be long's */
return lval1 == lval2;
}
} else {
string_cmp:
return zend_string_equal_content(s1, s2);
}
}
/* }}} */
ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2) /* {{{ */
1999-04-08 02:10:10 +08:00
{
2001-08-11 23:44:24 +08:00
int ret1, ret2;
2012-05-11 14:58:10 +08:00
int oflow1, oflow2;
2014-08-26 01:24:55 +08:00
zend_long lval1 = 0, lval2 = 0;
double dval1 = 0.0, dval2 = 0.0;
if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, 0, &oflow1)) &&
(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, 0, &oflow2))) {
2014-08-26 02:57:25 +08:00
#if ZEND_ULONG_MAX == 0xFFFFFFFF
if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
|| (oflow1 == -1 && dval1 < -9007199254740991.))) {
#else
2012-05-11 14:58:10 +08:00
if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
#endif
2012-05-11 14:58:10 +08:00
/* both values are integers overflown to the same side, and the
* double comparison may have resulted in crucial accuracy lost */
goto string_cmp;
}
2014-12-22 11:35:25 +08:00
if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
if (ret1 != IS_DOUBLE) {
2012-05-11 14:58:10 +08:00
if (oflow2) {
/* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2014-12-22 11:35:25 +08:00
return -1 * oflow2;
2012-05-11 14:58:10 +08:00
}
dval1 = (double) lval1;
2014-12-22 11:35:25 +08:00
} else if (ret2 != IS_DOUBLE) {
2012-05-11 14:58:10 +08:00
if (oflow1) {
2014-12-22 11:35:25 +08:00
return oflow1;
2012-05-11 14:58:10 +08:00
}
dval2 = (double) lval2;
} else if (dval1 == dval2 && !zend_finite(dval1)) {
/* Both values overflowed and have the same sign,
* so a numeric comparison would be inaccurate */
goto string_cmp;
1999-04-08 02:10:10 +08:00
}
2014-12-22 11:35:25 +08:00
dval1 = dval1 - dval2;
return ZEND_NORMALIZE_BOOL(dval1);
1999-04-08 02:10:10 +08:00
} else { /* they both have to be long's */
2014-12-22 11:35:25 +08:00
return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
1999-04-08 02:10:10 +08:00
}
} else {
2014-12-22 11:35:25 +08:00
int strcmp_ret;
string_cmp:
strcmp_ret = zend_binary_strcmp(s1->val, s1->len, s2->val, s2->len);
2014-12-22 11:35:25 +08:00
return ZEND_NORMALIZE_BOOL(strcmp_ret);
1999-04-08 02:10:10 +08:00
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
1999-04-08 02:10:10 +08:00
2014-12-14 06:06:14 +08:00
static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */
{
zval result;
2014-12-14 06:06:14 +08:00
if (compare_function(&result, z1, z2)==FAILURE) {
return 1;
}
2009-05-11 07:08:52 +08:00
return Z_LVAL(result);
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */
{
2014-12-14 06:06:14 +08:00
return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */
{
2014-12-22 12:16:25 +08:00
return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2));
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */
{
if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
2014-12-22 12:16:25 +08:00
return 0;
}
if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2014-12-22 12:16:25 +08:00
return 1;
} else {
2014-12-22 12:16:25 +08:00
return Z_OBJ_HT_P(o1)->compare_objects(o1, o2);
}
}
2009-05-11 07:08:52 +08:00
/* }}} */
2002-10-13 05:15:35 +08:00
ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
2002-10-13 05:15:35 +08:00
{
zend_string *str;
str = zend_strpprintf(0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
ZVAL_NEW_STR(op, str);
}
2009-05-11 07:08:52 +08:00
/* }}} */
ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */
{
if ((zend_ulong)num <= 9) {
return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
} else {
char buf[MAX_LENGTH_OF_LONG + 1];
char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
}
}
/* }}} */
ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */ {
return is_numeric_string_ex(ZSTR_VAL(str), ZSTR_LEN(str), lval, dval, -1, NULL);
}
2015-01-12 15:34:46 +08:00
/* }}} */
ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval, double *dval, int allow_errors, int *oflow_info) /* {{{ */
{
const char *ptr;
int digits = 0, dp_or_e = 0;
double local_dval = 0.0;
zend_uchar type;
zend_ulong tmp_lval = 0;
int neg = 0;
if (!length) {
return 0;
}
if (oflow_info != NULL) {
*oflow_info = 0;
}
/* Skip any whitespace
* This is much faster than the isspace() function */
while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
str++;
length--;
}
ptr = str;
if (*ptr == '-') {
neg = 1;
ptr++;
} else if (*ptr == '+') {
ptr++;
}
if (ZEND_IS_DIGIT(*ptr)) {
/* Skip any leading 0s */
while (*ptr == '0') {
ptr++;
}
/* Count the number of digits. If a decimal point/exponent is found,
* it's a double. Otherwise, if there's a dval or no need to check for
* a full match, stop when there are too many digits for a long */
for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) {
check_digits:
if (ZEND_IS_DIGIT(*ptr)) {
tmp_lval = tmp_lval * 10 + (*ptr) - '0';
continue;
} else if (*ptr == '.' && dp_or_e < 1) {
goto process_double;
} else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
const char *e = ptr + 1;
if (*e == '-' || *e == '+') {
ptr = e++;
}
if (ZEND_IS_DIGIT(*e)) {
goto process_double;
}
}
break;
}
if (digits >= MAX_LENGTH_OF_LONG) {
if (oflow_info != NULL) {
*oflow_info = *str == '-' ? -1 : 1;
}
dp_or_e = -1;
goto process_double;
}
} else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
process_double:
type = IS_DOUBLE;
/* If there's a dval, do the conversion; else continue checking
* the digits if we need to check for a full match */
if (dval) {
local_dval = zend_strtod(str, &ptr);
} else if (allow_errors != 1 && dp_or_e != -1) {
dp_or_e = (*ptr++ == '.') ? 1 : 2;
goto check_digits;
}
} else {
return 0;
}
if (ptr != str + length) {
if (!allow_errors) {
return 0;
}
if (allow_errors == -1) {
zend_error(E_NOTICE, "A non well formed numeric value encountered");
}
}
if (type == IS_LONG) {
if (digits == MAX_LENGTH_OF_LONG - 1) {
int cmp = strcmp(&ptr[-digits], long_min_digits);
if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
if (dval) {
*dval = zend_strtod(str, NULL);
}
if (oflow_info != NULL) {
*oflow_info = *str == '-' ? -1 : 1;
}
return IS_DOUBLE;
}
}
if (lval) {
if (neg) {
tmp_lval = -tmp_lval;
}
*lval = (zend_long) tmp_lval;
}
return IS_LONG;
} else {
if (dval) {
*dval = local_dval;
}
return IS_DOUBLE;
}
}
2015-01-12 15:34:46 +08:00
/* }}} */
/*
2015-01-12 17:24:37 +08:00
* String matching - Sunday algorithm
* http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
*/
static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
2015-01-12 15:34:46 +08:00
int i;
for (i = 0; i < 256; i++) {
td[i] = needle_len + 1;
}
2015-01-12 17:24:37 +08:00
if (reverse) {
for (i = needle_len - 1; i >= 0; i--) {
td[(unsigned char)needle[i]] = i + 1;
}
} else {
2016-04-29 19:44:56 +08:00
size_t i;
2015-01-12 17:24:37 +08:00
for (i = 0; i < needle_len; i++) {
td[(unsigned char)needle[i]] = (int)needle_len - i;
}
2015-01-12 15:34:46 +08:00
}
}
/* }}} */
ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
2015-01-12 15:34:46 +08:00
{
unsigned int td[256];
register size_t i;
2015-01-12 17:24:37 +08:00
register const char *p;
2015-01-12 15:34:46 +08:00
if (needle_len == 0 || (end - haystack) < needle_len) {
2015-01-12 15:34:46 +08:00
return NULL;
}
2015-01-12 17:24:37 +08:00
zend_memnstr_ex_pre(td, needle, needle_len, 0);
2015-01-12 15:34:46 +08:00
2015-01-12 17:24:37 +08:00
p = haystack;
2015-01-12 15:34:46 +08:00
end -= needle_len;
2015-01-12 17:24:37 +08:00
while (p <= end) {
2015-01-12 15:34:46 +08:00
for (i = 0; i < needle_len; i++) {
if (needle[i] != p[i]) {
break;
}
}
if (i == needle_len) {
2015-01-12 17:24:37 +08:00
return p;
2015-01-12 15:34:46 +08:00
}
if (UNEXPECTED(p == end)) {
return NULL;
}
2015-01-12 17:24:37 +08:00
p += td[(unsigned char)(p[needle_len])];
2015-01-12 15:34:46 +08:00
}
return NULL;
}
/* }}} */
ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
2015-01-12 17:24:37 +08:00
{
unsigned int td[256];
register size_t i;
register const char *p;
if (needle_len == 0 || (end - haystack) < needle_len) {
2015-01-12 17:24:37 +08:00
return NULL;
}
zend_memnstr_ex_pre(td, needle, needle_len, 1);
p = end;
p -= needle_len;
while (p >= haystack) {
for (i = 0; i < needle_len; i++) {
if (needle[i] != p[i]) {
break;
}
}
if (i == needle_len) {
return (const char *)p;
}
2015-01-13 11:06:40 +08:00
if (UNEXPECTED(p == haystack)) {
2015-01-12 17:24:37 +08:00
return NULL;
}
p -= td[(unsigned char)(p[-1])];
}
return NULL;
}
/* }}} */
2015-02-26 06:28:47 +08:00
#if !ZEND_DVAL_TO_LVAL_CAST_OK
# if SIZEOF_ZEND_LONG == 4
ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
2015-02-26 06:28:47 +08:00
{
double two_pow_32 = pow(2., 32.),
dmod;
dmod = fmod(d, two_pow_32);
if (dmod < 0) {
/* we're going to make this number positive; call ceil()
* to simulate rounding towards 0 of the negative number */
2018-08-29 15:10:59 +08:00
dmod = ceil(dmod) + two_pow_32;
2015-02-26 06:28:47 +08:00
}
return (zend_long)(zend_ulong)dmod;
}
#else
ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
2015-02-26 06:28:47 +08:00
{
double two_pow_64 = pow(2., 64.),
dmod;
dmod = fmod(d, two_pow_64);
if (dmod < 0) {
/* no need to call ceil; original double must have had no
* fractional part, hence dmod does not have one either */
dmod += two_pow_64;
}
return (zend_long)(zend_ulong)dmod;
}
#endif
#endif