xref: /PHP-8.4/Zend/zend_operators.c (revision 58aa6fc8)
1 /*
2    +----------------------------------------------------------------------+
3    | Zend Engine                                                          |
4    +----------------------------------------------------------------------+
5    | Copyright (c) Zend Technologies Ltd. (http://www.zend.com)           |
6    +----------------------------------------------------------------------+
7    | This source file is subject to version 2.00 of the Zend license,     |
8    | that is bundled with this package in the file LICENSE, and is        |
9    | available through the world-wide-web at the following url:           |
10    | http://www.zend.com/license/2_00.txt.                                |
11    | If you did not receive a copy of the Zend license and are unable to  |
12    | obtain it through the world-wide-web, please send a note to          |
13    | license@zend.com so we can mail you a copy immediately.              |
14    +----------------------------------------------------------------------+
15    | Authors: Andi Gutmans <andi@php.net>                                 |
16    |          Zeev Suraski <zeev@php.net>                                 |
17    |          Dmitry Stogov <dmitry@php.net>                              |
18    +----------------------------------------------------------------------+
19 */
20 
21 #include <ctype.h>
22 
23 #include "zend.h"
24 #include "zend_operators.h"
25 #include "zend_variables.h"
26 #include "zend_globals.h"
27 #include "zend_list.h"
28 #include "zend_API.h"
29 #include "zend_strtod.h"
30 #include "zend_exceptions.h"
31 #include "zend_closures.h"
32 
33 #include <locale.h>
34 #ifdef HAVE_LANGINFO_H
35 # include <langinfo.h>
36 #endif
37 
38 #ifdef ZEND_INTRIN_AVX2_NATIVE
39 #include <immintrin.h>
40 #endif
41 #ifdef __SSE2__
42 #include <emmintrin.h>
43 #endif
44 #if defined(__aarch64__) || defined(_M_ARM64)
45 #include <arm_neon.h>
46 #endif
47 
48 #if defined(ZEND_WIN32) && !defined(ZTS) && defined(_MSC_VER)
49 /* This performance improvement of tolower() on Windows gives 10-18% on bench.php */
50 #define ZEND_USE_TOLOWER_L 1
51 #endif
52 
53 #ifdef ZEND_USE_TOLOWER_L
54 static _locale_t current_locale = NULL;
55 /* this is true global! may lead to strange effects on ZTS, but so may setlocale() */
56 #define zend_tolower(c) _tolower_l(c, current_locale)
57 #else
58 #define zend_tolower(c) tolower(c)
59 #endif
60 
61 #define TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
62 
63 #ifdef ZEND_INTRIN_AVX2_NATIVE
64 #define HAVE_BLOCKCONV
65 
66 #define BLOCKCONV_INIT_RANGE(start, end) \
67 	const __m256i blconv_offset = _mm256_set1_epi8((signed char)(SCHAR_MIN - start)); \
68 	const __m256i blconv_threshold = _mm256_set1_epi8(SCHAR_MIN + (end - start) + 1);
69 
70 #define BLOCKCONV_STRIDE sizeof(__m256i)
71 
72 #define BLOCKCONV_INIT_DELTA(delta) \
73 	const __m256i blconv_delta = _mm256_set1_epi8(delta);
74 
75 #define BLOCKCONV_LOAD(input) \
76 	__m256i blconv_operand = _mm256_loadu_si256((__m256i*)(input)); \
77 	__m256i blconv_mask = _mm256_cmpgt_epi8(blconv_threshold, _mm256_add_epi8(blconv_operand, blconv_offset));
78 
79 #define BLOCKCONV_FOUND() _mm256_movemask_epi8(blconv_mask)
80 
81 #define BLOCKCONV_STORE(dest) \
82 	__m256i blconv_add = _mm256_and_si256(blconv_mask, blconv_delta); \
83 	__m256i blconv_result = _mm256_add_epi8(blconv_operand, blconv_add); \
84 	_mm256_storeu_si256((__m256i*)(dest), blconv_result);
85 
86 #elif __SSE2__
87 #define HAVE_BLOCKCONV
88 
89 /* Common code for SSE2 accelerated character case conversion */
90 
91 #define BLOCKCONV_INIT_RANGE(start, end) \
92 	const __m128i blconv_offset = _mm_set1_epi8((signed char)(SCHAR_MIN - start)); \
93 	const __m128i blconv_threshold = _mm_set1_epi8(SCHAR_MIN + (end - start) + 1);
94 
95 #define BLOCKCONV_STRIDE sizeof(__m128i)
96 
97 #define BLOCKCONV_INIT_DELTA(delta) \
98 	const __m128i blconv_delta = _mm_set1_epi8(delta);
99 
100 #define BLOCKCONV_LOAD(input) \
101 	__m128i blconv_operand = _mm_loadu_si128((__m128i*)(input)); \
102 	__m128i blconv_mask = _mm_cmplt_epi8(_mm_add_epi8(blconv_operand, blconv_offset), blconv_threshold);
103 
104 #define BLOCKCONV_FOUND() _mm_movemask_epi8(blconv_mask)
105 
106 #define BLOCKCONV_STORE(dest) \
107 	__m128i blconv_add = _mm_and_si128(blconv_mask, blconv_delta); \
108 	__m128i blconv_result = _mm_add_epi8(blconv_operand, blconv_add); \
109 	_mm_storeu_si128((__m128i *)(dest), blconv_result);
110 
111 #elif defined(__aarch64__) || defined(_M_ARM64)
112 #define HAVE_BLOCKCONV
113 
114 #define BLOCKCONV_INIT_RANGE(start, end) \
115 	const int8x16_t blconv_offset = vdupq_n_s8((signed char)(SCHAR_MIN - start)); \
116 	const int8x16_t blconv_threshold = vdupq_n_s8(SCHAR_MIN + (end - start) + 1);
117 
118 #define BLOCKCONV_STRIDE sizeof(int8x16_t)
119 
120 #define BLOCKCONV_INIT_DELTA(delta) \
121 	const int8x16_t blconv_delta = vdupq_n_s8(delta);
122 
123 #define BLOCKCONV_LOAD(input) \
124 	int8x16_t blconv_operand = vld1q_s8((const int8_t*)(input)); \
125 	uint8x16_t blconv_mask = vcltq_s8(vreinterpretq_s8_u8(vaddq_u8(vreinterpretq_u8_s8(blconv_operand), vreinterpretq_u8_s8(blconv_offset))), blconv_threshold);
126 
127 #define BLOCKCONV_FOUND() vmaxvq_u8(blconv_mask)
128 
129 #define BLOCKCONV_STORE(dest) \
130 	int8x16_t blconv_add = vandq_s8(vreinterpretq_s8_u8(blconv_mask), blconv_delta); \
131 	int8x16_t blconv_result = vaddq_s8(blconv_operand, blconv_add); \
132 	vst1q_s8((int8_t *)(dest), blconv_result);
133 
134 #endif /* defined(__aarch64__) || defined(_M_ARM64) */
135 
136 ZEND_API const unsigned char zend_tolower_map[256] = {
137 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
138 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
139 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
140 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
141 0x40,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
142 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x5b,0x5c,0x5d,0x5e,0x5f,
143 0x60,0x61,0x62,0x63,0x64,0x65,0x66,0x67,0x68,0x69,0x6a,0x6b,0x6c,0x6d,0x6e,0x6f,
144 0x70,0x71,0x72,0x73,0x74,0x75,0x76,0x77,0x78,0x79,0x7a,0x7b,0x7c,0x7d,0x7e,0x7f,
145 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
146 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
147 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
148 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
149 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
150 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
151 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
152 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
153 };
154 
155 ZEND_API const unsigned char zend_toupper_map[256] = {
156 0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07,0x08,0x09,0x0a,0x0b,0x0c,0x0d,0x0e,0x0f,
157 0x10,0x11,0x12,0x13,0x14,0x15,0x16,0x17,0x18,0x19,0x1a,0x1b,0x1c,0x1d,0x1e,0x1f,
158 0x20,0x21,0x22,0x23,0x24,0x25,0x26,0x27,0x28,0x29,0x2a,0x2b,0x2c,0x2d,0x2e,0x2f,
159 0x30,0x31,0x32,0x33,0x34,0x35,0x36,0x37,0x38,0x39,0x3a,0x3b,0x3c,0x3d,0x3e,0x3f,
160 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
161 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x5b,0x5c,0x5d,0x5e,0x5f,
162 0x60,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x48,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,
163 0x50,0x51,0x52,0x53,0x54,0x55,0x56,0x57,0x58,0x59,0x5a,0x7b,0x7c,0x7d,0x7e,0x7f,
164 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8a,0x8b,0x8c,0x8d,0x8e,0x8f,
165 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9a,0x9b,0x9c,0x9d,0x9e,0x9f,
166 0xa0,0xa1,0xa2,0xa3,0xa4,0xa5,0xa6,0xa7,0xa8,0xa9,0xaa,0xab,0xac,0xad,0xae,0xaf,
167 0xb0,0xb1,0xb2,0xb3,0xb4,0xb5,0xb6,0xb7,0xb8,0xb9,0xba,0xbb,0xbc,0xbd,0xbe,0xbf,
168 0xc0,0xc1,0xc2,0xc3,0xc4,0xc5,0xc6,0xc7,0xc8,0xc9,0xca,0xcb,0xcc,0xcd,0xce,0xcf,
169 0xd0,0xd1,0xd2,0xd3,0xd4,0xd5,0xd6,0xd7,0xd8,0xd9,0xda,0xdb,0xdc,0xdd,0xde,0xdf,
170 0xe0,0xe1,0xe2,0xe3,0xe4,0xe5,0xe6,0xe7,0xe8,0xe9,0xea,0xeb,0xec,0xed,0xee,0xef,
171 0xf0,0xf1,0xf2,0xf3,0xf4,0xf5,0xf6,0xf7,0xf8,0xf9,0xfa,0xfb,0xfc,0xfd,0xfe,0xff
172 };
173 
174 
175 /**
176  * Functions using locale lowercase:
177  	 	zend_binary_strncasecmp_l
178  	 	zend_binary_strcasecmp_l
179  * Functions using ascii lowercase:
180 		string_compare_function_ex
181 		string_case_compare_function
182   		zend_str_tolower_copy
183 		zend_str_tolower_dup
184 		zend_str_tolower
185 		zend_binary_strcasecmp
186 		zend_binary_strncasecmp
187  */
188 
zend_atol_internal(const char * str,size_t str_len)189 static zend_long ZEND_FASTCALL zend_atol_internal(const char *str, size_t str_len) /* {{{ */
190 {
191 	if (!str_len) {
192 		str_len = strlen(str);
193 	}
194 
195 	/* Perform following multiplications on unsigned to avoid overflow UB.
196 	 * For now overflow is silently ignored -- not clear what else can be
197 	 * done here, especially as the final result of this function may be
198 	 * used in an unsigned context (e.g. "memory_limit=3G", which overflows
199 	 * zend_long on 32-bit, but not size_t). */
200 	zend_ulong retval = (zend_ulong) ZEND_STRTOL(str, NULL, 0);
201 	if (str_len>0) {
202 		switch (str[str_len-1]) {
203 			case 'g':
204 			case 'G':
205 				retval *= 1024;
206 				ZEND_FALLTHROUGH;
207 			case 'm':
208 			case 'M':
209 				retval *= 1024;
210 				ZEND_FALLTHROUGH;
211 			case 'k':
212 			case 'K':
213 				retval *= 1024;
214 				break;
215 		}
216 	}
217 	return (zend_long) retval;
218 }
219 /* }}} */
220 
zend_atol(const char * str,size_t str_len)221 ZEND_API zend_long ZEND_FASTCALL zend_atol(const char *str, size_t str_len)
222 {
223 	return zend_atol_internal(str, str_len);
224 }
225 
zend_atoi(const char * str,size_t str_len)226 ZEND_API int ZEND_FASTCALL zend_atoi(const char *str, size_t str_len)
227 {
228 	return (int) zend_atol_internal(str, str_len);
229 }
230 
231 /* {{{ convert_object_to_type: dst will be either ctype or UNDEF */
232 #define convert_object_to_type(op, dst, ctype)									\
233 	ZVAL_UNDEF(dst);																		\
234 	if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), dst, ctype) == FAILURE) {					\
235 		zend_error(E_WARNING,																\
236 			"Object of class %s could not be converted to %s", ZSTR_VAL(Z_OBJCE_P(op)->name),\
237 		zend_get_type_by_const(ctype));														\
238 	} 																						\
239 
240 /* }}} */
241 
convert_scalar_to_number(zval * op)242 ZEND_API void ZEND_FASTCALL convert_scalar_to_number(zval *op) /* {{{ */
243 {
244 try_again:
245 	switch (Z_TYPE_P(op)) {
246 		case IS_REFERENCE:
247 			zend_unwrap_reference(op);
248 			goto try_again;
249 		case IS_STRING:
250 			{
251 				zend_string *str;
252 
253 				str = Z_STR_P(op);
254 				if ((Z_TYPE_INFO_P(op)=is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &Z_LVAL_P(op), &Z_DVAL_P(op), 1)) == 0) {
255 					ZVAL_LONG(op, 0);
256 				}
257 				zend_string_release_ex(str, 0);
258 				break;
259 			}
260 		case IS_NULL:
261 		case IS_FALSE:
262 			ZVAL_LONG(op, 0);
263 			break;
264 		case IS_TRUE:
265 			ZVAL_LONG(op, 1);
266 			break;
267 		case IS_RESOURCE:
268 			{
269 				zend_long l = Z_RES_HANDLE_P(op);
270 				zval_ptr_dtor(op);
271 				ZVAL_LONG(op, l);
272 			}
273 			break;
274 		case IS_OBJECT:
275 			{
276 				zval dst;
277 
278 				convert_object_to_type(op, &dst, _IS_NUMBER);
279 				zval_ptr_dtor(op);
280 
281 				if (Z_TYPE(dst) == IS_LONG || Z_TYPE(dst) == IS_DOUBLE) {
282 					ZVAL_COPY_VALUE(op, &dst);
283 				} else {
284 					ZVAL_LONG(op, 1);
285 				}
286 			}
287 			break;
288 	}
289 }
290 /* }}} */
291 
_zendi_convert_scalar_to_number_silent(zval * op,zval * holder)292 static zend_never_inline zval* ZEND_FASTCALL _zendi_convert_scalar_to_number_silent(zval *op, zval *holder) /* {{{ */
293 {
294 	switch (Z_TYPE_P(op)) {
295 		case IS_NULL:
296 		case IS_FALSE:
297 			ZVAL_LONG(holder, 0);
298 			return holder;
299 		case IS_TRUE:
300 			ZVAL_LONG(holder, 1);
301 			return holder;
302 		case IS_STRING:
303 			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), 1)) == 0) {
304 				ZVAL_LONG(holder, 0);
305 			}
306 			return holder;
307 		case IS_RESOURCE:
308 			ZVAL_LONG(holder, Z_RES_HANDLE_P(op));
309 			return holder;
310 		case IS_OBJECT:
311 			convert_object_to_type(op, holder, _IS_NUMBER);
312 			if (UNEXPECTED(EG(exception)) ||
313 			    UNEXPECTED(Z_TYPE_P(holder) != IS_LONG && Z_TYPE_P(holder) != IS_DOUBLE)) {
314 				ZVAL_LONG(holder, 1);
315 			}
316 			return holder;
317 		case IS_LONG:
318 		case IS_DOUBLE:
319 		default:
320 			return op;
321 	}
322 }
323 /* }}} */
324 
_zendi_try_convert_scalar_to_number(zval * op,zval * holder)325 static zend_never_inline zend_result ZEND_FASTCALL _zendi_try_convert_scalar_to_number(zval *op, zval *holder) /* {{{ */
326 {
327 	switch (Z_TYPE_P(op)) {
328 		case IS_NULL:
329 		case IS_FALSE:
330 			ZVAL_LONG(holder, 0);
331 			return SUCCESS;
332 		case IS_TRUE:
333 			ZVAL_LONG(holder, 1);
334 			return SUCCESS;
335 		case IS_STRING:
336 		{
337 			bool trailing_data = false;
338 			/* For BC reasons we allow errors so that we can warn on leading numeric string */
339 			if (0 == (Z_TYPE_INFO_P(holder) = is_numeric_string_ex(Z_STRVAL_P(op), Z_STRLEN_P(op),
340 					&Z_LVAL_P(holder), &Z_DVAL_P(holder),  /* allow errors */ true, NULL, &trailing_data))) {
341 				/* Will lead to invalid OP type error */
342 				return FAILURE;
343 			}
344 			if (UNEXPECTED(trailing_data)) {
345 				zend_error(E_WARNING, "A non-numeric value encountered");
346 				if (UNEXPECTED(EG(exception))) {
347 					return FAILURE;
348 				}
349 			}
350 			return SUCCESS;
351 		}
352 		case IS_OBJECT:
353 			if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), holder, _IS_NUMBER) == FAILURE
354 					|| EG(exception)) {
355 				return FAILURE;
356 			}
357 			ZEND_ASSERT(Z_TYPE_P(holder) == IS_LONG || Z_TYPE_P(holder) == IS_DOUBLE);
358 			return SUCCESS;
359 		case IS_RESOURCE:
360 		case IS_ARRAY:
361 			return FAILURE;
362 		EMPTY_SWITCH_DEFAULT_CASE()
363 	}
364 }
365 /* }}} */
366 
zendi_try_convert_scalar_to_number(zval * op,zval * holder)367 static zend_always_inline zend_result zendi_try_convert_scalar_to_number(zval *op, zval *holder) /* {{{ */
368 {
369 	if (Z_TYPE_P(op) == IS_LONG || Z_TYPE_P(op) == IS_DOUBLE) {
370 		ZVAL_COPY_VALUE(holder, op);
371 		return SUCCESS;
372 	} else {
373 		return _zendi_try_convert_scalar_to_number(op, holder);
374 	}
375 }
376 /* }}} */
377 
zendi_try_get_long(const zval * op,bool * failed)378 static zend_never_inline zend_long ZEND_FASTCALL zendi_try_get_long(const zval *op, bool *failed) /* {{{ */
379 {
380 	*failed = 0;
381 	switch (Z_TYPE_P(op)) {
382 		case IS_NULL:
383 		case IS_FALSE:
384 			return 0;
385 		case IS_TRUE:
386 			return 1;
387 		case IS_DOUBLE: {
388 			double dval = Z_DVAL_P(op);
389 			zend_long lval = zend_dval_to_lval(dval);
390 			if (!zend_is_long_compatible(dval, lval)) {
391 				zend_incompatible_double_to_long_error(dval);
392 				if (UNEXPECTED(EG(exception))) {
393 					*failed = 1;
394 				}
395 			}
396 			return lval;
397 		}
398 		case IS_STRING:
399 			{
400 				uint8_t type;
401 				zend_long lval;
402 				double dval;
403 				bool trailing_data = false;
404 
405 				/* For BC reasons we allow errors so that we can warn on leading numeric string */
406 				type = is_numeric_string_ex(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval,
407 					/* allow errors */ true, NULL, &trailing_data);
408 				if (type == 0) {
409 					*failed = 1;
410 					return 0;
411 				}
412 				if (UNEXPECTED(trailing_data)) {
413 					zend_error(E_WARNING, "A non-numeric value encountered");
414 					if (UNEXPECTED(EG(exception))) {
415 						*failed = 1;
416 					}
417 				}
418 				if (EXPECTED(type == IS_LONG)) {
419 					return lval;
420 				} else {
421 					/* Previously we used strtol here, not is_numeric_string,
422 					 * and strtol gives you LONG_MAX/_MIN on overflow.
423 					 * We use use saturating conversion to emulate strtol()'s
424 					 * behaviour.
425 					 */
426 					lval = zend_dval_to_lval_cap(dval);
427 					if (!zend_is_long_compatible(dval, lval)) {
428 						zend_incompatible_string_to_long_error(Z_STR_P(op));
429 						if (UNEXPECTED(EG(exception))) {
430 							*failed = 1;
431 						}
432 					}
433 					return lval;
434 				}
435 			}
436 		case IS_OBJECT:
437 			{
438 				zval dst;
439 				if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &dst, IS_LONG) == FAILURE
440 						|| EG(exception)) {
441 					*failed = 1;
442 					return 0;
443 				}
444 				ZEND_ASSERT(Z_TYPE(dst) == IS_LONG);
445 				return Z_LVAL(dst);
446 			}
447 		case IS_RESOURCE:
448 		case IS_ARRAY:
449 			*failed = 1;
450 			return 0;
451 		EMPTY_SWITCH_DEFAULT_CASE()
452 	}
453 }
454 /* }}} */
455 
zval_try_get_long(const zval * op,bool * failed)456 ZEND_API zend_long ZEND_FASTCALL zval_try_get_long(const zval *op, bool *failed)
457 {
458 	if (EXPECTED(Z_TYPE_P(op) == IS_LONG)) {
459 		*failed = false;
460 		return Z_LVAL_P(op);
461 	}
462 	return zendi_try_get_long(op, failed);
463 }
464 
465 #define ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode) \
466 	if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT) \
467 		&& UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation))) { \
468 		if (EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, op2))) { \
469 			return SUCCESS; \
470 		} \
471 	}
472 
473 #define ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode) \
474 	if (UNEXPECTED(Z_TYPE_P(op2) == IS_OBJECT) \
475 		&& UNEXPECTED(Z_OBJ_HANDLER_P(op2, do_operation)) \
476 		&& EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op2, do_operation)(opcode, result, op1, op2))) { \
477 		return SUCCESS; \
478 	}
479 
480 #define ZEND_TRY_BINARY_OBJECT_OPERATION(opcode) \
481 	ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode) \
482 	else \
483 	ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode)
484 
485 #define ZEND_TRY_UNARY_OBJECT_OPERATION(opcode) \
486 	if (UNEXPECTED(Z_TYPE_P(op1) == IS_OBJECT) \
487 		&& UNEXPECTED(Z_OBJ_HANDLER_P(op1, do_operation)) \
488 		&& EXPECTED(SUCCESS == Z_OBJ_HANDLER_P(op1, do_operation)(opcode, result, op1, NULL))) { \
489 		return SUCCESS; \
490 	}
491 
492 #define convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, opcode, sigil) \
493 	do {																\
494 		if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {						\
495 			bool failed;											\
496 			if (Z_ISREF_P(op1)) {										\
497 				op1 = Z_REFVAL_P(op1);									\
498 				if (Z_TYPE_P(op1) == IS_LONG) {							\
499 					op1_lval = Z_LVAL_P(op1);							\
500 					break;												\
501 				}														\
502 			}															\
503 			ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(opcode);				\
504 			op1_lval = zendi_try_get_long(op1, &failed);				\
505 			if (UNEXPECTED(failed)) {									\
506 				zend_binop_error(sigil, op1, op2);						\
507 				if (result != op1) {									\
508 					ZVAL_UNDEF(result);									\
509 				}														\
510 				return FAILURE;											\
511 			}															\
512 		} else {														\
513 			op1_lval = Z_LVAL_P(op1);									\
514 		}																\
515 	} while (0);														\
516 	do {																\
517 		if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {						\
518 			bool failed;											\
519 			if (Z_ISREF_P(op2)) {										\
520 				op2 = Z_REFVAL_P(op2);									\
521 				if (Z_TYPE_P(op2) == IS_LONG) {							\
522 					op2_lval = Z_LVAL_P(op2);							\
523 					break;												\
524 				}														\
525 			}															\
526 			ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(opcode);				\
527 			op2_lval = zendi_try_get_long(op2, &failed);				\
528 			if (UNEXPECTED(failed)) {									\
529 				zend_binop_error(sigil, op1, op2);						\
530 				if (result != op1) {									\
531 					ZVAL_UNDEF(result);									\
532 				}														\
533 				return FAILURE;											\
534 			}															\
535 		} else {														\
536 			op2_lval = Z_LVAL_P(op2);									\
537 		}																\
538 	} while (0);
539 
convert_to_long(zval * op)540 ZEND_API void ZEND_FASTCALL convert_to_long(zval *op) /* {{{ */
541 {
542 	zend_long tmp;
543 
544 try_again:
545 	switch (Z_TYPE_P(op)) {
546 		case IS_NULL:
547 		case IS_FALSE:
548 			ZVAL_LONG(op, 0);
549 			break;
550 		case IS_TRUE:
551 			ZVAL_LONG(op, 1);
552 			break;
553 		case IS_RESOURCE:
554 			tmp = Z_RES_HANDLE_P(op);
555 			zval_ptr_dtor(op);
556 			ZVAL_LONG(op, tmp);
557 			break;
558 		case IS_LONG:
559 			break;
560 		case IS_DOUBLE:
561 			ZVAL_LONG(op, zend_dval_to_lval(Z_DVAL_P(op)));
562 			break;
563 		case IS_STRING:
564 			{
565 				zend_string *str = Z_STR_P(op);
566 				ZVAL_LONG(op, zval_get_long(op));
567 				zend_string_release_ex(str, 0);
568 			}
569 			break;
570 		case IS_ARRAY:
571 			tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
572 			zval_ptr_dtor(op);
573 			ZVAL_LONG(op, tmp);
574 			break;
575 		case IS_OBJECT:
576 			{
577 				zval dst;
578 
579 				convert_object_to_type(op, &dst, IS_LONG);
580 				zval_ptr_dtor(op);
581 
582 				if (Z_TYPE(dst) == IS_LONG) {
583 					ZVAL_LONG(op, Z_LVAL(dst));
584 				} else {
585 					ZVAL_LONG(op, 1);
586 				}
587 				return;
588 			}
589 		case IS_REFERENCE:
590 			zend_unwrap_reference(op);
591 			goto try_again;
592 		EMPTY_SWITCH_DEFAULT_CASE()
593 	}
594 }
595 /* }}} */
596 
convert_to_double(zval * op)597 ZEND_API void ZEND_FASTCALL convert_to_double(zval *op) /* {{{ */
598 {
599 	double tmp;
600 
601 try_again:
602 	switch (Z_TYPE_P(op)) {
603 		case IS_NULL:
604 		case IS_FALSE:
605 			ZVAL_DOUBLE(op, 0.0);
606 			break;
607 		case IS_TRUE:
608 			ZVAL_DOUBLE(op, 1.0);
609 			break;
610 		case IS_RESOURCE: {
611 				double d = (double) Z_RES_HANDLE_P(op);
612 				zval_ptr_dtor(op);
613 				ZVAL_DOUBLE(op, d);
614 			}
615 			break;
616 		case IS_LONG:
617 			ZVAL_DOUBLE(op, (double) Z_LVAL_P(op));
618 			break;
619 		case IS_DOUBLE:
620 			break;
621 		case IS_STRING:
622 			{
623 				zend_string *str = Z_STR_P(op);
624 
625 				ZVAL_DOUBLE(op, zend_strtod(ZSTR_VAL(str), NULL));
626 				zend_string_release_ex(str, 0);
627 			}
628 			break;
629 		case IS_ARRAY:
630 			tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
631 			zval_ptr_dtor(op);
632 			ZVAL_DOUBLE(op, tmp);
633 			break;
634 		case IS_OBJECT:
635 			{
636 				zval dst;
637 
638 				convert_object_to_type(op, &dst, IS_DOUBLE);
639 				zval_ptr_dtor(op);
640 
641 				if (Z_TYPE(dst) == IS_DOUBLE) {
642 					ZVAL_DOUBLE(op, Z_DVAL(dst));
643 				} else {
644 					ZVAL_DOUBLE(op, 1.0);
645 				}
646 				break;
647 			}
648 		case IS_REFERENCE:
649 			zend_unwrap_reference(op);
650 			goto try_again;
651 		EMPTY_SWITCH_DEFAULT_CASE()
652 	}
653 }
654 /* }}} */
655 
convert_to_null(zval * op)656 ZEND_API void ZEND_FASTCALL convert_to_null(zval *op) /* {{{ */
657 {
658 	zval_ptr_dtor(op);
659 	ZVAL_NULL(op);
660 }
661 /* }}} */
662 
convert_to_boolean(zval * op)663 ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op) /* {{{ */
664 {
665 	bool tmp;
666 
667 try_again:
668 	switch (Z_TYPE_P(op)) {
669 		case IS_FALSE:
670 		case IS_TRUE:
671 			break;
672 		case IS_NULL:
673 			ZVAL_FALSE(op);
674 			break;
675 		case IS_RESOURCE: {
676 				zend_long l = (Z_RES_HANDLE_P(op) ? 1 : 0);
677 
678 				zval_ptr_dtor(op);
679 				ZVAL_BOOL(op, l);
680 			}
681 			break;
682 		case IS_LONG:
683 			ZVAL_BOOL(op, Z_LVAL_P(op) ? 1 : 0);
684 			break;
685 		case IS_DOUBLE:
686 			ZVAL_BOOL(op, Z_DVAL_P(op) ? 1 : 0);
687 			break;
688 		case IS_STRING:
689 			{
690 				zend_string *str = Z_STR_P(op);
691 
692 				if (ZSTR_LEN(str) == 0
693 					|| (ZSTR_LEN(str) == 1 && ZSTR_VAL(str)[0] == '0')) {
694 					ZVAL_FALSE(op);
695 				} else {
696 					ZVAL_TRUE(op);
697 				}
698 				zend_string_release_ex(str, 0);
699 			}
700 			break;
701 		case IS_ARRAY:
702 			tmp = (zend_hash_num_elements(Z_ARRVAL_P(op))?1:0);
703 			zval_ptr_dtor(op);
704 			ZVAL_BOOL(op, tmp);
705 			break;
706 		case IS_OBJECT:
707 			{
708 				zval dst;
709 
710 				convert_object_to_type(op, &dst, _IS_BOOL);
711 				zval_ptr_dtor(op);
712 
713 				if (Z_TYPE_INFO(dst) == IS_FALSE || Z_TYPE_INFO(dst) == IS_TRUE) {
714 					Z_TYPE_INFO_P(op) = Z_TYPE_INFO(dst);
715 				} else {
716 					ZVAL_TRUE(op);
717 				}
718 				break;
719 			}
720 		case IS_REFERENCE:
721 			zend_unwrap_reference(op);
722 			goto try_again;
723 		EMPTY_SWITCH_DEFAULT_CASE()
724 	}
725 }
726 /* }}} */
727 
_convert_to_string(zval * op)728 ZEND_API void ZEND_FASTCALL _convert_to_string(zval *op) /* {{{ */
729 {
730 try_again:
731 	switch (Z_TYPE_P(op)) {
732 		case IS_UNDEF:
733 		case IS_NULL:
734 		case IS_FALSE: {
735 			ZVAL_EMPTY_STRING(op);
736 			break;
737 		}
738 		case IS_TRUE:
739 			ZVAL_CHAR(op, '1');
740 			break;
741 		case IS_STRING:
742 			break;
743 		case IS_RESOURCE: {
744 			zend_string *str = zend_strpprintf(0, "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
745 			zval_ptr_dtor(op);
746 			ZVAL_NEW_STR(op, str);
747 			break;
748 		}
749 		case IS_LONG:
750 			ZVAL_STR(op, zend_long_to_str(Z_LVAL_P(op)));
751 			break;
752 		case IS_DOUBLE:
753 			ZVAL_NEW_STR(op, zend_double_to_str(Z_DVAL_P(op)));
754 			break;
755 		case IS_ARRAY:
756 			zend_error(E_WARNING, "Array to string conversion");
757 			zval_ptr_dtor(op);
758 			ZVAL_INTERNED_STR(op, ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED));
759 			break;
760 		case IS_OBJECT: {
761 			zval tmp;
762 			if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &tmp, IS_STRING) == SUCCESS) {
763 				zval_ptr_dtor(op);
764 				ZVAL_COPY_VALUE(op, &tmp);
765 				return;
766 			}
767 			if (!EG(exception)) {
768 				zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
769 			}
770 			zval_ptr_dtor(op);
771 			ZVAL_EMPTY_STRING(op);
772 			break;
773 		}
774 		case IS_REFERENCE:
775 			zend_unwrap_reference(op);
776 			goto try_again;
777 		EMPTY_SWITCH_DEFAULT_CASE()
778 	}
779 }
780 /* }}} */
781 
_try_convert_to_string(zval * op)782 ZEND_API bool ZEND_FASTCALL _try_convert_to_string(zval *op) /* {{{ */
783 {
784 	zend_string *str;
785 
786 	ZEND_ASSERT(Z_TYPE_P(op) != IS_STRING);
787 	str = zval_try_get_string_func(op);
788 	if (UNEXPECTED(!str)) {
789 		return 0;
790 	}
791 	zval_ptr_dtor(op);
792 	ZVAL_STR(op, str);
793 	return 1;
794 }
795 /* }}} */
796 
convert_scalar_to_array(zval * op)797 static void convert_scalar_to_array(zval *op) /* {{{ */
798 {
799 	HashTable *ht = zend_new_array(1);
800 	zend_hash_index_add_new(ht, 0, op);
801 	ZVAL_ARR(op, ht);
802 }
803 /* }}} */
804 
convert_to_array(zval * op)805 ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
806 {
807 try_again:
808 	switch (Z_TYPE_P(op)) {
809 		case IS_ARRAY:
810 			break;
811 /* OBJECTS_OPTIMIZE */
812 		case IS_OBJECT:
813 			if (Z_OBJCE_P(op) == zend_ce_closure) {
814 				convert_scalar_to_array(op);
815 			} else if (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(op)) {
816 				/* Optimized version without rebuilding properties HashTable */
817 				HashTable *ht = zend_std_build_object_properties_array(Z_OBJ_P(op));
818 				OBJ_RELEASE(Z_OBJ_P(op));
819 				ZVAL_ARR(op, ht);
820 			} else {
821 				HashTable *obj_ht = zend_get_properties_for(op, ZEND_PROP_PURPOSE_ARRAY_CAST);
822 				if (obj_ht) {
823 					HashTable *new_obj_ht = zend_proptable_to_symtable(obj_ht,
824 						(Z_OBJCE_P(op)->default_properties_count ||
825 						 Z_OBJ_P(op)->handlers != &std_object_handlers ||
826 						 GC_IS_RECURSIVE(obj_ht)));
827 					zval_ptr_dtor(op);
828 					ZVAL_ARR(op, new_obj_ht);
829 					zend_release_properties(obj_ht);
830 				} else {
831 					zval_ptr_dtor(op);
832 					/*ZVAL_EMPTY_ARRAY(op);*/
833 					array_init(op);
834 				}
835 			}
836 			break;
837 		case IS_NULL:
838 			/*ZVAL_EMPTY_ARRAY(op);*/
839 			array_init(op);
840 			break;
841 		case IS_REFERENCE:
842 			zend_unwrap_reference(op);
843 			goto try_again;
844 		default:
845 			convert_scalar_to_array(op);
846 			break;
847 	}
848 }
849 /* }}} */
850 
convert_to_object(zval * op)851 ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
852 {
853 try_again:
854 	switch (Z_TYPE_P(op)) {
855 		case IS_ARRAY:
856 			{
857 				HashTable *ht = zend_symtable_to_proptable(Z_ARR_P(op));
858 				zend_object *obj;
859 
860 				if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) {
861 					/* TODO: try not to duplicate immutable arrays as well ??? */
862 					ht = zend_array_dup(ht);
863 				} else if (ht != Z_ARR_P(op)) {
864 					zval_ptr_dtor(op);
865 				} else {
866 					GC_DELREF(ht);
867 				}
868 				obj = zend_objects_new(zend_standard_class_def);
869 				obj->properties = ht;
870 				ZVAL_OBJ(op, obj);
871 				break;
872 			}
873 		case IS_OBJECT:
874 			break;
875 		case IS_NULL:
876 			object_init(op);
877 			break;
878 		case IS_REFERENCE:
879 			zend_unwrap_reference(op);
880 			goto try_again;
881 		default: {
882 			zval tmp;
883 			ZVAL_COPY_VALUE(&tmp, op);
884 			object_init(op);
885 			zend_hash_add_new(Z_OBJPROP_P(op), ZSTR_KNOWN(ZEND_STR_SCALAR), &tmp);
886 			break;
887 		}
888 	}
889 }
890 /* }}} */
891 
zend_incompatible_double_to_long_error(double d)892 ZEND_API void ZEND_COLD zend_incompatible_double_to_long_error(double d)
893 {
894 	zend_error_unchecked(E_DEPRECATED, "Implicit conversion from float %.*H to int loses precision", -1, d);
895 }
zend_incompatible_string_to_long_error(const zend_string * s)896 ZEND_API void ZEND_COLD zend_incompatible_string_to_long_error(const zend_string *s)
897 {
898 	zend_error(E_DEPRECATED, "Implicit conversion from float-string \"%s\" to int loses precision", ZSTR_VAL(s));
899 }
900 
zval_get_long_func(const zval * op,bool is_strict)901 ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(const zval *op, bool is_strict) /* {{{ */
902 {
903 try_again:
904 	switch (Z_TYPE_P(op)) {
905 		case IS_UNDEF:
906 		case IS_NULL:
907 		case IS_FALSE:
908 			return 0;
909 		case IS_TRUE:
910 			return 1;
911 		case IS_RESOURCE:
912 			return Z_RES_HANDLE_P(op);
913 		case IS_LONG:
914 			return Z_LVAL_P(op);
915 		case IS_DOUBLE: {
916 			double dval = Z_DVAL_P(op);
917 			zend_long lval = zend_dval_to_lval(dval);
918 			if (UNEXPECTED(is_strict)) {
919 				if (!zend_is_long_compatible(dval, lval)) {
920 					zend_incompatible_double_to_long_error(dval);
921 				}
922 			}
923 			return lval;
924 		}
925 		case IS_STRING:
926 			{
927 				uint8_t type;
928 				zend_long lval;
929 				double dval;
930 				if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, true))) {
931 					return 0;
932 				} else if (EXPECTED(type == IS_LONG)) {
933 					return lval;
934 				} else {
935 					/* Previously we used strtol here, not is_numeric_string,
936 					 * and strtol gives you LONG_MAX/_MIN on overflow.
937 					 * We use saturating conversion to emulate strtol()'s
938 					 * behaviour.
939 					 */
940 					 /* Most usages are expected to not be (int) casts */
941 					lval = zend_dval_to_lval_cap(dval);
942 					if (UNEXPECTED(is_strict)) {
943 						if (!zend_is_long_compatible(dval, lval)) {
944 							zend_incompatible_string_to_long_error(Z_STR_P(op));
945 						}
946 					}
947 					return lval;
948 				}
949 			}
950 		case IS_ARRAY:
951 			return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
952 		case IS_OBJECT:
953 			{
954 				zval dst;
955 				convert_object_to_type(op, &dst, IS_LONG);
956 				if (Z_TYPE(dst) == IS_LONG) {
957 					return Z_LVAL(dst);
958 				} else {
959 					return 1;
960 				}
961 			}
962 		case IS_REFERENCE:
963 			op = Z_REFVAL_P(op);
964 			goto try_again;
965 		EMPTY_SWITCH_DEFAULT_CASE()
966 	}
967 	return 0;
968 }
969 /* }}} */
970 
zval_get_double_func(const zval * op)971 ZEND_API double ZEND_FASTCALL zval_get_double_func(const zval *op) /* {{{ */
972 {
973 try_again:
974 	switch (Z_TYPE_P(op)) {
975 		case IS_NULL:
976 		case IS_FALSE:
977 			return 0.0;
978 		case IS_TRUE:
979 			return 1.0;
980 		case IS_RESOURCE:
981 			return (double) Z_RES_HANDLE_P(op);
982 		case IS_LONG:
983 			return (double) Z_LVAL_P(op);
984 		case IS_DOUBLE:
985 			return Z_DVAL_P(op);
986 		case IS_STRING:
987 			return zend_strtod(Z_STRVAL_P(op), NULL);
988 		case IS_ARRAY:
989 			return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1.0 : 0.0;
990 		case IS_OBJECT:
991 			{
992 				zval dst;
993 				convert_object_to_type(op, &dst, IS_DOUBLE);
994 
995 				if (Z_TYPE(dst) == IS_DOUBLE) {
996 					return Z_DVAL(dst);
997 				} else {
998 					return 1.0;
999 				}
1000 			}
1001 		case IS_REFERENCE:
1002 			op = Z_REFVAL_P(op);
1003 			goto try_again;
1004 		EMPTY_SWITCH_DEFAULT_CASE()
1005 	}
1006 	return 0.0;
1007 }
1008 /* }}} */
1009 
__zval_get_string_func(zval * op,bool try)1010 static zend_always_inline zend_string* __zval_get_string_func(zval *op, bool try) /* {{{ */
1011 {
1012 try_again:
1013 	switch (Z_TYPE_P(op)) {
1014 		case IS_UNDEF:
1015 		case IS_NULL:
1016 		case IS_FALSE:
1017 			return ZSTR_EMPTY_ALLOC();
1018 		case IS_TRUE:
1019 			return ZSTR_CHAR('1');
1020 		case IS_RESOURCE:
1021 			return zend_strpprintf(0, "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
1022 		case IS_LONG:
1023 			return zend_long_to_str(Z_LVAL_P(op));
1024 		case IS_DOUBLE:
1025 			return zend_double_to_str(Z_DVAL_P(op));
1026 		case IS_ARRAY:
1027 			zend_error(E_WARNING, "Array to string conversion");
1028 			return (try && UNEXPECTED(EG(exception))) ?
1029 				NULL : ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
1030 		case IS_OBJECT: {
1031 			zval tmp;
1032 			if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &tmp, IS_STRING) == SUCCESS) {
1033 				return Z_STR(tmp);
1034 			}
1035 			if (!EG(exception)) {
1036 				zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
1037 			}
1038 			return try ? NULL : ZSTR_EMPTY_ALLOC();
1039 		}
1040 		case IS_REFERENCE:
1041 			op = Z_REFVAL_P(op);
1042 			goto try_again;
1043 		case IS_STRING:
1044 			return zend_string_copy(Z_STR_P(op));
1045 		EMPTY_SWITCH_DEFAULT_CASE()
1046 	}
1047 	return NULL;
1048 }
1049 /* }}} */
1050 
zval_get_string_func(zval * op)1051 ZEND_API zend_string* ZEND_FASTCALL zval_get_string_func(zval *op) /* {{{ */
1052 {
1053 	return __zval_get_string_func(op, 0);
1054 }
1055 /* }}} */
1056 
zval_try_get_string_func(zval * op)1057 ZEND_API zend_string* ZEND_FASTCALL zval_try_get_string_func(zval *op) /* {{{ */
1058 {
1059 	return __zval_get_string_func(op, 1);
1060 }
1061 /* }}} */
1062 
zend_binop_error(const char * operator,zval * op1,zval * op2)1063 static ZEND_COLD zend_never_inline void ZEND_FASTCALL zend_binop_error(const char *operator, zval *op1, zval *op2) /* {{{ */ {
1064 	if (EG(exception)) {
1065 		return;
1066 	}
1067 
1068 	zend_type_error("Unsupported operand types: %s %s %s",
1069 		zend_zval_type_name(op1), operator, zend_zval_type_name(op2));
1070 }
1071 /* }}} */
1072 
add_function_array(zval * result,zval * op1,zval * op2)1073 static zend_never_inline void ZEND_FASTCALL add_function_array(zval *result, zval *op1, zval *op2) /* {{{ */
1074 {
1075 	if (result == op1 && Z_ARR_P(op1) == Z_ARR_P(op2)) {
1076 		/* $a += $a */
1077 		return;
1078 	}
1079 	if (result != op1) {
1080 		ZVAL_ARR(result, zend_array_dup(Z_ARR_P(op1)));
1081 	} else {
1082 		SEPARATE_ARRAY(result);
1083 	}
1084 	zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
1085 }
1086 /* }}} */
1087 
add_function_fast(zval * result,zval * op1,zval * op2)1088 static zend_always_inline zend_result add_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1089 {
1090 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1091 
1092 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1093 		fast_long_add_function(result, op1, op2);
1094 		return SUCCESS;
1095 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1096 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
1097 		return SUCCESS;
1098 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1099 		ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
1100 		return SUCCESS;
1101 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1102 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
1103 		return SUCCESS;
1104 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_ARRAY, IS_ARRAY))) {
1105 		add_function_array(result, op1, op2);
1106 		return SUCCESS;
1107 	} else {
1108 		return FAILURE;
1109 	}
1110 } /* }}} */
1111 
add_function_slow(zval * result,zval * op1,zval * op2)1112 static zend_never_inline zend_result ZEND_FASTCALL add_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1113 {
1114 	ZVAL_DEREF(op1);
1115 	ZVAL_DEREF(op2);
1116 	if (add_function_fast(result, op1, op2) == SUCCESS) {
1117 		return SUCCESS;
1118 	}
1119 
1120 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD);
1121 
1122 	zval op1_copy, op2_copy;
1123 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1124 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1125 		zend_binop_error("+", op1, op2);
1126 		if (result != op1) {
1127 			ZVAL_UNDEF(result);
1128 		}
1129 		return FAILURE;
1130 	}
1131 
1132 	if (result == op1) {
1133 		zval_ptr_dtor(result);
1134 	}
1135 
1136 	if (add_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
1137 		return SUCCESS;
1138 	}
1139 
1140 	ZEND_ASSERT(0 && "Operation must succeed");
1141 	return FAILURE;
1142 } /* }}} */
1143 
add_function(zval * result,zval * op1,zval * op2)1144 ZEND_API zend_result ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
1145 {
1146 	if (add_function_fast(result, op1, op2) == SUCCESS) {
1147 		return SUCCESS;
1148 	} else {
1149 		return add_function_slow(result, op1, op2);
1150 	}
1151 }
1152 /* }}} */
1153 
sub_function_fast(zval * result,zval * op1,zval * op2)1154 static zend_always_inline zend_result sub_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1155 {
1156 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1157 
1158 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1159 		fast_long_sub_function(result, op1, op2);
1160 		return SUCCESS;
1161 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1162 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
1163 		return SUCCESS;
1164 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1165 		ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
1166 		return SUCCESS;
1167 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1168 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
1169 		return SUCCESS;
1170 	} else {
1171 		return FAILURE;
1172 	}
1173 }
1174 /* }}} */
1175 
sub_function_slow(zval * result,zval * op1,zval * op2)1176 static zend_never_inline zend_result ZEND_FASTCALL sub_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1177 {
1178 	ZVAL_DEREF(op1);
1179 	ZVAL_DEREF(op2);
1180 	if (sub_function_fast(result, op1, op2) == SUCCESS) {
1181 		return SUCCESS;
1182 	}
1183 
1184 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB);
1185 
1186 	zval op1_copy, op2_copy;
1187 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1188 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1189 		zend_binop_error("-", op1, op2);
1190 		if (result != op1) {
1191 			ZVAL_UNDEF(result);
1192 		}
1193 		return FAILURE;
1194 	}
1195 
1196 	if (result == op1) {
1197 		zval_ptr_dtor(result);
1198 	}
1199 
1200 	if (sub_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
1201 		return SUCCESS;
1202 	}
1203 
1204 	ZEND_ASSERT(0 && "Operation must succeed");
1205 	return FAILURE;
1206 }
1207 /* }}} */
1208 
sub_function(zval * result,zval * op1,zval * op2)1209 ZEND_API zend_result ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* {{{ */
1210 {
1211 	if (sub_function_fast(result, op1, op2) == SUCCESS) {
1212 		return SUCCESS;
1213 	} else {
1214 		return sub_function_slow(result, op1, op2);
1215 	}
1216 }
1217 /* }}} */
1218 
mul_function_fast(zval * result,zval * op1,zval * op2)1219 static zend_always_inline zend_result mul_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1220 {
1221 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1222 
1223 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1224 		zend_long overflow;
1225 		ZEND_SIGNED_MULTIPLY_LONG(
1226 			Z_LVAL_P(op1), Z_LVAL_P(op2),
1227 			Z_LVAL_P(result), Z_DVAL_P(result), overflow);
1228 		Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
1229 		return SUCCESS;
1230 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1231 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
1232 		return SUCCESS;
1233 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1234 		ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
1235 		return SUCCESS;
1236 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1237 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
1238 		return SUCCESS;
1239 	} else {
1240 		return FAILURE;
1241 	}
1242 }
1243 /* }}} */
1244 
mul_function_slow(zval * result,zval * op1,zval * op2)1245 static zend_never_inline zend_result ZEND_FASTCALL mul_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1246 {
1247 	ZVAL_DEREF(op1);
1248 	ZVAL_DEREF(op2);
1249 	if (mul_function_fast(result, op1, op2) == SUCCESS) {
1250 		return SUCCESS;
1251 	}
1252 
1253 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL);
1254 
1255 	zval op1_copy, op2_copy;
1256 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1257 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1258 		zend_binop_error("*", op1, op2);
1259 		if (result != op1) {
1260 			ZVAL_UNDEF(result);
1261 		}
1262 		return FAILURE;
1263 	}
1264 
1265 	if (result == op1) {
1266 		zval_ptr_dtor(result);
1267 	}
1268 
1269 	if (mul_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
1270 		return SUCCESS;
1271 	}
1272 
1273 	ZEND_ASSERT(0 && "Operation must succeed");
1274 	return FAILURE;
1275 }
1276 /* }}} */
1277 
mul_function(zval * result,zval * op1,zval * op2)1278 ZEND_API zend_result ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */
1279 {
1280 	if (mul_function_fast(result, op1, op2) == SUCCESS) {
1281 		return SUCCESS;
1282 	} else {
1283 		return mul_function_slow(result, op1, op2);
1284 	}
1285 }
1286 /* }}} */
1287 
zend_power_base_0_exponent_lt_0_error(void)1288 static void ZEND_COLD zend_power_base_0_exponent_lt_0_error(void)
1289 {
1290 	zend_error(E_DEPRECATED, "Power of base 0 and negative exponent is deprecated");
1291 }
1292 
safe_pow(double base,double exponent)1293 static double safe_pow(double base, double exponent)
1294 {
1295 	if (UNEXPECTED(base == 0.0 && exponent < 0.0)) {
1296 		zend_power_base_0_exponent_lt_0_error();
1297 	}
1298 
1299 	return pow(base, exponent);
1300 }
1301 
pow_function_base(zval * result,zval * op1,zval * op2)1302 static zend_result ZEND_FASTCALL pow_function_base(zval *result, zval *op1, zval *op2) /* {{{ */
1303 {
1304 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1305 
1306 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1307 		if (Z_LVAL_P(op2) >= 0) {
1308 			zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
1309 
1310 			if (i == 0) {
1311 				ZVAL_LONG(result, 1L);
1312 				return SUCCESS;
1313 			} else if (l2 == 0) {
1314 				ZVAL_LONG(result, 0);
1315 				return SUCCESS;
1316 			}
1317 
1318 			while (i >= 1) {
1319 				zend_long overflow;
1320 				double dval = 0.0;
1321 
1322 				if (i % 2) {
1323 					--i;
1324 					ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
1325 					if (overflow) {
1326 						ZVAL_DOUBLE(result, dval * safe_pow(l2, i));
1327 						return SUCCESS;
1328 					}
1329 				} else {
1330 					i /= 2;
1331 					ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
1332 					if (overflow) {
1333 						ZVAL_DOUBLE(result, (double)l1 * safe_pow(dval, i));
1334 						return SUCCESS;
1335 					}
1336 				}
1337 			}
1338 			/* i == 0 */
1339 			ZVAL_LONG(result, l1);
1340 		} else {
1341 			ZVAL_DOUBLE(result, safe_pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
1342 		}
1343 		return SUCCESS;
1344 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1345 		ZVAL_DOUBLE(result, safe_pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
1346 		return SUCCESS;
1347 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1348 		ZVAL_DOUBLE(result, safe_pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
1349 		return SUCCESS;
1350 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1351 		ZVAL_DOUBLE(result, safe_pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
1352 		return SUCCESS;
1353 	} else {
1354 		return FAILURE;
1355 	}
1356 }
1357 /* }}} */
1358 
pow_function(zval * result,zval * op1,zval * op2)1359 ZEND_API zend_result ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */
1360 {
1361 	ZVAL_DEREF(op1);
1362 	ZVAL_DEREF(op2);
1363 	if (pow_function_base(result, op1, op2) == SUCCESS) {
1364 		return SUCCESS;
1365 	}
1366 
1367 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW);
1368 
1369 	zval op1_copy, op2_copy;
1370 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1371 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1372 		zend_binop_error("**", op1, op2);
1373 		if (result != op1) {
1374 			ZVAL_UNDEF(result);
1375 		}
1376 		return FAILURE;
1377 	}
1378 
1379 	if (result == op1) {
1380 		zval_ptr_dtor(result);
1381 	}
1382 
1383 	if (pow_function_base(result, &op1_copy, &op2_copy) == SUCCESS) {
1384 		return SUCCESS;
1385 	}
1386 
1387 	ZEND_ASSERT(0 && "Operation must succeed");
1388 	return FAILURE;
1389 }
1390 /* }}} */
1391 
1392 /* Returns SUCCESS/TYPES_NOT_HANDLED/DIV_BY_ZERO */
1393 #define TYPES_NOT_HANDLED 1
1394 #define DIV_BY_ZERO 2
div_function_base(zval * result,zval * op1,zval * op2)1395 static int ZEND_FASTCALL div_function_base(zval *result, zval *op1, zval *op2) /* {{{ */
1396 {
1397 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1398 
1399 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1400 		if (Z_LVAL_P(op2) == 0) {
1401 			return DIV_BY_ZERO;
1402 		} else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
1403 			/* Prevent overflow error/crash */
1404 			ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
1405 			return SUCCESS;
1406 		}
1407 		if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
1408 			ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
1409 		} else {
1410 			ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
1411 		}
1412 		return SUCCESS;
1413 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1414 		if (Z_DVAL_P(op2) == 0) {
1415 			return DIV_BY_ZERO;
1416 		}
1417 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1418 		return SUCCESS;
1419 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1420 		if (Z_LVAL_P(op2) == 0) {
1421 			return DIV_BY_ZERO;
1422 		}
1423 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1424 		return SUCCESS;
1425 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1426 		if (Z_DVAL_P(op2) == 0) {
1427 			return DIV_BY_ZERO;
1428 		}
1429 		ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1430 		return SUCCESS;
1431 	} else {
1432 		return TYPES_NOT_HANDLED;
1433 	}
1434 }
1435 /* }}} */
1436 
div_function(zval * result,zval * op1,zval * op2)1437 ZEND_API zend_result ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */
1438 {
1439 	ZVAL_DEREF(op1);
1440 	ZVAL_DEREF(op2);
1441 
1442 	int retval = div_function_base(result, op1, op2);
1443 	if (EXPECTED(retval == SUCCESS)) {
1444 		return SUCCESS;
1445 	}
1446 
1447 	if (UNEXPECTED(retval == DIV_BY_ZERO)) {
1448 		goto div_by_zero;
1449 	}
1450 
1451 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);
1452 
1453 	zval result_copy, op1_copy, op2_copy;
1454 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1455 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1456 		zend_binop_error("/", op1, op2);
1457 		if (result != op1) {
1458 			ZVAL_UNDEF(result);
1459 		}
1460 		return FAILURE;
1461 	}
1462 
1463 	retval = div_function_base(&result_copy, &op1_copy, &op2_copy);
1464 	if (retval == SUCCESS) {
1465 		if (result == op1) {
1466 			zval_ptr_dtor(result);
1467 		}
1468 		ZVAL_COPY_VALUE(result, &result_copy);
1469 		return SUCCESS;
1470 	}
1471 
1472 div_by_zero:
1473 	ZEND_ASSERT(retval == DIV_BY_ZERO && "TYPES_NOT_HANDLED should not occur here");
1474 	if (result != op1) {
1475 		ZVAL_UNDEF(result);
1476 	}
1477 	zend_throw_error(zend_ce_division_by_zero_error, "Division by zero");
1478 	return FAILURE;
1479 }
1480 /* }}} */
1481 
mod_function(zval * result,zval * op1,zval * op2)1482 ZEND_API zend_result ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* {{{ */
1483 {
1484 	zend_long op1_lval, op2_lval;
1485 
1486 	convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_MOD, "%");
1487 
1488 	if (op2_lval == 0) {
1489 		/* modulus by zero */
1490 		if (EG(current_execute_data) && !CG(in_compilation)) {
1491 			zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
1492 		} else {
1493 			zend_error_noreturn(E_ERROR, "Modulo by zero");
1494 		}
1495 		if (op1 != result) {
1496 			ZVAL_UNDEF(result);
1497 		}
1498 		return FAILURE;
1499 	}
1500 
1501 	if (op1 == result) {
1502 		zval_ptr_dtor(result);
1503 	}
1504 
1505 	if (op2_lval == -1) {
1506 		/* Prevent overflow error/crash if op1==LONG_MIN */
1507 		ZVAL_LONG(result, 0);
1508 		return SUCCESS;
1509 	}
1510 
1511 	ZVAL_LONG(result, op1_lval % op2_lval);
1512 	return SUCCESS;
1513 }
1514 /* }}} */
1515 
boolean_xor_function(zval * result,zval * op1,zval * op2)1516 ZEND_API zend_result ZEND_FASTCALL boolean_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1517 {
1518 	int op1_val, op2_val;
1519 
1520 	do {
1521 		if (Z_TYPE_P(op1) == IS_FALSE) {
1522 			op1_val = 0;
1523 		} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1524 			op1_val = 1;
1525 		} else {
1526 			if (Z_ISREF_P(op1)) {
1527 				op1 = Z_REFVAL_P(op1);
1528 				if (Z_TYPE_P(op1) == IS_FALSE) {
1529 					op1_val = 0;
1530 					break;
1531 				} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1532 					op1_val = 1;
1533 					break;
1534 				}
1535 			}
1536 			ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BOOL_XOR);
1537 			op1_val = zval_is_true(op1);
1538 		}
1539 	} while (0);
1540 	do {
1541 		if (Z_TYPE_P(op2) == IS_FALSE) {
1542 			op2_val = 0;
1543 		} else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1544 			op2_val = 1;
1545 		} else {
1546 			if (Z_ISREF_P(op2)) {
1547 				op2 = Z_REFVAL_P(op2);
1548 				if (Z_TYPE_P(op2) == IS_FALSE) {
1549 					op2_val = 0;
1550 					break;
1551 				} else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1552 					op2_val = 1;
1553 					break;
1554 				}
1555 			}
1556 			ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BOOL_XOR);
1557 			op2_val = zval_is_true(op2);
1558 		}
1559 	} while (0);
1560 
1561 	ZVAL_BOOL(result, op1_val ^ op2_val);
1562 	return SUCCESS;
1563 }
1564 /* }}} */
1565 
boolean_not_function(zval * result,zval * op1)1566 ZEND_API zend_result ZEND_FASTCALL boolean_not_function(zval *result, zval *op1) /* {{{ */
1567 {
1568 	if (Z_TYPE_P(op1) < IS_TRUE) {
1569 		ZVAL_TRUE(result);
1570 	} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1571 		ZVAL_FALSE(result);
1572 	} else {
1573 		if (Z_ISREF_P(op1)) {
1574 			op1 = Z_REFVAL_P(op1);
1575 			if (Z_TYPE_P(op1) < IS_TRUE) {
1576 				ZVAL_TRUE(result);
1577 				return SUCCESS;
1578 			} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1579 				ZVAL_FALSE(result);
1580 				return SUCCESS;
1581 			}
1582 		}
1583 		ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1584 
1585 		ZVAL_BOOL(result, !zval_is_true(op1));
1586 	}
1587 	return SUCCESS;
1588 }
1589 /* }}} */
1590 
bitwise_not_function(zval * result,zval * op1)1591 ZEND_API zend_result ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{ */
1592 {
1593 try_again:
1594 	switch (Z_TYPE_P(op1)) {
1595 		case IS_LONG:
1596 			ZVAL_LONG(result, ~Z_LVAL_P(op1));
1597 			return SUCCESS;
1598 		case IS_DOUBLE: {
1599 			zend_long lval = zend_dval_to_lval(Z_DVAL_P(op1));
1600 			if (!zend_is_long_compatible(Z_DVAL_P(op1), lval)) {
1601 				zend_incompatible_double_to_long_error(Z_DVAL_P(op1));
1602 				if (EG(exception)) {
1603 					if (result != op1) {
1604 						ZVAL_UNDEF(result);
1605 					}
1606 					return FAILURE;
1607 				}
1608 			}
1609 			ZVAL_LONG(result, ~lval);
1610 			return SUCCESS;
1611 		}
1612 		case IS_STRING: {
1613 			size_t i;
1614 
1615 			if (Z_STRLEN_P(op1) == 1) {
1616 				zend_uchar not = (zend_uchar) ~*Z_STRVAL_P(op1);
1617 				ZVAL_CHAR(result, not);
1618 			} else {
1619 				ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
1620 				for (i = 0; i < Z_STRLEN_P(op1); i++) {
1621 					Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1622 				}
1623 				Z_STRVAL_P(result)[i] = 0;
1624 			}
1625 			return SUCCESS;
1626 		}
1627 		case IS_REFERENCE:
1628 			op1 = Z_REFVAL_P(op1);
1629 			goto try_again;
1630 		default:
1631 			ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1632 
1633 			if (result != op1) {
1634 				ZVAL_UNDEF(result);
1635 			}
1636 			zend_type_error("Cannot perform bitwise not on %s", zend_zval_value_name(op1));
1637 			return FAILURE;
1638 	}
1639 }
1640 /* }}} */
1641 
bitwise_or_function(zval * result,zval * op1,zval * op2)1642 ZEND_API zend_result ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2) /* {{{ */
1643 {
1644 	zend_long op1_lval, op2_lval;
1645 
1646 	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1647 		ZVAL_LONG(result, Z_LVAL_P(op1) | Z_LVAL_P(op2));
1648 		return SUCCESS;
1649 	}
1650 
1651 	ZVAL_DEREF(op1);
1652 	ZVAL_DEREF(op2);
1653 
1654 	if (Z_TYPE_P(op1) == IS_STRING && EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1655 		zval *longer, *shorter;
1656 		zend_string *str;
1657 		size_t i;
1658 
1659 		if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1660 			if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1661 				zend_uchar or = (zend_uchar) (*Z_STRVAL_P(op1) | *Z_STRVAL_P(op2));
1662 				if (result==op1) {
1663 					zval_ptr_dtor_str(result);
1664 				}
1665 				ZVAL_CHAR(result, or);
1666 				return SUCCESS;
1667 			}
1668 			longer = op1;
1669 			shorter = op2;
1670 		} else {
1671 			longer = op2;
1672 			shorter = op1;
1673 		}
1674 
1675 		str = zend_string_alloc(Z_STRLEN_P(longer), 0);
1676 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1677 			ZSTR_VAL(str)[i] = Z_STRVAL_P(longer)[i] | Z_STRVAL_P(shorter)[i];
1678 		}
1679 		memcpy(ZSTR_VAL(str) + i, Z_STRVAL_P(longer) + i, Z_STRLEN_P(longer) - i + 1);
1680 		if (result==op1) {
1681 			zval_ptr_dtor_str(result);
1682 		}
1683 		ZVAL_NEW_STR(result, str);
1684 		return SUCCESS;
1685 	}
1686 
1687 	if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1688 		bool failed;
1689 		ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR);
1690 		op1_lval = zendi_try_get_long(op1, &failed);
1691 		if (UNEXPECTED(failed)) {
1692 			zend_binop_error("|", op1, op2);
1693 			if (result != op1) {
1694 				ZVAL_UNDEF(result);
1695 			}
1696 			return FAILURE;
1697 		}
1698 	} else {
1699 		op1_lval = Z_LVAL_P(op1);
1700 	}
1701 	if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1702 		bool failed;
1703 		ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR);
1704 		op2_lval = zendi_try_get_long(op2, &failed);
1705 		if (UNEXPECTED(failed)) {
1706 			zend_binop_error("|", op1, op2);
1707 			if (result != op1) {
1708 				ZVAL_UNDEF(result);
1709 			}
1710 			return FAILURE;
1711 		}
1712 	} else {
1713 		op2_lval = Z_LVAL_P(op2);
1714 	}
1715 
1716 	if (op1 == result) {
1717 		zval_ptr_dtor(result);
1718 	}
1719 	ZVAL_LONG(result, op1_lval | op2_lval);
1720 	return SUCCESS;
1721 }
1722 /* }}} */
1723 
bitwise_and_function(zval * result,zval * op1,zval * op2)1724 ZEND_API zend_result ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2) /* {{{ */
1725 {
1726 	zend_long op1_lval, op2_lval;
1727 
1728 	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1729 		ZVAL_LONG(result, Z_LVAL_P(op1) & Z_LVAL_P(op2));
1730 		return SUCCESS;
1731 	}
1732 
1733 	ZVAL_DEREF(op1);
1734 	ZVAL_DEREF(op2);
1735 
1736 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1737 		zval *longer, *shorter;
1738 		zend_string *str;
1739 		size_t i;
1740 
1741 		if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1742 			if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1743 				zend_uchar and = (zend_uchar) (*Z_STRVAL_P(op1) & *Z_STRVAL_P(op2));
1744 				if (result==op1) {
1745 					zval_ptr_dtor_str(result);
1746 				}
1747 				ZVAL_CHAR(result, and);
1748 				return SUCCESS;
1749 			}
1750 			longer = op1;
1751 			shorter = op2;
1752 		} else {
1753 			longer = op2;
1754 			shorter = op1;
1755 		}
1756 
1757 		str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1758 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1759 			ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] & Z_STRVAL_P(longer)[i];
1760 		}
1761 		ZSTR_VAL(str)[i] = 0;
1762 		if (result==op1) {
1763 			zval_ptr_dtor_str(result);
1764 		}
1765 		ZVAL_NEW_STR(result, str);
1766 		return SUCCESS;
1767 	}
1768 
1769 	if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1770 		bool failed;
1771 		ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND);
1772 		op1_lval = zendi_try_get_long(op1, &failed);
1773 		if (UNEXPECTED(failed)) {
1774 			zend_binop_error("&", op1, op2);
1775 			if (result != op1) {
1776 				ZVAL_UNDEF(result);
1777 			}
1778 			return FAILURE;
1779 		}
1780 	} else {
1781 		op1_lval = Z_LVAL_P(op1);
1782 	}
1783 	if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1784 		bool failed;
1785 		ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND);
1786 		op2_lval = zendi_try_get_long(op2, &failed);
1787 		if (UNEXPECTED(failed)) {
1788 			zend_binop_error("&", op1, op2);
1789 			if (result != op1) {
1790 				ZVAL_UNDEF(result);
1791 			}
1792 			return FAILURE;
1793 		}
1794 	} else {
1795 		op2_lval = Z_LVAL_P(op2);
1796 	}
1797 
1798 	if (op1 == result) {
1799 		zval_ptr_dtor(result);
1800 	}
1801 	ZVAL_LONG(result, op1_lval & op2_lval);
1802 	return SUCCESS;
1803 }
1804 /* }}} */
1805 
bitwise_xor_function(zval * result,zval * op1,zval * op2)1806 ZEND_API zend_result ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1807 {
1808 	zend_long op1_lval, op2_lval;
1809 
1810 	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1811 		ZVAL_LONG(result, Z_LVAL_P(op1) ^ Z_LVAL_P(op2));
1812 		return SUCCESS;
1813 	}
1814 
1815 	ZVAL_DEREF(op1);
1816 	ZVAL_DEREF(op2);
1817 
1818 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1819 		zval *longer, *shorter;
1820 		zend_string *str;
1821 		size_t i;
1822 
1823 		if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1824 			if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1825 				zend_uchar xor = (zend_uchar) (*Z_STRVAL_P(op1) ^ *Z_STRVAL_P(op2));
1826 				if (result==op1) {
1827 					zval_ptr_dtor_str(result);
1828 				}
1829 				ZVAL_CHAR(result, xor);
1830 				return SUCCESS;
1831 			}
1832 			longer = op1;
1833 			shorter = op2;
1834 		} else {
1835 			longer = op2;
1836 			shorter = op1;
1837 		}
1838 
1839 		str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1840 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1841 			ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] ^ Z_STRVAL_P(longer)[i];
1842 		}
1843 		ZSTR_VAL(str)[i] = 0;
1844 		if (result==op1) {
1845 			zval_ptr_dtor_str(result);
1846 		}
1847 		ZVAL_NEW_STR(result, str);
1848 		return SUCCESS;
1849 	}
1850 
1851 	if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1852 		bool failed;
1853 		ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR);
1854 		op1_lval = zendi_try_get_long(op1, &failed);
1855 		if (UNEXPECTED(failed)) {
1856 			zend_binop_error("^", op1, op2);
1857 			if (result != op1) {
1858 				ZVAL_UNDEF(result);
1859 			}
1860 			return FAILURE;
1861 		}
1862 	} else {
1863 		op1_lval = Z_LVAL_P(op1);
1864 	}
1865 	if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1866 		bool failed;
1867 		ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR);
1868 		op2_lval = zendi_try_get_long(op2, &failed);
1869 		if (UNEXPECTED(failed)) {
1870 			zend_binop_error("^", op1, op2);
1871 			if (result != op1) {
1872 				ZVAL_UNDEF(result);
1873 			}
1874 			return FAILURE;
1875 		}
1876 	} else {
1877 		op2_lval = Z_LVAL_P(op2);
1878 	}
1879 
1880 	if (op1 == result) {
1881 		zval_ptr_dtor(result);
1882 	}
1883 	ZVAL_LONG(result, op1_lval ^ op2_lval);
1884 	return SUCCESS;
1885 }
1886 /* }}} */
1887 
shift_left_function(zval * result,zval * op1,zval * op2)1888 ZEND_API zend_result ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2) /* {{{ */
1889 {
1890 	zend_long op1_lval, op2_lval;
1891 
1892 	convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SL, "<<");
1893 
1894 	/* prevent wrapping quirkiness on some processors where << 64 + x == << x */
1895 	if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1896 		if (EXPECTED(op2_lval > 0)) {
1897 			if (op1 == result) {
1898 				zval_ptr_dtor(result);
1899 			}
1900 			ZVAL_LONG(result, 0);
1901 			return SUCCESS;
1902 		} else {
1903 			if (EG(current_execute_data) && !CG(in_compilation)) {
1904 				zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1905 			} else {
1906 				zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1907 			}
1908 			if (op1 != result) {
1909 				ZVAL_UNDEF(result);
1910 			}
1911 			return FAILURE;
1912 		}
1913 	}
1914 
1915 	if (op1 == result) {
1916 		zval_ptr_dtor(result);
1917 	}
1918 
1919 	/* Perform shift on unsigned numbers to get well-defined wrap behavior. */
1920 	ZVAL_LONG(result, (zend_long) ((zend_ulong) op1_lval << op2_lval));
1921 	return SUCCESS;
1922 }
1923 /* }}} */
1924 
shift_right_function(zval * result,zval * op1,zval * op2)1925 ZEND_API zend_result ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2) /* {{{ */
1926 {
1927 	zend_long op1_lval, op2_lval;
1928 
1929 	convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SR, ">>");
1930 
1931 	/* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */
1932 	if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1933 		if (EXPECTED(op2_lval > 0)) {
1934 			if (op1 == result) {
1935 				zval_ptr_dtor(result);
1936 			}
1937 			ZVAL_LONG(result, (op1_lval < 0) ? -1 : 0);
1938 			return SUCCESS;
1939 		} else {
1940 			if (EG(current_execute_data) && !CG(in_compilation)) {
1941 				zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1942 			} else {
1943 				zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1944 			}
1945 			if (op1 != result) {
1946 				ZVAL_UNDEF(result);
1947 			}
1948 			return FAILURE;
1949 		}
1950 	}
1951 
1952 	if (op1 == result) {
1953 		zval_ptr_dtor(result);
1954 	}
1955 
1956 	ZVAL_LONG(result, op1_lval >> op2_lval);
1957 	return SUCCESS;
1958 }
1959 /* }}} */
1960 
concat_function(zval * result,zval * op1,zval * op2)1961 ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */
1962 {
1963 	zval *orig_op1 = op1;
1964 	zend_string *op1_string, *op2_string;
1965 	bool free_op1_string = false;
1966 	bool free_op2_string = false;
1967 
1968 	do {
1969 		if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
1970 			op1_string = Z_STR_P(op1);
1971 		} else {
1972 	 		if (Z_ISREF_P(op1)) {
1973 	 			op1 = Z_REFVAL_P(op1);
1974 				if (Z_TYPE_P(op1) == IS_STRING) {
1975 					op1_string = Z_STR_P(op1);
1976 					break;
1977 				}
1978 	 		}
1979 			ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT);
1980 			op1_string = zval_get_string_func(op1);
1981 			if (UNEXPECTED(EG(exception))) {
1982 				zend_string_release(op1_string);
1983 				if (orig_op1 != result) {
1984 					ZVAL_UNDEF(result);
1985 				}
1986 				return FAILURE;
1987 			}
1988 			free_op1_string = true;
1989 			if (result == op1) {
1990 				if (UNEXPECTED(op1 == op2)) {
1991 					op2_string = op1_string;
1992 					goto has_op2_string;
1993 				}
1994 			}
1995 		}
1996 	} while (0);
1997 	do {
1998 		if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1999 			op2_string = Z_STR_P(op2);
2000 		} else {
2001 			if (Z_ISREF_P(op2)) {
2002 				op2 = Z_REFVAL_P(op2);
2003 				if (Z_TYPE_P(op2) == IS_STRING) {
2004 					op2_string = Z_STR_P(op2);
2005 					break;
2006 				}
2007 			}
2008 			/* hold an additional reference because a userland function could free this */
2009 			if (!free_op1_string) {
2010 				op1_string = zend_string_copy(op1_string);
2011 				free_op1_string = true;
2012 			}
2013 			ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT);
2014 			op2_string = zval_get_string_func(op2);
2015 			if (UNEXPECTED(EG(exception))) {
2016 				zend_string_release(op1_string);
2017 				zend_string_release(op2_string);
2018 				if (orig_op1 != result) {
2019 					ZVAL_UNDEF(result);
2020 				}
2021 				return FAILURE;
2022 			}
2023 			free_op2_string = true;
2024 		}
2025 	} while (0);
2026 
2027 has_op2_string:;
2028 	if (UNEXPECTED(ZSTR_LEN(op1_string) == 0)) {
2029 		if (EXPECTED(result != op2 || Z_TYPE_P(result) != IS_STRING)) {
2030 			if (result == orig_op1) {
2031 				i_zval_ptr_dtor(result);
2032 			}
2033 			if (free_op2_string) {
2034 				/* transfer ownership of op2_string */
2035 				ZVAL_STR(result, op2_string);
2036 				free_op2_string = false;
2037 			} else {
2038 				ZVAL_STR_COPY(result, op2_string);
2039 			}
2040 		}
2041 	} else if (UNEXPECTED(ZSTR_LEN(op2_string) == 0)) {
2042 		if (EXPECTED(result != op1 || Z_TYPE_P(result) != IS_STRING)) {
2043 			if (result == orig_op1) {
2044 				i_zval_ptr_dtor(result);
2045 			}
2046 			if (free_op1_string) {
2047 				/* transfer ownership of op1_string */
2048 				ZVAL_STR(result, op1_string);
2049 				free_op1_string = false;
2050 			} else {
2051 				ZVAL_STR_COPY(result, op1_string);
2052 			}
2053 		}
2054 	} else {
2055 		size_t op1_len = ZSTR_LEN(op1_string);
2056 		size_t op2_len = ZSTR_LEN(op2_string);
2057 		size_t result_len = op1_len + op2_len;
2058 		zend_string *result_str;
2059 		uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_string, op2_string);
2060 
2061 		if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) {
2062 			if (free_op1_string) zend_string_release(op1_string);
2063 			if (free_op2_string) zend_string_release(op2_string);
2064 			zend_throw_error(NULL, "String size overflow");
2065 			if (orig_op1 != result) {
2066 				ZVAL_UNDEF(result);
2067 			}
2068 			return FAILURE;
2069 		}
2070 
2071 		if (result == op1) {
2072 			/* Destroy the old result first to drop the refcount, such that $x .= ...; may happen in-place. */
2073 			if (free_op1_string) {
2074 				/* op1_string will be used as the result, so we should not free it */
2075 				i_zval_ptr_dtor(result);
2076 				/* Set it to NULL in case that the extension will throw an out-of-memory error.
2077 				 * Otherwise the shutdown sequence will try to free this again. */
2078 				ZVAL_NULL(result);
2079 				free_op1_string = false;
2080 			}
2081 			/* special case, perform operations on result */
2082 			result_str = zend_string_extend(op1_string, result_len, 0);
2083 			/* account for the case where result_str == op1_string == op2_string and the realloc is done */
2084 			if (op1_string == op2_string) {
2085 				if (free_op2_string) {
2086 					zend_string_release(op2_string);
2087 					free_op2_string = false;
2088 				}
2089 				op2_string = result_str;
2090 			}
2091 		} else {
2092 			result_str = zend_string_alloc(result_len, 0);
2093 			memcpy(ZSTR_VAL(result_str), ZSTR_VAL(op1_string), op1_len);
2094 			if (result == orig_op1) {
2095 				i_zval_ptr_dtor(result);
2096 			}
2097 		}
2098 		GC_ADD_FLAGS(result_str, flags);
2099 
2100 		ZVAL_NEW_STR(result, result_str);
2101 		memcpy(ZSTR_VAL(result_str) + op1_len, ZSTR_VAL(op2_string), op2_len);
2102 		ZSTR_VAL(result_str)[result_len] = '\0';
2103 	}
2104 
2105 	if (free_op1_string) zend_string_release(op1_string);
2106 	if (free_op2_string) zend_string_release(op2_string);
2107 
2108 	return SUCCESS;
2109 }
2110 /* }}} */
2111 
string_compare_function_ex(zval * op1,zval * op2,bool case_insensitive)2112 ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, bool case_insensitive) /* {{{ */
2113 {
2114 	zend_string *tmp_str1, *tmp_str2;
2115 	zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2116 	zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2117 	int ret;
2118 
2119 	if (case_insensitive) {
2120 		ret = zend_binary_strcasecmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2121 	} else {
2122 		ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2123 	}
2124 
2125 	zend_tmp_string_release(tmp_str1);
2126 	zend_tmp_string_release(tmp_str2);
2127 	return ret;
2128 }
2129 /* }}} */
2130 
string_compare_function(zval * op1,zval * op2)2131 ZEND_API int ZEND_FASTCALL string_compare_function(zval *op1, zval *op2) /* {{{ */
2132 {
2133 	if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
2134 	    EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
2135 		if (Z_STR_P(op1) == Z_STR_P(op2)) {
2136 			return 0;
2137 		} else {
2138 			return zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
2139 		}
2140 	} else {
2141 		zend_string *tmp_str1, *tmp_str2;
2142 		zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2143 		zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2144 		int ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2145 
2146 		zend_tmp_string_release(tmp_str1);
2147 		zend_tmp_string_release(tmp_str2);
2148 		return ret;
2149 	}
2150 }
2151 /* }}} */
2152 
string_case_compare_function(zval * op1,zval * op2)2153 ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2) /* {{{ */
2154 {
2155 	if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
2156 	    EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
2157 		if (Z_STR_P(op1) == Z_STR_P(op2)) {
2158 			return 0;
2159 		} else {
2160 			return zend_binary_strcasecmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
2161 		}
2162 	} else {
2163 		zend_string *tmp_str1, *tmp_str2;
2164 		zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2165 		zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2166 		int ret = zend_binary_strcasecmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2167 
2168 		zend_tmp_string_release(tmp_str1);
2169 		zend_tmp_string_release(tmp_str2);
2170 		return ret;
2171 	}
2172 }
2173 /* }}} */
2174 
string_locale_compare_function(zval * op1,zval * op2)2175 ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2) /* {{{ */
2176 {
2177 	zend_string *tmp_str1, *tmp_str2;
2178 	zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2179 	zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2180 	int ret = strcoll(ZSTR_VAL(str1), ZSTR_VAL(str2));
2181 
2182 	zend_tmp_string_release(tmp_str1);
2183 	zend_tmp_string_release(tmp_str2);
2184 	return ret;
2185 }
2186 /* }}} */
2187 
numeric_compare_function(zval * op1,zval * op2)2188 ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{ */
2189 {
2190 	double d1, d2;
2191 
2192 	d1 = zval_get_double(op1);
2193 	d2 = zval_get_double(op2);
2194 
2195 	return ZEND_THREEWAY_COMPARE(d1, d2);
2196 }
2197 /* }}} */
2198 
compare_function(zval * result,zval * op1,zval * op2)2199 ZEND_API zend_result ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
2200 {
2201 	ZVAL_LONG(result, zend_compare(op1, op2));
2202 	return SUCCESS;
2203 }
2204 /* }}} */
2205 
compare_long_to_string(zend_long lval,zend_string * str)2206 static int compare_long_to_string(zend_long lval, zend_string *str) /* {{{ */
2207 {
2208 	zend_long str_lval;
2209 	double str_dval;
2210 	uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
2211 
2212 	if (type == IS_LONG) {
2213 		return lval > str_lval ? 1 : lval < str_lval ? -1 : 0;
2214 	}
2215 
2216 	if (type == IS_DOUBLE) {
2217 		return ZEND_THREEWAY_COMPARE((double) lval, str_dval);
2218 	}
2219 
2220 	zend_string *lval_as_str = zend_long_to_str(lval);
2221 	int cmp_result = zend_binary_strcmp(
2222 		ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
2223 	zend_string_release(lval_as_str);
2224 	return ZEND_NORMALIZE_BOOL(cmp_result);
2225 }
2226 /* }}} */
2227 
compare_double_to_string(double dval,zend_string * str)2228 static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
2229 {
2230 	zend_long str_lval;
2231 	double str_dval;
2232 	uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
2233 
2234 	if (type == IS_LONG) {
2235 		return ZEND_THREEWAY_COMPARE(dval, (double) str_lval);
2236 	}
2237 
2238 	if (type == IS_DOUBLE) {
2239 		return ZEND_THREEWAY_COMPARE(dval, str_dval);
2240 	}
2241 
2242 	zend_string *dval_as_str = zend_double_to_str(dval);
2243 	int cmp_result = zend_binary_strcmp(
2244 		ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
2245 	zend_string_release(dval_as_str);
2246 	return ZEND_NORMALIZE_BOOL(cmp_result);
2247 }
2248 /* }}} */
2249 
zend_compare(zval * op1,zval * op2)2250 ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
2251 {
2252 	int converted = 0;
2253 	zval op1_copy, op2_copy;
2254 
2255 	while (1) {
2256 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2257 			case TYPE_PAIR(IS_LONG, IS_LONG):
2258 				return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
2259 
2260 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2261 				return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), (double)Z_LVAL_P(op2));
2262 
2263 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2264 				return ZEND_THREEWAY_COMPARE((double)Z_LVAL_P(op1), Z_DVAL_P(op2));
2265 
2266 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2267 				return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), Z_DVAL_P(op2));
2268 
2269 			case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2270 				return zend_compare_arrays(op1, op2);
2271 
2272 			case TYPE_PAIR(IS_NULL, IS_NULL):
2273 			case TYPE_PAIR(IS_NULL, IS_FALSE):
2274 			case TYPE_PAIR(IS_FALSE, IS_NULL):
2275 			case TYPE_PAIR(IS_FALSE, IS_FALSE):
2276 			case TYPE_PAIR(IS_TRUE, IS_TRUE):
2277 				return 0;
2278 
2279 			case TYPE_PAIR(IS_NULL, IS_TRUE):
2280 				return -1;
2281 
2282 			case TYPE_PAIR(IS_TRUE, IS_NULL):
2283 				return 1;
2284 
2285 			case TYPE_PAIR(IS_STRING, IS_STRING):
2286 				if (Z_STR_P(op1) == Z_STR_P(op2)) {
2287 					return 0;
2288 				}
2289 				return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
2290 
2291 			case TYPE_PAIR(IS_NULL, IS_STRING):
2292 				return Z_STRLEN_P(op2) == 0 ? 0 : -1;
2293 
2294 			case TYPE_PAIR(IS_STRING, IS_NULL):
2295 				return Z_STRLEN_P(op1) == 0 ? 0 : 1;
2296 
2297 			case TYPE_PAIR(IS_LONG, IS_STRING):
2298 				return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2));
2299 
2300 			case TYPE_PAIR(IS_STRING, IS_LONG):
2301 				return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1));
2302 
2303 			case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2304 				if (zend_isnan(Z_DVAL_P(op1))) {
2305 					return 1;
2306 				}
2307 
2308 				return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2));
2309 
2310 			case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2311 				if (zend_isnan(Z_DVAL_P(op2))) {
2312 					return 1;
2313 				}
2314 
2315 				return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1));
2316 
2317 			case TYPE_PAIR(IS_OBJECT, IS_NULL):
2318 				return 1;
2319 
2320 			case TYPE_PAIR(IS_NULL, IS_OBJECT):
2321 				return -1;
2322 
2323 			default:
2324 				if (Z_ISREF_P(op1)) {
2325 					op1 = Z_REFVAL_P(op1);
2326 					continue;
2327 				} else if (Z_ISREF_P(op2)) {
2328 					op2 = Z_REFVAL_P(op2);
2329 					continue;
2330 				}
2331 
2332 				if (Z_TYPE_P(op1) == IS_OBJECT
2333 				 && Z_TYPE_P(op2) == IS_OBJECT
2334 				 && Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2335 					return 0;
2336 				} else if (Z_TYPE_P(op1) == IS_OBJECT) {
2337 					return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
2338 				} else if (Z_TYPE_P(op2) == IS_OBJECT) {
2339 					return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
2340 				}
2341 
2342 				if (!converted) {
2343 					if (Z_TYPE_P(op1) < IS_TRUE) {
2344 						return zval_is_true(op2) ? -1 : 0;
2345 					} else if (Z_TYPE_P(op1) == IS_TRUE) {
2346 						return zval_is_true(op2) ? 0 : 1;
2347 					} else if (Z_TYPE_P(op2) < IS_TRUE) {
2348 						return zval_is_true(op1) ? 1 : 0;
2349 					} else if (Z_TYPE_P(op2) == IS_TRUE) {
2350 						return zval_is_true(op1) ? 0 : -1;
2351 					} else {
2352 						op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
2353 						op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
2354 						if (EG(exception)) {
2355 							return 1; /* to stop comparison of arrays */
2356 						}
2357 						converted = 1;
2358 					}
2359 				} else if (Z_TYPE_P(op1)==IS_ARRAY) {
2360 					return 1;
2361 				} else if (Z_TYPE_P(op2)==IS_ARRAY) {
2362 					return -1;
2363 				} else {
2364 					ZEND_UNREACHABLE();
2365 					zend_throw_error(NULL, "Unsupported operand types");
2366 					return 1;
2367 				}
2368 		}
2369 	}
2370 }
2371 /* }}} */
2372 
2373 /* return int to be compatible with compare_func_t */
hash_zval_identical_function(zval * z1,zval * z2)2374 static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */
2375 {
2376 	/* is_identical_function() returns 1 in case of identity and 0 in case
2377 	 * of a difference;
2378 	 * whereas this comparison function is expected to return 0 on identity,
2379 	 * and non zero otherwise.
2380 	 */
2381 	ZVAL_DEREF(z1);
2382 	ZVAL_DEREF(z2);
2383 	return fast_is_not_identical_function(z1, z2);
2384 }
2385 /* }}} */
2386 
zend_is_identical(const zval * op1,const zval * op2)2387 ZEND_API bool ZEND_FASTCALL zend_is_identical(const zval *op1, const zval *op2) /* {{{ */
2388 {
2389 	if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
2390 		return 0;
2391 	}
2392 	switch (Z_TYPE_P(op1)) {
2393 		case IS_NULL:
2394 		case IS_FALSE:
2395 		case IS_TRUE:
2396 			return 1;
2397 		case IS_LONG:
2398 			return (Z_LVAL_P(op1) == Z_LVAL_P(op2));
2399 		case IS_RESOURCE:
2400 			return (Z_RES_P(op1) == Z_RES_P(op2));
2401 		case IS_DOUBLE:
2402 			return (Z_DVAL_P(op1) == Z_DVAL_P(op2));
2403 		case IS_STRING:
2404 			return zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
2405 		case IS_ARRAY:
2406 			return (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
2407 				zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1) == 0);
2408 		case IS_OBJECT:
2409 			return (Z_OBJ_P(op1) == Z_OBJ_P(op2));
2410 		default:
2411 			return 0;
2412 	}
2413 }
2414 /* }}} */
2415 
is_identical_function(zval * result,zval * op1,zval * op2)2416 ZEND_API zend_result ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2417 {
2418 	ZVAL_BOOL(result, zend_is_identical(op1, op2));
2419 	return SUCCESS;
2420 }
2421 /* }}} */
2422 
is_not_identical_function(zval * result,zval * op1,zval * op2)2423 ZEND_API zend_result ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2424 {
2425 	ZVAL_BOOL(result, !zend_is_identical(op1, op2));
2426 	return SUCCESS;
2427 }
2428 /* }}} */
2429 
is_equal_function(zval * result,zval * op1,zval * op2)2430 ZEND_API zend_result ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2431 {
2432 	ZVAL_BOOL(result, zend_compare(op1, op2) == 0);
2433 	return SUCCESS;
2434 }
2435 /* }}} */
2436 
is_not_equal_function(zval * result,zval * op1,zval * op2)2437 ZEND_API zend_result ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2438 {
2439 	ZVAL_BOOL(result, (zend_compare(op1, op2) != 0));
2440 	return SUCCESS;
2441 }
2442 /* }}} */
2443 
is_smaller_function(zval * result,zval * op1,zval * op2)2444 ZEND_API zend_result ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2) /* {{{ */
2445 {
2446 	ZVAL_BOOL(result, (zend_compare(op1, op2) < 0));
2447 	return SUCCESS;
2448 }
2449 /* }}} */
2450 
is_smaller_or_equal_function(zval * result,zval * op1,zval * op2)2451 ZEND_API zend_result ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2452 {
2453 	ZVAL_BOOL(result, (zend_compare(op1, op2) <= 0));
2454 	return SUCCESS;
2455 }
2456 /* }}} */
2457 
zend_class_implements_interface(const zend_class_entry * class_ce,const zend_class_entry * interface_ce)2458 ZEND_API bool ZEND_FASTCALL zend_class_implements_interface(const zend_class_entry *class_ce, const zend_class_entry *interface_ce) /* {{{ */
2459 {
2460 	uint32_t i;
2461 	ZEND_ASSERT(interface_ce->ce_flags & ZEND_ACC_INTERFACE);
2462 
2463 	if (class_ce->num_interfaces) {
2464 		ZEND_ASSERT(class_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2465 		for (i = 0; i < class_ce->num_interfaces; i++) {
2466 			if (class_ce->interfaces[i] == interface_ce) {
2467 				return 1;
2468 			}
2469 		}
2470 	}
2471 	return 0;
2472 }
2473 /* }}} */
2474 
instanceof_function_slow(const zend_class_entry * instance_ce,const zend_class_entry * ce)2475 ZEND_API bool ZEND_FASTCALL instanceof_function_slow(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2476 {
2477 	ZEND_ASSERT(instance_ce != ce && "Should have been checked already");
2478 	if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2479 		uint32_t i;
2480 
2481 		if (instance_ce->num_interfaces) {
2482 			ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2483 			for (i = 0; i < instance_ce->num_interfaces; i++) {
2484 				if (instance_ce->interfaces[i] == ce) {
2485 					return 1;
2486 				}
2487 			}
2488 		}
2489 		return 0;
2490 	} else {
2491 		while (1) {
2492 			instance_ce = instance_ce->parent;
2493 			if (instance_ce == ce) {
2494 				return 1;
2495 			}
2496 			if (instance_ce == NULL) {
2497 				return 0;
2498 			}
2499 		}
2500 	}
2501 }
2502 /* }}} */
2503 
2504 #define LOWER_CASE 1
2505 #define UPPER_CASE 2
2506 #define NUMERIC 3
2507 
zend_string_only_has_ascii_alphanumeric(const zend_string * str)2508 ZEND_API bool zend_string_only_has_ascii_alphanumeric(const zend_string *str)
2509 {
2510 	const char *p = ZSTR_VAL(str);
2511 	const char *e = ZSTR_VAL(str) + ZSTR_LEN(str);
2512 	while (p < e) {
2513 		char c = *p++;
2514 		if (UNEXPECTED( c < '0' || c > 'z' || (c < 'a' && c > 'Z') || (c < 'A' && c > '9') ) ) {
2515 			return false;
2516 		}
2517 	}
2518 	return true;
2519 }
2520 
increment_string(zval * str)2521 static bool ZEND_FASTCALL increment_string(zval *str) /* {{{ */
2522 {
2523 	int carry=0;
2524 	size_t pos=Z_STRLEN_P(str)-1;
2525 	char *s;
2526 	zend_string *t;
2527 	int last=0; /* Shut up the compiler warning */
2528 	int ch;
2529 
2530 	if (UNEXPECTED(Z_STRLEN_P(str) == 0)) {
2531 		zend_error(E_DEPRECATED, "Increment on non-alphanumeric string is deprecated");
2532 		if (EG(exception)) {
2533 			return false;
2534 		}
2535 		/* A userland error handler can change the type from string to something else */
2536 		zval_ptr_dtor(str);
2537 		ZVAL_CHAR(str, '1');
2538 		return true;
2539 	}
2540 
2541 	if (UNEXPECTED(!zend_string_only_has_ascii_alphanumeric(Z_STR_P(str)))) {
2542 		zend_string *zstr = Z_STR_P(str);
2543 		zend_string_addref(zstr);
2544 		zend_error(E_DEPRECATED, "Increment on non-alphanumeric string is deprecated");
2545 		if (EG(exception)) {
2546 			zend_string_release(zstr);
2547 			return false;
2548 		}
2549 		zval_ptr_dtor(str);
2550 		ZVAL_STR(str, zstr);
2551 	}
2552 
2553 	if (!Z_REFCOUNTED_P(str)) {
2554 		Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2555 		Z_TYPE_INFO_P(str) = IS_STRING_EX;
2556 	} else if (Z_REFCOUNT_P(str) > 1) {
2557 		/* Only release string after allocation succeeded. */
2558 		zend_string *orig_str = Z_STR_P(str);
2559 		Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2560 		GC_DELREF(orig_str);
2561 	} else {
2562 		zend_string_forget_hash_val(Z_STR_P(str));
2563 	}
2564 	s = Z_STRVAL_P(str);
2565 
2566 	do {
2567 		ch = s[pos];
2568 		if (ch >= 'a' && ch <= 'z') {
2569 			if (ch == 'z') {
2570 				s[pos] = 'a';
2571 				carry=1;
2572 			} else {
2573 				s[pos]++;
2574 				carry=0;
2575 			}
2576 			last=LOWER_CASE;
2577 		} else if (ch >= 'A' && ch <= 'Z') {
2578 			if (ch == 'Z') {
2579 				s[pos] = 'A';
2580 				carry=1;
2581 			} else {
2582 				s[pos]++;
2583 				carry=0;
2584 			}
2585 			last=UPPER_CASE;
2586 		} else if (ch >= '0' && ch <= '9') {
2587 			if (ch == '9') {
2588 				s[pos] = '0';
2589 				carry=1;
2590 			} else {
2591 				s[pos]++;
2592 				carry=0;
2593 			}
2594 			last = NUMERIC;
2595 		} else {
2596 			carry=0;
2597 			break;
2598 		}
2599 		if (carry == 0) {
2600 			break;
2601 		}
2602 	} while (pos-- > 0);
2603 
2604 	if (carry) {
2605 		t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
2606 		memcpy(ZSTR_VAL(t) + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
2607 		ZSTR_VAL(t)[Z_STRLEN_P(str) + 1] = '\0';
2608 		switch (last) {
2609 			case NUMERIC:
2610 				ZSTR_VAL(t)[0] = '1';
2611 				break;
2612 			case UPPER_CASE:
2613 				ZSTR_VAL(t)[0] = 'A';
2614 				break;
2615 			case LOWER_CASE:
2616 				ZSTR_VAL(t)[0] = 'a';
2617 				break;
2618 		}
2619 		zend_string_free(Z_STR_P(str));
2620 		ZVAL_NEW_STR(str, t);
2621 	}
2622 	return true;
2623 }
2624 /* }}} */
2625 
increment_function(zval * op1)2626 ZEND_API zend_result ZEND_FASTCALL increment_function(zval *op1) /* {{{ */
2627 {
2628 try_again:
2629 	switch (Z_TYPE_P(op1)) {
2630 		case IS_LONG:
2631 			fast_long_increment_function(op1);
2632 			break;
2633 		case IS_DOUBLE:
2634 			Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2635 			break;
2636 		case IS_NULL:
2637 			ZVAL_LONG(op1, 1);
2638 			break;
2639 		case IS_STRING: {
2640 				zend_long lval;
2641 				double dval;
2642 
2643 				switch (is_numeric_str_function(Z_STR_P(op1), &lval, &dval)) {
2644 					case IS_LONG:
2645 						zval_ptr_dtor_str(op1);
2646 						if (lval == ZEND_LONG_MAX) {
2647 							/* switch to double */
2648 							double d = (double)lval;
2649 							ZVAL_DOUBLE(op1, d+1);
2650 						} else {
2651 							ZVAL_LONG(op1, lval+1);
2652 						}
2653 						break;
2654 					case IS_DOUBLE:
2655 						zval_ptr_dtor_str(op1);
2656 						ZVAL_DOUBLE(op1, dval+1);
2657 						break;
2658 					default:
2659 						/* Perl style string increment */
2660 						increment_string(op1);
2661 						if (EG(exception)) {
2662 							return FAILURE;
2663 						}
2664 						break;
2665 				}
2666 			}
2667 			break;
2668 		case IS_FALSE:
2669 		case IS_TRUE: {
2670 			/* Error handler can undef/change type of op1, save it and reset it in case those cases */
2671 			zval copy;
2672 			ZVAL_COPY_VALUE(&copy, op1);
2673 			zend_error(E_WARNING, "Increment on type bool has no effect, this will change in the next major version of PHP");
2674 			zval_ptr_dtor(op1);
2675 			ZVAL_COPY_VALUE(op1, &copy);
2676 			if (EG(exception)) {
2677 				return FAILURE;
2678 			}
2679 			break;
2680 		}
2681 		case IS_REFERENCE:
2682 			op1 = Z_REFVAL_P(op1);
2683 			goto try_again;
2684 		case IS_OBJECT: {
2685 			if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2686 				zval op2;
2687 				ZVAL_LONG(&op2, 1);
2688 				if (Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2) == SUCCESS) {
2689 					return SUCCESS;
2690 				}
2691 			}
2692 			zval tmp;
2693 			if (Z_OBJ_HT_P(op1)->cast_object(Z_OBJ_P(op1), &tmp, _IS_NUMBER) == SUCCESS) {
2694 				ZEND_ASSERT(Z_TYPE(tmp) == IS_LONG || Z_TYPE(tmp) == IS_DOUBLE);
2695 				zval_ptr_dtor(op1);
2696 				ZVAL_COPY_VALUE(op1, &tmp);
2697 				goto try_again;
2698 			}
2699 			ZEND_FALLTHROUGH;
2700 		}
2701 		case IS_RESOURCE:
2702 		case IS_ARRAY:
2703 			zend_type_error("Cannot increment %s", zend_zval_value_name(op1));
2704 			return FAILURE;
2705 		EMPTY_SWITCH_DEFAULT_CASE()
2706 	}
2707 	return SUCCESS;
2708 }
2709 /* }}} */
2710 
decrement_function(zval * op1)2711 ZEND_API zend_result ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */
2712 {
2713 	zend_long lval;
2714 	double dval;
2715 
2716 try_again:
2717 	switch (Z_TYPE_P(op1)) {
2718 		case IS_LONG:
2719 			fast_long_decrement_function(op1);
2720 			break;
2721 		case IS_DOUBLE:
2722 			Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2723 			break;
2724 		case IS_STRING:		/* Like perl we only support string increment */
2725 			if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2726 				zend_error(E_DEPRECATED, "Decrement on empty string is deprecated as non-numeric");
2727 				if (EG(exception)) {
2728 					return FAILURE;
2729 				}
2730 				/* A userland error handler can change the type from string to something else */
2731 				zval_ptr_dtor(op1);
2732 				ZVAL_LONG(op1, -1);
2733 				break;
2734 			}
2735 			switch (is_numeric_str_function(Z_STR_P(op1), &lval, &dval)) {
2736 				case IS_LONG:
2737 					zval_ptr_dtor_str(op1);
2738 					if (lval == ZEND_LONG_MIN) {
2739 						double d = (double)lval;
2740 						ZVAL_DOUBLE(op1, d-1);
2741 					} else {
2742 						ZVAL_LONG(op1, lval-1);
2743 					}
2744 					break;
2745 				case IS_DOUBLE:
2746 					zval_ptr_dtor_str(op1);
2747 					ZVAL_DOUBLE(op1, dval - 1);
2748 					break;
2749 				default: {
2750 					/* Error handler can unset the variable */
2751 					zend_string *zstr = Z_STR_P(op1);
2752 					zend_string_addref(zstr);
2753 					zend_error(E_DEPRECATED, "Decrement on non-numeric string has no effect and is deprecated");
2754 					if (EG(exception)) {
2755 						zend_string_release(zstr);
2756 						return FAILURE;
2757 					}
2758 					zval_ptr_dtor(op1);
2759 					ZVAL_STR(op1, zstr);
2760 				}
2761 			}
2762 			break;
2763 		case IS_NULL: {
2764 			/* Error handler can undef/change type of op1, save it and reset it in case those cases */
2765 			zval copy;
2766 			ZVAL_COPY_VALUE(&copy, op1);
2767 			zend_error(E_WARNING, "Decrement on type null has no effect, this will change in the next major version of PHP");
2768 			zval_ptr_dtor(op1);
2769 			ZVAL_COPY_VALUE(op1, &copy);
2770 			if (EG(exception)) {
2771 				return FAILURE;
2772 			}
2773 			break;
2774 		}
2775 		case IS_FALSE:
2776 		case IS_TRUE: {
2777 			/* Error handler can undef/change type of op1, save it and reset it in case those cases */
2778 			zval copy;
2779 			ZVAL_COPY_VALUE(&copy, op1);
2780 			zend_error(E_WARNING, "Decrement on type bool has no effect, this will change in the next major version of PHP");
2781 			zval_ptr_dtor(op1);
2782 			ZVAL_COPY_VALUE(op1, &copy);
2783 			if (EG(exception)) {
2784 				return FAILURE;
2785 			}
2786 			break;
2787 		}
2788 		case IS_REFERENCE:
2789 			op1 = Z_REFVAL_P(op1);
2790 			goto try_again;
2791 		case IS_OBJECT: {
2792 			if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2793 				zval op2;
2794 				ZVAL_LONG(&op2, 1);
2795 				if (Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2) == SUCCESS) {
2796 					return SUCCESS;
2797 				}
2798 			}
2799 			zval tmp;
2800 			if (Z_OBJ_HT_P(op1)->cast_object(Z_OBJ_P(op1), &tmp, _IS_NUMBER) == SUCCESS) {
2801 				ZEND_ASSERT(Z_TYPE(tmp) == IS_LONG || Z_TYPE(tmp) == IS_DOUBLE);
2802 				zval_ptr_dtor(op1);
2803 				ZVAL_COPY_VALUE(op1, &tmp);
2804 				goto try_again;
2805 			}
2806 			ZEND_FALLTHROUGH;
2807 		}
2808 		case IS_RESOURCE:
2809 		case IS_ARRAY:
2810 			zend_type_error("Cannot decrement %s", zend_zval_value_name(op1));
2811 			return FAILURE;
2812 		EMPTY_SWITCH_DEFAULT_CASE()
2813 	}
2814 
2815 	return SUCCESS;
2816 }
2817 /* }}} */
2818 
zend_is_true(const zval * op)2819 ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op) /* {{{ */
2820 {
2821 	return i_zend_is_true(op);
2822 }
2823 /* }}} */
2824 
zend_object_is_true(const zval * op)2825 ZEND_API bool ZEND_FASTCALL zend_object_is_true(const zval *op) /* {{{ */
2826 {
2827 	zend_object *zobj = Z_OBJ_P(op);
2828 	zval tmp;
2829 	if (zobj->handlers->cast_object(zobj, &tmp, _IS_BOOL) == SUCCESS) {
2830 		return Z_TYPE(tmp) == IS_TRUE;
2831 	}
2832 	zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to bool", ZSTR_VAL(zobj->ce->name));
2833 	return false;
2834 }
2835 /* }}} */
2836 
zend_update_current_locale(void)2837 ZEND_API void zend_update_current_locale(void) /* {{{ */
2838 {
2839 #ifdef ZEND_USE_TOLOWER_L
2840 # if defined(ZEND_WIN32) && defined(_MSC_VER)
2841 	current_locale = _get_current_locale();
2842 # else
2843 	current_locale = uselocale(0);
2844 # endif
2845 #endif
2846 #if defined(ZEND_WIN32) && defined(_MSC_VER)
2847 	if (MB_CUR_MAX > 1) {
2848 		unsigned int cp = ___lc_codepage_func();
2849 		CG(variable_width_locale) = 1;
2850 		// TODO: EUC-* are also ASCII compatible ???
2851 		CG(ascii_compatible_locale) =
2852 			cp == 65001; /* UTF-8 */
2853 	} else {
2854 		CG(variable_width_locale) = 0;
2855 		CG(ascii_compatible_locale) = 1;
2856 	}
2857 #elif defined(MB_CUR_MAX)
2858 	/* Check if current locale uses variable width encoding */
2859 	if (MB_CUR_MAX > 1) {
2860 #ifdef HAVE_NL_LANGINFO
2861 		const char *charmap = nl_langinfo(CODESET);
2862 #else
2863 		char buf[16];
2864 		const char *charmap = NULL;
2865 		const char *locale = setlocale(LC_CTYPE, NULL);
2866 
2867 		if (locale) {
2868 			const char *dot = strchr(locale, '.');
2869 			const char *modifier;
2870 
2871 			if (dot) {
2872 				dot++;
2873 				modifier = strchr(dot, '@');
2874 				if (!modifier) {
2875 					charmap = dot;
2876 				} else if (modifier - dot < sizeof(buf)) {
2877 					memcpy(buf, dot, modifier - dot);
2878                     buf[modifier - dot] = '\0';
2879                     charmap = buf;
2880 				}
2881 			}
2882 		}
2883 #endif
2884 		CG(variable_width_locale) = 1;
2885 		CG(ascii_compatible_locale) = 0;
2886 
2887 		if (charmap) {
2888 			size_t len = strlen(charmap);
2889 			static const char *ascii_compatible_charmaps[] = {
2890 				"utf-8",
2891 				"utf8",
2892 				// TODO: EUC-* are also ASCII compatible ???
2893 				NULL
2894 			};
2895 			const char **p;
2896 			/* Check if current locale is ASCII compatible */
2897 			for (p = ascii_compatible_charmaps; *p; p++) {
2898 				if (zend_binary_strcasecmp(charmap, len, *p, strlen(*p)) == 0) {
2899 					CG(ascii_compatible_locale) = 1;
2900 					break;
2901 				}
2902 			}
2903 		}
2904 
2905 	} else {
2906 		CG(variable_width_locale) = 0;
2907 		CG(ascii_compatible_locale) = 1;
2908 	}
2909 #else
2910 	/* We can't determine current charset. Assume the worst case */
2911 	CG(variable_width_locale) = 1;
2912 	CG(ascii_compatible_locale) = 0;
2913 #endif
2914 }
2915 /* }}} */
2916 
zend_reset_lc_ctype_locale(void)2917 ZEND_API void zend_reset_lc_ctype_locale(void)
2918 {
2919 	/* Use the C.UTF-8 locale so that readline can process UTF-8 input, while not interfering
2920 	 * with single-byte locale-dependent functions used by PHP. */
2921 	if (!setlocale(LC_CTYPE, "C.UTF-8")) {
2922 		setlocale(LC_CTYPE, "C");
2923 	}
2924 }
2925 
zend_str_tolower_impl(char * dest,const char * str,size_t length)2926 static zend_always_inline void zend_str_tolower_impl(char *dest, const char *str, size_t length) /* {{{ */ {
2927 	unsigned char *p = (unsigned char*)str;
2928 	unsigned char *q = (unsigned char*)dest;
2929 	unsigned char *end = p + length;
2930 #ifdef HAVE_BLOCKCONV
2931 	if (length >= BLOCKCONV_STRIDE) {
2932 		BLOCKCONV_INIT_RANGE('A', 'Z');
2933 		BLOCKCONV_INIT_DELTA('a' - 'A');
2934 		do {
2935 			BLOCKCONV_LOAD(p);
2936 			BLOCKCONV_STORE(q);
2937 			p += BLOCKCONV_STRIDE;
2938 			q += BLOCKCONV_STRIDE;
2939 		} while (p + BLOCKCONV_STRIDE <= end);
2940 	}
2941 #endif
2942 	while (p < end) {
2943 		*q++ = zend_tolower_ascii(*p++);
2944 	}
2945 }
2946 /* }}} */
2947 
zend_str_toupper_impl(char * dest,const char * str,size_t length)2948 static zend_always_inline void zend_str_toupper_impl(char *dest, const char *str, size_t length) /* {{{ */ {
2949 	unsigned char *p = (unsigned char*)str;
2950 	unsigned char *q = (unsigned char*)dest;
2951 	unsigned char *end = p + length;
2952 #ifdef HAVE_BLOCKCONV
2953 	if (length >= BLOCKCONV_STRIDE) {
2954 		BLOCKCONV_INIT_RANGE('a', 'z');
2955 		BLOCKCONV_INIT_DELTA('A' - 'a');
2956 		do {
2957 			BLOCKCONV_LOAD(p);
2958 			BLOCKCONV_STORE(q);
2959 			p += BLOCKCONV_STRIDE;
2960 			q += BLOCKCONV_STRIDE;
2961 		} while (p + BLOCKCONV_STRIDE <= end);
2962 	}
2963 #endif
2964 	while (p < end) {
2965 		*q++ = zend_toupper_ascii(*p++);
2966 	}
2967 }
2968 /* }}} */
2969 
zend_str_tolower_copy(char * dest,const char * source,size_t length)2970 ZEND_API char* ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
2971 {
2972 	zend_str_tolower_impl(dest, source, length);
2973 	dest[length] = '\0';
2974 	return dest;
2975 }
2976 /* }}} */
2977 
zend_str_toupper_copy(char * dest,const char * source,size_t length)2978 ZEND_API char* ZEND_FASTCALL zend_str_toupper_copy(char *dest, const char *source, size_t length) /* {{{ */
2979 {
2980 	zend_str_toupper_impl(dest, source, length);
2981 	dest[length] = '\0';
2982 	return dest;
2983 }
2984 /* }}} */
2985 
zend_str_tolower_dup(const char * source,size_t length)2986 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2987 {
2988 	return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2989 }
2990 /* }}} */
2991 
zend_str_toupper_dup(const char * source,size_t length)2992 ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup(const char *source, size_t length) /* {{{ */
2993 {
2994 	return zend_str_toupper_copy((char *)emalloc(length+1), source, length);
2995 }
2996 /* }}} */
2997 
zend_str_tolower(char * str,size_t length)2998 ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length) /* {{{ */
2999 {
3000 	zend_str_tolower_impl(str, (const char*)str, length);
3001 }
3002 /* }}} */
3003 
zend_str_toupper(char * str,size_t length)3004 ZEND_API void ZEND_FASTCALL zend_str_toupper(char *str, size_t length) /* {{{ */
3005 {
3006 	zend_str_toupper_impl(str, (const char*)str, length);
3007 }
3008 /* }}} */
3009 
3010 
zend_str_tolower_dup_ex(const char * source,size_t length)3011 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length) /* {{{ */
3012 {
3013 	const unsigned char *p = (const unsigned char*)source;
3014 	const unsigned char *end = p + length;
3015 
3016 	while (p < end) {
3017 		if (*p != zend_tolower_ascii(*p)) {
3018 			char *res = (char*)emalloc(length + 1);
3019 			unsigned char *r;
3020 
3021 			if (p != (const unsigned char*)source) {
3022 				memcpy(res, source, p - (const unsigned char*)source);
3023 			}
3024 			r = (unsigned char*)p + (res - source);
3025 			zend_str_tolower_impl((char *)r, (const char*)p, end - p);
3026 			res[length] = '\0';
3027 			return res;
3028 		}
3029 		p++;
3030 	}
3031 	return NULL;
3032 }
3033 /* }}} */
3034 
zend_str_toupper_dup_ex(const char * source,size_t length)3035 ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup_ex(const char *source, size_t length) /* {{{ */
3036 {
3037 	const unsigned char *p = (const unsigned char*)source;
3038 	const unsigned char *end = p + length;
3039 
3040 	while (p < end) {
3041 		if (*p != zend_toupper_ascii(*p)) {
3042 			char *res = (char*)emalloc(length + 1);
3043 			unsigned char *r;
3044 
3045 			if (p != (const unsigned char*)source) {
3046 				memcpy(res, source, p - (const unsigned char*)source);
3047 			}
3048 			r = (unsigned char*)p + (res - source);
3049 			zend_str_toupper_impl((char *)r, (const char*)p, end - p);
3050 			res[length] = '\0';
3051 			return res;
3052 		}
3053 		p++;
3054 	}
3055 	return NULL;
3056 }
3057 /* }}} */
3058 
zend_string_tolower_ex(zend_string * str,bool persistent)3059 ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) /* {{{ */
3060 {
3061 	size_t length = ZSTR_LEN(str);
3062 	unsigned char *p = (unsigned char *) ZSTR_VAL(str);
3063 	unsigned char *end = p + length;
3064 
3065 #ifdef HAVE_BLOCKCONV
3066 	BLOCKCONV_INIT_RANGE('A', 'Z');
3067 	while (p + BLOCKCONV_STRIDE <= end) {
3068 		BLOCKCONV_LOAD(p);
3069 		if (BLOCKCONV_FOUND()) {
3070 			zend_string *res = zend_string_alloc(length, persistent);
3071 			memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
3072 			unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
3073 
3074 			/* Lowercase the chunk we already compared. */
3075 			BLOCKCONV_INIT_DELTA('a' - 'A');
3076 			BLOCKCONV_STORE(q);
3077 
3078 			/* Lowercase the rest of the string. */
3079 			p += BLOCKCONV_STRIDE;
3080 			q += BLOCKCONV_STRIDE;
3081 			zend_str_tolower_impl((char *) q, (const char *) p, end - p);
3082 			ZSTR_VAL(res)[length] = '\0';
3083 			return res;
3084 		}
3085 		p += BLOCKCONV_STRIDE;
3086 	}
3087 #endif
3088 
3089 	while (p < end) {
3090 		if (*p != zend_tolower_ascii(*p)) {
3091 			zend_string *res = zend_string_alloc(length, persistent);
3092 			memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
3093 
3094 			unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
3095 			while (p < end) {
3096 				*q++ = zend_tolower_ascii(*p++);
3097 			}
3098 			ZSTR_VAL(res)[length] = '\0';
3099 			return res;
3100 		}
3101 		p++;
3102 	}
3103 
3104 	return zend_string_copy(str);
3105 }
3106 /* }}} */
3107 
zend_string_toupper_ex(zend_string * str,bool persistent)3108 ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent) /* {{{ */
3109 {
3110 	size_t length = ZSTR_LEN(str);
3111 	unsigned char *p = (unsigned char *) ZSTR_VAL(str);
3112 	unsigned char *end = p + length;
3113 
3114 #ifdef HAVE_BLOCKCONV
3115 	BLOCKCONV_INIT_RANGE('a', 'z');
3116 	while (p + BLOCKCONV_STRIDE <= end) {
3117 		BLOCKCONV_LOAD(p);
3118 		if (BLOCKCONV_FOUND()) {
3119 			zend_string *res = zend_string_alloc(length, persistent);
3120 			memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
3121 			unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str));
3122 
3123 			/* Uppercase the chunk we already compared. */
3124 			BLOCKCONV_INIT_DELTA('A' - 'a');
3125 			BLOCKCONV_STORE(q);
3126 
3127 			/* Uppercase the rest of the string. */
3128 			p += BLOCKCONV_STRIDE;
3129 			q += BLOCKCONV_STRIDE;
3130 			zend_str_toupper_impl((char *) q, (const char *) p, end - p);
3131 			ZSTR_VAL(res)[length] = '\0';
3132 			return res;
3133 		}
3134 		p += BLOCKCONV_STRIDE;
3135 	}
3136 #endif
3137 
3138 	while (p < end) {
3139 		if (*p != zend_toupper_ascii(*p)) {
3140 			zend_string *res = zend_string_alloc(length, persistent);
3141 			memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
3142 
3143 			unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str));
3144 			while (p < end) {
3145 				*q++ = zend_toupper_ascii(*p++);
3146 			}
3147 			ZSTR_VAL(res)[length] = '\0';
3148 			return res;
3149 		}
3150 		p++;
3151 	}
3152 
3153 	return zend_string_copy(str);
3154 }
3155 /* }}} */
3156 
zend_binary_strcmp(const char * s1,size_t len1,const char * s2,size_t len2)3157 ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
3158 {
3159 	int retval;
3160 
3161 	if (s1 == s2) {
3162 		return 0;
3163 	}
3164 	retval = memcmp(s1, s2, MIN(len1, len2));
3165 	if (!retval) {
3166 		return ZEND_THREEWAY_COMPARE(len1, len2);
3167 	} else {
3168 		return retval;
3169 	}
3170 }
3171 /* }}} */
3172 
zend_binary_strncmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)3173 ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
3174 {
3175 	int retval;
3176 
3177 	if (s1 == s2) {
3178 		return 0;
3179 	}
3180 	retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
3181 	if (!retval) {
3182 		return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
3183 	} else {
3184 		return retval;
3185 	}
3186 }
3187 /* }}} */
3188 
zend_binary_strcasecmp(const char * s1,size_t len1,const char * s2,size_t len2)3189 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
3190 {
3191 	size_t len;
3192 	int c1, c2;
3193 
3194 	if (s1 == s2) {
3195 		return 0;
3196 	}
3197 
3198 	len = MIN(len1, len2);
3199 	while (len--) {
3200 		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
3201 		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
3202 		if (c1 != c2) {
3203 			return c1 - c2;
3204 		}
3205 	}
3206 
3207 	return ZEND_THREEWAY_COMPARE(len1, len2);
3208 }
3209 /* }}} */
3210 
zend_binary_strncasecmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)3211 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
3212 {
3213 	size_t len;
3214 	int c1, c2;
3215 
3216 	if (s1 == s2) {
3217 		return 0;
3218 	}
3219 	len = MIN(length, MIN(len1, len2));
3220 	while (len--) {
3221 		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
3222 		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
3223 		if (c1 != c2) {
3224 			return c1 - c2;
3225 		}
3226 	}
3227 
3228 	return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
3229 }
3230 /* }}} */
3231 
zend_binary_strcasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2)3232 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
3233 {
3234 	size_t len;
3235 	int c1, c2;
3236 
3237 	if (s1 == s2) {
3238 		return 0;
3239 	}
3240 
3241 	len = MIN(len1, len2);
3242 	while (len--) {
3243 		c1 = zend_tolower((int)*(unsigned char *)s1++);
3244 		c2 = zend_tolower((int)*(unsigned char *)s2++);
3245 		if (c1 != c2) {
3246 			return c1 - c2;
3247 		}
3248 	}
3249 
3250 	return ZEND_THREEWAY_COMPARE(len1, len2);
3251 }
3252 /* }}} */
3253 
zend_binary_strncasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)3254 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
3255 {
3256 	size_t len;
3257 	int c1, c2;
3258 
3259 	if (s1 == s2) {
3260 		return 0;
3261 	}
3262 	len = MIN(length, MIN(len1, len2));
3263 	while (len--) {
3264 		c1 = zend_tolower((int)*(unsigned char *)s1++);
3265 		c2 = zend_tolower((int)*(unsigned char *)s2++);
3266 		if (c1 != c2) {
3267 			return c1 - c2;
3268 		}
3269 	}
3270 
3271 	return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
3272 }
3273 /* }}} */
3274 
zend_binary_zval_strcmp(zval * s1,zval * s2)3275 ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
3276 {
3277 	return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
3278 }
3279 /* }}} */
3280 
zend_binary_zval_strncmp(zval * s1,zval * s2,zval * s3)3281 ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
3282 {
3283 	return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
3284 }
3285 /* }}} */
3286 
zendi_smart_streq(zend_string * s1,zend_string * s2)3287 ZEND_API bool ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2) /* {{{ */
3288 {
3289 	uint8_t ret1, ret2;
3290 	int oflow1, oflow2;
3291 	zend_long lval1 = 0, lval2 = 0;
3292 	double dval1 = 0.0, dval2 = 0.0;
3293 
3294 	if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
3295 		(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
3296 #if ZEND_ULONG_MAX == 0xFFFFFFFF
3297 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
3298 			((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
3299 			|| (oflow1 == -1 && dval1 < -9007199254740991.))) {
3300 #else
3301 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
3302 #endif
3303 			/* both values are integers overflown to the same side, and the
3304 			 * double comparison may have resulted in crucial accuracy lost */
3305 			goto string_cmp;
3306 		}
3307 		if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
3308 			if (ret1 != IS_DOUBLE) {
3309 				if (oflow2) {
3310 					/* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
3311 					return 0;
3312 				}
3313 				dval1 = (double) lval1;
3314 			} else if (ret2 != IS_DOUBLE) {
3315 				if (oflow1) {
3316 					return 0;
3317 				}
3318 				dval2 = (double) lval2;
3319 			} else if (dval1 == dval2 && !zend_finite(dval1)) {
3320 				/* Both values overflowed and have the same sign,
3321 				 * so a numeric comparison would be inaccurate */
3322 				goto string_cmp;
3323 			}
3324 			return dval1 == dval2;
3325 		} else { /* they both have to be long's */
3326 			return lval1 == lval2;
3327 		}
3328 	} else {
3329 string_cmp:
3330 		return zend_string_equal_content(s1, s2);
3331 	}
3332 }
3333 /* }}} */
3334 
3335 ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2) /* {{{ */
3336 {
3337 	uint8_t ret1, ret2;
3338 	int oflow1, oflow2;
3339 	zend_long lval1 = 0, lval2 = 0;
3340 	double dval1 = 0.0, dval2 = 0.0;
3341 
3342 	if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
3343 		(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
3344 #if ZEND_ULONG_MAX == 0xFFFFFFFF
3345 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
3346 			((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
3347 			|| (oflow1 == -1 && dval1 < -9007199254740991.))) {
3348 #else
3349 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
3350 #endif
3351 			/* both values are integers overflowed to the same side, and the
3352 			 * double comparison may have resulted in crucial accuracy lost */
3353 			goto string_cmp;
3354 		}
3355 		if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
3356 			if (ret1 != IS_DOUBLE) {
3357 				if (oflow2) {
3358 					/* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
3359 					return -1 * oflow2;
3360 				}
3361 				dval1 = (double) lval1;
3362 			} else if (ret2 != IS_DOUBLE) {
3363 				if (oflow1) {
3364 					return oflow1;
3365 				}
3366 				dval2 = (double) lval2;
3367 			} else if (dval1 == dval2 && !zend_finite(dval1)) {
3368 				/* Both values overflowed and have the same sign,
3369 				 * so a numeric comparison would be inaccurate */
3370 				goto string_cmp;
3371 			}
3372 			dval1 = dval1 - dval2;
3373 			return ZEND_NORMALIZE_BOOL(dval1);
3374 		} else { /* they both have to be long's */
3375 			return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
3376 		}
3377 	} else {
3378 		int strcmp_ret;
3379 string_cmp:
3380 		strcmp_ret = zend_binary_strcmp(s1->val, s1->len, s2->val, s2->len);
3381 		return ZEND_NORMALIZE_BOOL(strcmp_ret);
3382 	}
3383 }
3384 /* }}} */
3385 
3386 static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */
3387 {
3388 	return zend_compare(z1, z2);
3389 }
3390 /* }}} */
3391 
3392 ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */
3393 {
3394 	return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
3395 }
3396 /* }}} */
3397 
3398 ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */
3399 {
3400 	return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2));
3401 }
3402 /* }}} */
3403 
3404 ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */
3405 {
3406 	if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
3407 		return 0;
3408 	}
3409 
3410 	if (Z_OBJ_HT_P(o1)->compare == NULL) {
3411 		return 1;
3412 	} else {
3413 		return Z_OBJ_HT_P(o1)->compare(o1, o2);
3414 	}
3415 }
3416 /* }}} */
3417 
3418 ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */
3419 {
3420 	if ((zend_ulong)num <= 9) {
3421 		return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3422 	} else {
3423 		char buf[MAX_LENGTH_OF_LONG + 1];
3424 		char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
3425 		zend_string *str =  zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3426 		GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3427 		return str;
3428 	}
3429 }
3430 /* }}} */
3431 
3432 ZEND_API zend_string* ZEND_FASTCALL zend_ulong_to_str(zend_ulong num)
3433 {
3434 	if (num <= 9) {
3435 		return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3436 	} else {
3437 		char buf[MAX_LENGTH_OF_LONG + 1];
3438 		char *res = zend_print_ulong_to_buf(buf + sizeof(buf) - 1, num);
3439 		zend_string *str =  zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3440 		GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3441 		return str;
3442 	}
3443 }
3444 
3445 /* buf points to the END of the buffer */
3446 static zend_always_inline char *zend_print_u64_to_buf(char *buf, uint64_t num64) {
3447 #if SIZEOF_ZEND_LONG == 8
3448 	return zend_print_ulong_to_buf(buf, num64);
3449 #else
3450 	*buf = '\0';
3451 	while (num64 > ZEND_ULONG_MAX) {
3452 		*--buf = (char) (num64 % 10) + '0';
3453 		num64 /= 10;
3454 	}
3455 
3456 	zend_ulong num = (zend_ulong) num64;
3457 	do {
3458 		*--buf = (char) (num % 10) + '0';
3459 		num /= 10;
3460 	} while (num > 0);
3461 	return buf;
3462 #endif
3463 }
3464 
3465 /* buf points to the END of the buffer */
3466 static zend_always_inline char *zend_print_i64_to_buf(char *buf, int64_t num) {
3467 	if (num < 0) {
3468 	    char *result = zend_print_u64_to_buf(buf, ~((uint64_t) num) + 1);
3469 	    *--result = '-';
3470 		return result;
3471 	} else {
3472 	    return zend_print_u64_to_buf(buf, num);
3473 	}
3474 }
3475 
3476 ZEND_API zend_string* ZEND_FASTCALL zend_u64_to_str(uint64_t num)
3477 {
3478 	if (num <= 9) {
3479 		return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3480 	} else {
3481 		char buf[20 + 1];
3482 		char *res = zend_print_u64_to_buf(buf + sizeof(buf) - 1, num);
3483 		zend_string *str =  zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3484 		GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3485 		return str;
3486 	}
3487 }
3488 
3489 ZEND_API zend_string* ZEND_FASTCALL zend_i64_to_str(int64_t num)
3490 {
3491 	if ((uint64_t)num <= 9) {
3492 		return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3493 	} else {
3494 		char buf[20 + 1];
3495 		char *res = zend_print_i64_to_buf(buf + sizeof(buf) - 1, num);
3496 		zend_string *str =  zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3497 		GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3498 		return str;
3499 	}
3500 }
3501 
3502 ZEND_API zend_string* ZEND_FASTCALL zend_double_to_str(double num)
3503 {
3504 	char buf[ZEND_DOUBLE_MAX_LENGTH];
3505 	/* Model snprintf precision behavior. */
3506 	int precision = (int) EG(precision);
3507 	zend_gcvt(num, precision ? precision : 1, '.', 'E', buf);
3508 	zend_string *str =  zend_string_init(buf, strlen(buf), 0);
3509 	GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3510 	return str;
3511 }
3512 
3513 ZEND_API uint8_t ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */
3514 {
3515 	return is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), lval, dval, false);
3516 }
3517 /* }}} */
3518 
3519 ZEND_API uint8_t ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval,
3520 	double *dval, bool allow_errors, int *oflow_info, bool *trailing_data) /* {{{ */
3521 {
3522 	const char *ptr;
3523 	int digits = 0, dp_or_e = 0;
3524 	double local_dval = 0.0;
3525 	uint8_t type;
3526 	zend_ulong tmp_lval = 0;
3527 	int neg = 0;
3528 
3529 	if (!length) {
3530 		return 0;
3531 	}
3532 
3533 	if (oflow_info != NULL) {
3534 		*oflow_info = 0;
3535 	}
3536 	if (trailing_data != NULL) {
3537 		*trailing_data = false;
3538 	}
3539 
3540 	/* Skip any whitespace
3541 	 * This is much faster than the isspace() function */
3542 	while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
3543 		str++;
3544 		length--;
3545 	}
3546 	ptr = str;
3547 
3548 	if (*ptr == '-') {
3549 		neg = 1;
3550 		ptr++;
3551 	} else if (*ptr == '+') {
3552 		ptr++;
3553 	}
3554 
3555 	if (ZEND_IS_DIGIT(*ptr)) {
3556 		/* Skip any leading 0s */
3557 		while (*ptr == '0') {
3558 			ptr++;
3559 		}
3560 
3561 		/* Count the number of digits. If a decimal point/exponent is found,
3562 		 * it's a double. Otherwise, if there's a dval or no need to check for
3563 		 * a full match, stop when there are too many digits for a long */
3564 		for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors)); digits++, ptr++) {
3565 check_digits:
3566 			if (ZEND_IS_DIGIT(*ptr)) {
3567 				tmp_lval = tmp_lval * 10 + (*ptr) - '0';
3568 				continue;
3569 			} else if (*ptr == '.' && dp_or_e < 1) {
3570 				goto process_double;
3571 			} else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
3572 				const char *e = ptr + 1;
3573 
3574 				if (*e == '-' || *e == '+') {
3575 					ptr = e++;
3576 				}
3577 				if (ZEND_IS_DIGIT(*e)) {
3578 					goto process_double;
3579 				}
3580 			}
3581 
3582 			break;
3583 		}
3584 
3585 		if (digits >= MAX_LENGTH_OF_LONG) {
3586 			if (oflow_info != NULL) {
3587 				*oflow_info = *str == '-' ? -1 : 1;
3588 			}
3589 			dp_or_e = -1;
3590 			goto process_double;
3591 		}
3592 	} else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
3593 process_double:
3594 		type = IS_DOUBLE;
3595 
3596 		/* If there's a dval, do the conversion; else continue checking
3597 		 * the digits if we need to check for a full match */
3598 		if (dval) {
3599 			local_dval = zend_strtod(str, &ptr);
3600 		} else if (!allow_errors && dp_or_e != -1) {
3601 			dp_or_e = (*ptr++ == '.') ? 1 : 2;
3602 			goto check_digits;
3603 		}
3604 	} else {
3605 		return 0;
3606 	}
3607 
3608 	if (ptr != str + length) {
3609 		const char *endptr = ptr;
3610 		while (*endptr == ' ' || *endptr == '\t' || *endptr == '\n' || *endptr == '\r' || *endptr == '\v' || *endptr == '\f') {
3611 			endptr++;
3612 			length--;
3613 		}
3614 		if (ptr != str + length) {
3615 			if (!allow_errors) {
3616 				return 0;
3617 			}
3618 			if (trailing_data != NULL) {
3619 				*trailing_data = true;
3620 			}
3621 		}
3622 	}
3623 
3624 	if (type == IS_LONG) {
3625 		if (digits == MAX_LENGTH_OF_LONG - 1) {
3626 			int cmp = strcmp(&ptr[-digits], long_min_digits);
3627 
3628 			if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
3629 				if (dval) {
3630 					*dval = zend_strtod(str, NULL);
3631 				}
3632 				if (oflow_info != NULL) {
3633 					*oflow_info = *str == '-' ? -1 : 1;
3634 				}
3635 
3636 				return IS_DOUBLE;
3637 			}
3638 		}
3639 
3640 		if (lval) {
3641 			if (neg) {
3642 				tmp_lval = -tmp_lval;
3643 			}
3644 			*lval = (zend_long) tmp_lval;
3645 		}
3646 
3647 		return IS_LONG;
3648 	} else {
3649 		if (dval) {
3650 			*dval = local_dval;
3651 		}
3652 
3653 		return IS_DOUBLE;
3654 	}
3655 }
3656 /* }}} */
3657 
3658 /*
3659  * String matching - Sunday algorithm
3660  * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
3661  */
3662 static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
3663 	int i;
3664 
3665 	for (i = 0; i < 256; i++) {
3666 		td[i] = needle_len + 1;
3667 	}
3668 
3669 	if (reverse) {
3670 		for (i = needle_len - 1; i >= 0; i--) {
3671 			td[(unsigned char)needle[i]] = i + 1;
3672 		}
3673 	} else {
3674 		size_t i;
3675 
3676 		for (i = 0; i < needle_len; i++) {
3677 			td[(unsigned char)needle[i]] = (int)needle_len - i;
3678 		}
3679 	}
3680 }
3681 /* }}} */
3682 
3683 ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3684 {
3685 	unsigned int td[256];
3686 	size_t i;
3687 	const char *p;
3688 
3689 	if (needle_len == 0 || (end - haystack) < needle_len) {
3690 		return NULL;
3691 	}
3692 
3693 	zend_memnstr_ex_pre(td, needle, needle_len, 0);
3694 
3695 	p = haystack;
3696 	end -= needle_len;
3697 
3698 	while (p <= end) {
3699 		for (i = 0; i < needle_len; i++) {
3700 			if (needle[i] != p[i]) {
3701 				break;
3702 			}
3703 		}
3704 		if (i == needle_len) {
3705 			return p;
3706 		}
3707 		if (UNEXPECTED(p == end)) {
3708 			return NULL;
3709 		}
3710 		p += td[(unsigned char)(p[needle_len])];
3711 	}
3712 
3713 	return NULL;
3714 }
3715 /* }}} */
3716 
3717 ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3718 {
3719 	unsigned int td[256];
3720 	size_t i;
3721 	const char *p;
3722 
3723 	if (needle_len == 0 || (end - haystack) < needle_len) {
3724 		return NULL;
3725 	}
3726 
3727 	zend_memnstr_ex_pre(td, needle, needle_len, 1);
3728 
3729 	p = end;
3730 	p -= needle_len;
3731 
3732 	while (p >= haystack) {
3733 		for (i = 0; i < needle_len; i++) {
3734 			if (needle[i] != p[i]) {
3735 				break;
3736 			}
3737 		}
3738 
3739 		if (i == needle_len) {
3740 			return (const char *)p;
3741 		}
3742 
3743 		if (UNEXPECTED(p == haystack)) {
3744 			return NULL;
3745 		}
3746 
3747 		p -= td[(unsigned char)(p[-1])];
3748 	}
3749 
3750 	return NULL;
3751 }
3752 /* }}} */
3753 
3754 #if SIZEOF_ZEND_LONG == 4
3755 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d) /* {{{ */
3756 {
3757 	double	two_pow_32 = pow(2., 32.),
3758 			dmod;
3759 
3760 	dmod = fmod(d, two_pow_32);
3761 	if (dmod < 0) {
3762 		/* we're going to make this number positive; call ceil()
3763 		 * to simulate rounding towards 0 of the negative number */
3764 		dmod = ceil(dmod) + two_pow_32;
3765 	}
3766 	return (zend_long)(zend_ulong)dmod;
3767 }
3768 #else
3769 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
3770 {
3771 	double	two_pow_64 = pow(2., 64.),
3772 			dmod;
3773 
3774 	dmod = fmod(d, two_pow_64);
3775 	if (dmod < 0) {
3776 		/* no need to call ceil; original double must have had no
3777 		 * fractional part, hence dmod does not have one either */
3778 		dmod += two_pow_64;
3779 	}
3780 	return (zend_long)(zend_ulong)dmod;
3781 }
3782 /* }}} */
3783 #endif
3784