xref: /php-src/Zend/zend_operators.c (revision 0b614a6c)
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(vaddq_s8(blconv_operand, 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 (Z_OBJ_P(op)->properties == NULL
816 			 && Z_OBJ_HT_P(op)->get_properties_for == NULL
817 			 && Z_OBJ_HT_P(op)->get_properties == zend_std_get_properties) {
818 				/* Optimized version without rebuilding properties HashTable */
819 				HashTable *ht = zend_std_build_object_properties_array(Z_OBJ_P(op));
820 				OBJ_RELEASE(Z_OBJ_P(op));
821 				ZVAL_ARR(op, ht);
822 			} else {
823 				HashTable *obj_ht = zend_get_properties_for(op, ZEND_PROP_PURPOSE_ARRAY_CAST);
824 				if (obj_ht) {
825 					HashTable *new_obj_ht = zend_proptable_to_symtable(obj_ht,
826 						(Z_OBJCE_P(op)->default_properties_count ||
827 						 Z_OBJ_P(op)->handlers != &std_object_handlers ||
828 						 GC_IS_RECURSIVE(obj_ht)));
829 					zval_ptr_dtor(op);
830 					ZVAL_ARR(op, new_obj_ht);
831 					zend_release_properties(obj_ht);
832 				} else {
833 					zval_ptr_dtor(op);
834 					/*ZVAL_EMPTY_ARRAY(op);*/
835 					array_init(op);
836 				}
837 			}
838 			break;
839 		case IS_NULL:
840 			/*ZVAL_EMPTY_ARRAY(op);*/
841 			array_init(op);
842 			break;
843 		case IS_REFERENCE:
844 			zend_unwrap_reference(op);
845 			goto try_again;
846 		default:
847 			convert_scalar_to_array(op);
848 			break;
849 	}
850 }
851 /* }}} */
852 
convert_to_object(zval * op)853 ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
854 {
855 try_again:
856 	switch (Z_TYPE_P(op)) {
857 		case IS_ARRAY:
858 			{
859 				HashTable *ht = zend_symtable_to_proptable(Z_ARR_P(op));
860 				zend_object *obj;
861 
862 				if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) {
863 					/* TODO: try not to duplicate immutable arrays as well ??? */
864 					ht = zend_array_dup(ht);
865 				} else if (ht != Z_ARR_P(op)) {
866 					zval_ptr_dtor(op);
867 				} else {
868 					GC_DELREF(ht);
869 				}
870 				obj = zend_objects_new(zend_standard_class_def);
871 				obj->properties = ht;
872 				ZVAL_OBJ(op, obj);
873 				break;
874 			}
875 		case IS_OBJECT:
876 			break;
877 		case IS_NULL:
878 			object_init(op);
879 			break;
880 		case IS_REFERENCE:
881 			zend_unwrap_reference(op);
882 			goto try_again;
883 		default: {
884 			zval tmp;
885 			ZVAL_COPY_VALUE(&tmp, op);
886 			object_init(op);
887 			zend_hash_add_new(Z_OBJPROP_P(op), ZSTR_KNOWN(ZEND_STR_SCALAR), &tmp);
888 			break;
889 		}
890 	}
891 }
892 /* }}} */
893 
zend_incompatible_double_to_long_error(double d)894 ZEND_API void ZEND_COLD zend_incompatible_double_to_long_error(double d)
895 {
896 	zend_error_unchecked(E_DEPRECATED, "Implicit conversion from float %.*H to int loses precision", -1, d);
897 }
zend_incompatible_string_to_long_error(const zend_string * s)898 ZEND_API void ZEND_COLD zend_incompatible_string_to_long_error(const zend_string *s)
899 {
900 	zend_error(E_DEPRECATED, "Implicit conversion from float-string \"%s\" to int loses precision", ZSTR_VAL(s));
901 }
902 
zval_get_long_func(const zval * op,bool is_strict)903 ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(const zval *op, bool is_strict) /* {{{ */
904 {
905 try_again:
906 	switch (Z_TYPE_P(op)) {
907 		case IS_UNDEF:
908 		case IS_NULL:
909 		case IS_FALSE:
910 			return 0;
911 		case IS_TRUE:
912 			return 1;
913 		case IS_RESOURCE:
914 			return Z_RES_HANDLE_P(op);
915 		case IS_LONG:
916 			return Z_LVAL_P(op);
917 		case IS_DOUBLE: {
918 			double dval = Z_DVAL_P(op);
919 			zend_long lval = zend_dval_to_lval(dval);
920 			if (UNEXPECTED(is_strict)) {
921 				if (!zend_is_long_compatible(dval, lval)) {
922 					zend_incompatible_double_to_long_error(dval);
923 				}
924 			}
925 			return lval;
926 		}
927 		case IS_STRING:
928 			{
929 				uint8_t type;
930 				zend_long lval;
931 				double dval;
932 				if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, true))) {
933 					return 0;
934 				} else if (EXPECTED(type == IS_LONG)) {
935 					return lval;
936 				} else {
937 					/* Previously we used strtol here, not is_numeric_string,
938 					 * and strtol gives you LONG_MAX/_MIN on overflow.
939 					 * We use saturating conversion to emulate strtol()'s
940 					 * behaviour.
941 					 */
942 					 /* Most usages are expected to not be (int) casts */
943 					lval = zend_dval_to_lval_cap(dval);
944 					if (UNEXPECTED(is_strict)) {
945 						if (!zend_is_long_compatible(dval, lval)) {
946 							zend_incompatible_string_to_long_error(Z_STR_P(op));
947 						}
948 					}
949 					return lval;
950 				}
951 			}
952 		case IS_ARRAY:
953 			return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
954 		case IS_OBJECT:
955 			{
956 				zval dst;
957 				convert_object_to_type(op, &dst, IS_LONG);
958 				if (Z_TYPE(dst) == IS_LONG) {
959 					return Z_LVAL(dst);
960 				} else {
961 					return 1;
962 				}
963 			}
964 		case IS_REFERENCE:
965 			op = Z_REFVAL_P(op);
966 			goto try_again;
967 		EMPTY_SWITCH_DEFAULT_CASE()
968 	}
969 	return 0;
970 }
971 /* }}} */
972 
zval_get_double_func(const zval * op)973 ZEND_API double ZEND_FASTCALL zval_get_double_func(const zval *op) /* {{{ */
974 {
975 try_again:
976 	switch (Z_TYPE_P(op)) {
977 		case IS_NULL:
978 		case IS_FALSE:
979 			return 0.0;
980 		case IS_TRUE:
981 			return 1.0;
982 		case IS_RESOURCE:
983 			return (double) Z_RES_HANDLE_P(op);
984 		case IS_LONG:
985 			return (double) Z_LVAL_P(op);
986 		case IS_DOUBLE:
987 			return Z_DVAL_P(op);
988 		case IS_STRING:
989 			return zend_strtod(Z_STRVAL_P(op), NULL);
990 		case IS_ARRAY:
991 			return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1.0 : 0.0;
992 		case IS_OBJECT:
993 			{
994 				zval dst;
995 				convert_object_to_type(op, &dst, IS_DOUBLE);
996 
997 				if (Z_TYPE(dst) == IS_DOUBLE) {
998 					return Z_DVAL(dst);
999 				} else {
1000 					return 1.0;
1001 				}
1002 			}
1003 		case IS_REFERENCE:
1004 			op = Z_REFVAL_P(op);
1005 			goto try_again;
1006 		EMPTY_SWITCH_DEFAULT_CASE()
1007 	}
1008 	return 0.0;
1009 }
1010 /* }}} */
1011 
__zval_get_string_func(zval * op,bool try)1012 static zend_always_inline zend_string* __zval_get_string_func(zval *op, bool try) /* {{{ */
1013 {
1014 try_again:
1015 	switch (Z_TYPE_P(op)) {
1016 		case IS_UNDEF:
1017 		case IS_NULL:
1018 		case IS_FALSE:
1019 			return ZSTR_EMPTY_ALLOC();
1020 		case IS_TRUE:
1021 			return ZSTR_CHAR('1');
1022 		case IS_RESOURCE:
1023 			return zend_strpprintf(0, "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
1024 		case IS_LONG:
1025 			return zend_long_to_str(Z_LVAL_P(op));
1026 		case IS_DOUBLE:
1027 			return zend_double_to_str(Z_DVAL_P(op));
1028 		case IS_ARRAY:
1029 			zend_error(E_WARNING, "Array to string conversion");
1030 			return (try && UNEXPECTED(EG(exception))) ?
1031 				NULL : ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
1032 		case IS_OBJECT: {
1033 			zval tmp;
1034 			if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &tmp, IS_STRING) == SUCCESS) {
1035 				return Z_STR(tmp);
1036 			}
1037 			if (!EG(exception)) {
1038 				zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
1039 			}
1040 			return try ? NULL : ZSTR_EMPTY_ALLOC();
1041 		}
1042 		case IS_REFERENCE:
1043 			op = Z_REFVAL_P(op);
1044 			goto try_again;
1045 		case IS_STRING:
1046 			return zend_string_copy(Z_STR_P(op));
1047 		EMPTY_SWITCH_DEFAULT_CASE()
1048 	}
1049 	return NULL;
1050 }
1051 /* }}} */
1052 
zval_get_string_func(zval * op)1053 ZEND_API zend_string* ZEND_FASTCALL zval_get_string_func(zval *op) /* {{{ */
1054 {
1055 	return __zval_get_string_func(op, 0);
1056 }
1057 /* }}} */
1058 
zval_try_get_string_func(zval * op)1059 ZEND_API zend_string* ZEND_FASTCALL zval_try_get_string_func(zval *op) /* {{{ */
1060 {
1061 	return __zval_get_string_func(op, 1);
1062 }
1063 /* }}} */
1064 
zend_binop_error(const char * operator,zval * op1,zval * op2)1065 static ZEND_COLD zend_never_inline void ZEND_FASTCALL zend_binop_error(const char *operator, zval *op1, zval *op2) /* {{{ */ {
1066 	if (EG(exception)) {
1067 		return;
1068 	}
1069 
1070 	zend_type_error("Unsupported operand types: %s %s %s",
1071 		zend_zval_type_name(op1), operator, zend_zval_type_name(op2));
1072 }
1073 /* }}} */
1074 
add_function_array(zval * result,zval * op1,zval * op2)1075 static zend_never_inline void ZEND_FASTCALL add_function_array(zval *result, zval *op1, zval *op2) /* {{{ */
1076 {
1077 	if (result == op1 && Z_ARR_P(op1) == Z_ARR_P(op2)) {
1078 		/* $a += $a */
1079 		return;
1080 	}
1081 	if (result != op1) {
1082 		ZVAL_ARR(result, zend_array_dup(Z_ARR_P(op1)));
1083 	} else {
1084 		SEPARATE_ARRAY(result);
1085 	}
1086 	zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
1087 }
1088 /* }}} */
1089 
add_function_fast(zval * result,zval * op1,zval * op2)1090 static zend_always_inline zend_result add_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1091 {
1092 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1093 
1094 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1095 		fast_long_add_function(result, op1, op2);
1096 		return SUCCESS;
1097 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1098 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
1099 		return SUCCESS;
1100 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1101 		ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
1102 		return SUCCESS;
1103 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1104 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
1105 		return SUCCESS;
1106 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_ARRAY, IS_ARRAY))) {
1107 		add_function_array(result, op1, op2);
1108 		return SUCCESS;
1109 	} else {
1110 		return FAILURE;
1111 	}
1112 } /* }}} */
1113 
add_function_slow(zval * result,zval * op1,zval * op2)1114 static zend_never_inline zend_result ZEND_FASTCALL add_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1115 {
1116 	ZVAL_DEREF(op1);
1117 	ZVAL_DEREF(op2);
1118 	if (add_function_fast(result, op1, op2) == SUCCESS) {
1119 		return SUCCESS;
1120 	}
1121 
1122 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD);
1123 
1124 	zval op1_copy, op2_copy;
1125 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1126 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1127 		zend_binop_error("+", op1, op2);
1128 		if (result != op1) {
1129 			ZVAL_UNDEF(result);
1130 		}
1131 		return FAILURE;
1132 	}
1133 
1134 	if (result == op1) {
1135 		zval_ptr_dtor(result);
1136 	}
1137 
1138 	if (add_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
1139 		return SUCCESS;
1140 	}
1141 
1142 	ZEND_ASSERT(0 && "Operation must succeed");
1143 	return FAILURE;
1144 } /* }}} */
1145 
add_function(zval * result,zval * op1,zval * op2)1146 ZEND_API zend_result ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
1147 {
1148 	if (add_function_fast(result, op1, op2) == SUCCESS) {
1149 		return SUCCESS;
1150 	} else {
1151 		return add_function_slow(result, op1, op2);
1152 	}
1153 }
1154 /* }}} */
1155 
sub_function_fast(zval * result,zval * op1,zval * op2)1156 static zend_always_inline zend_result sub_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1157 {
1158 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1159 
1160 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1161 		fast_long_sub_function(result, op1, op2);
1162 		return SUCCESS;
1163 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1164 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
1165 		return SUCCESS;
1166 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1167 		ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
1168 		return SUCCESS;
1169 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1170 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
1171 		return SUCCESS;
1172 	} else {
1173 		return FAILURE;
1174 	}
1175 }
1176 /* }}} */
1177 
sub_function_slow(zval * result,zval * op1,zval * op2)1178 static zend_never_inline zend_result ZEND_FASTCALL sub_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1179 {
1180 	ZVAL_DEREF(op1);
1181 	ZVAL_DEREF(op2);
1182 	if (sub_function_fast(result, op1, op2) == SUCCESS) {
1183 		return SUCCESS;
1184 	}
1185 
1186 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB);
1187 
1188 	zval op1_copy, op2_copy;
1189 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1190 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1191 		zend_binop_error("-", op1, op2);
1192 		if (result != op1) {
1193 			ZVAL_UNDEF(result);
1194 		}
1195 		return FAILURE;
1196 	}
1197 
1198 	if (result == op1) {
1199 		zval_ptr_dtor(result);
1200 	}
1201 
1202 	if (sub_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
1203 		return SUCCESS;
1204 	}
1205 
1206 	ZEND_ASSERT(0 && "Operation must succeed");
1207 	return FAILURE;
1208 }
1209 /* }}} */
1210 
sub_function(zval * result,zval * op1,zval * op2)1211 ZEND_API zend_result ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* {{{ */
1212 {
1213 	if (sub_function_fast(result, op1, op2) == SUCCESS) {
1214 		return SUCCESS;
1215 	} else {
1216 		return sub_function_slow(result, op1, op2);
1217 	}
1218 }
1219 /* }}} */
1220 
mul_function_fast(zval * result,zval * op1,zval * op2)1221 static zend_always_inline zend_result mul_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1222 {
1223 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1224 
1225 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1226 		zend_long overflow;
1227 		ZEND_SIGNED_MULTIPLY_LONG(
1228 			Z_LVAL_P(op1), Z_LVAL_P(op2),
1229 			Z_LVAL_P(result), Z_DVAL_P(result), overflow);
1230 		Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
1231 		return SUCCESS;
1232 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1233 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
1234 		return SUCCESS;
1235 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1236 		ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
1237 		return SUCCESS;
1238 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1239 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
1240 		return SUCCESS;
1241 	} else {
1242 		return FAILURE;
1243 	}
1244 }
1245 /* }}} */
1246 
mul_function_slow(zval * result,zval * op1,zval * op2)1247 static zend_never_inline zend_result ZEND_FASTCALL mul_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1248 {
1249 	ZVAL_DEREF(op1);
1250 	ZVAL_DEREF(op2);
1251 	if (mul_function_fast(result, op1, op2) == SUCCESS) {
1252 		return SUCCESS;
1253 	}
1254 
1255 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL);
1256 
1257 	zval op1_copy, op2_copy;
1258 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1259 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1260 		zend_binop_error("*", op1, op2);
1261 		if (result != op1) {
1262 			ZVAL_UNDEF(result);
1263 		}
1264 		return FAILURE;
1265 	}
1266 
1267 	if (result == op1) {
1268 		zval_ptr_dtor(result);
1269 	}
1270 
1271 	if (mul_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
1272 		return SUCCESS;
1273 	}
1274 
1275 	ZEND_ASSERT(0 && "Operation must succeed");
1276 	return FAILURE;
1277 }
1278 /* }}} */
1279 
mul_function(zval * result,zval * op1,zval * op2)1280 ZEND_API zend_result ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */
1281 {
1282 	if (mul_function_fast(result, op1, op2) == SUCCESS) {
1283 		return SUCCESS;
1284 	} else {
1285 		return mul_function_slow(result, op1, op2);
1286 	}
1287 }
1288 /* }}} */
1289 
pow_function_base(zval * result,zval * op1,zval * op2)1290 static zend_result ZEND_FASTCALL pow_function_base(zval *result, zval *op1, zval *op2) /* {{{ */
1291 {
1292 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1293 
1294 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1295 		if (Z_LVAL_P(op2) >= 0) {
1296 			zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
1297 
1298 			if (i == 0) {
1299 				ZVAL_LONG(result, 1L);
1300 				return SUCCESS;
1301 			} else if (l2 == 0) {
1302 				ZVAL_LONG(result, 0);
1303 				return SUCCESS;
1304 			}
1305 
1306 			while (i >= 1) {
1307 				zend_long overflow;
1308 				double dval = 0.0;
1309 
1310 				if (i % 2) {
1311 					--i;
1312 					ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
1313 					if (overflow) {
1314 						ZVAL_DOUBLE(result, dval * pow(l2, i));
1315 						return SUCCESS;
1316 					}
1317 				} else {
1318 					i /= 2;
1319 					ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
1320 					if (overflow) {
1321 						ZVAL_DOUBLE(result, (double)l1 * pow(dval, i));
1322 						return SUCCESS;
1323 					}
1324 				}
1325 			}
1326 			/* i == 0 */
1327 			ZVAL_LONG(result, l1);
1328 		} else {
1329 			ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
1330 		}
1331 		return SUCCESS;
1332 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1333 		ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
1334 		return SUCCESS;
1335 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1336 		ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
1337 		return SUCCESS;
1338 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1339 		ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
1340 		return SUCCESS;
1341 	} else {
1342 		return FAILURE;
1343 	}
1344 }
1345 /* }}} */
1346 
pow_function(zval * result,zval * op1,zval * op2)1347 ZEND_API zend_result ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */
1348 {
1349 	ZVAL_DEREF(op1);
1350 	ZVAL_DEREF(op2);
1351 	if (pow_function_base(result, op1, op2) == SUCCESS) {
1352 		return SUCCESS;
1353 	}
1354 
1355 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW);
1356 
1357 	zval op1_copy, op2_copy;
1358 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1359 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1360 		zend_binop_error("**", op1, op2);
1361 		if (result != op1) {
1362 			ZVAL_UNDEF(result);
1363 		}
1364 		return FAILURE;
1365 	}
1366 
1367 	if (result == op1) {
1368 		zval_ptr_dtor(result);
1369 	}
1370 
1371 	if (pow_function_base(result, &op1_copy, &op2_copy) == SUCCESS) {
1372 		return SUCCESS;
1373 	}
1374 
1375 	ZEND_ASSERT(0 && "Operation must succeed");
1376 	return FAILURE;
1377 }
1378 /* }}} */
1379 
1380 /* Returns SUCCESS/TYPES_NOT_HANDLED/DIV_BY_ZERO */
1381 #define TYPES_NOT_HANDLED 1
1382 #define DIV_BY_ZERO 2
div_function_base(zval * result,zval * op1,zval * op2)1383 static int ZEND_FASTCALL div_function_base(zval *result, zval *op1, zval *op2) /* {{{ */
1384 {
1385 	uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1386 
1387 	if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1388 		if (Z_LVAL_P(op2) == 0) {
1389 			return DIV_BY_ZERO;
1390 		} else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
1391 			/* Prevent overflow error/crash */
1392 			ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
1393 			return SUCCESS;
1394 		}
1395 		if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
1396 			ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
1397 		} else {
1398 			ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
1399 		}
1400 		return SUCCESS;
1401 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1402 		if (Z_DVAL_P(op2) == 0) {
1403 			return DIV_BY_ZERO;
1404 		}
1405 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1406 		return SUCCESS;
1407 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1408 		if (Z_LVAL_P(op2) == 0) {
1409 			return DIV_BY_ZERO;
1410 		}
1411 		ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1412 		return SUCCESS;
1413 	} else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1414 		if (Z_DVAL_P(op2) == 0) {
1415 			return DIV_BY_ZERO;
1416 		}
1417 		ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1418 		return SUCCESS;
1419 	} else {
1420 		return TYPES_NOT_HANDLED;
1421 	}
1422 }
1423 /* }}} */
1424 
div_function(zval * result,zval * op1,zval * op2)1425 ZEND_API zend_result ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */
1426 {
1427 	ZVAL_DEREF(op1);
1428 	ZVAL_DEREF(op2);
1429 
1430 	int retval = div_function_base(result, op1, op2);
1431 	if (EXPECTED(retval == SUCCESS)) {
1432 		return SUCCESS;
1433 	}
1434 
1435 	if (UNEXPECTED(retval == DIV_BY_ZERO)) {
1436 		goto div_by_zero;
1437 	}
1438 
1439 	ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);
1440 
1441 	zval result_copy, op1_copy, op2_copy;
1442 	if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1443 			|| UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1444 		zend_binop_error("/", op1, op2);
1445 		if (result != op1) {
1446 			ZVAL_UNDEF(result);
1447 		}
1448 		return FAILURE;
1449 	}
1450 
1451 	retval = div_function_base(&result_copy, &op1_copy, &op2_copy);
1452 	if (retval == SUCCESS) {
1453 		if (result == op1) {
1454 			zval_ptr_dtor(result);
1455 		}
1456 		ZVAL_COPY_VALUE(result, &result_copy);
1457 		return SUCCESS;
1458 	}
1459 
1460 div_by_zero:
1461 	ZEND_ASSERT(retval == DIV_BY_ZERO && "TYPES_NOT_HANDLED should not occur here");
1462 	if (result != op1) {
1463 		ZVAL_UNDEF(result);
1464 	}
1465 	zend_throw_error(zend_ce_division_by_zero_error, "Division by zero");
1466 	return FAILURE;
1467 }
1468 /* }}} */
1469 
mod_function(zval * result,zval * op1,zval * op2)1470 ZEND_API zend_result ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* {{{ */
1471 {
1472 	zend_long op1_lval, op2_lval;
1473 
1474 	convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_MOD, "%");
1475 
1476 	if (op2_lval == 0) {
1477 		/* modulus by zero */
1478 		if (EG(current_execute_data) && !CG(in_compilation)) {
1479 			zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
1480 		} else {
1481 			zend_error_noreturn(E_ERROR, "Modulo by zero");
1482 		}
1483 		if (op1 != result) {
1484 			ZVAL_UNDEF(result);
1485 		}
1486 		return FAILURE;
1487 	}
1488 
1489 	if (op1 == result) {
1490 		zval_ptr_dtor(result);
1491 	}
1492 
1493 	if (op2_lval == -1) {
1494 		/* Prevent overflow error/crash if op1==LONG_MIN */
1495 		ZVAL_LONG(result, 0);
1496 		return SUCCESS;
1497 	}
1498 
1499 	ZVAL_LONG(result, op1_lval % op2_lval);
1500 	return SUCCESS;
1501 }
1502 /* }}} */
1503 
boolean_xor_function(zval * result,zval * op1,zval * op2)1504 ZEND_API zend_result ZEND_FASTCALL boolean_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1505 {
1506 	int op1_val, op2_val;
1507 
1508 	do {
1509 		if (Z_TYPE_P(op1) == IS_FALSE) {
1510 			op1_val = 0;
1511 		} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1512 			op1_val = 1;
1513 		} else {
1514 			if (Z_ISREF_P(op1)) {
1515 				op1 = Z_REFVAL_P(op1);
1516 				if (Z_TYPE_P(op1) == IS_FALSE) {
1517 					op1_val = 0;
1518 					break;
1519 				} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1520 					op1_val = 1;
1521 					break;
1522 				}
1523 			}
1524 			ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BOOL_XOR);
1525 			op1_val = zval_is_true(op1);
1526 		}
1527 	} while (0);
1528 	do {
1529 		if (Z_TYPE_P(op2) == IS_FALSE) {
1530 			op2_val = 0;
1531 		} else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1532 			op2_val = 1;
1533 		} else {
1534 			if (Z_ISREF_P(op2)) {
1535 				op2 = Z_REFVAL_P(op2);
1536 				if (Z_TYPE_P(op2) == IS_FALSE) {
1537 					op2_val = 0;
1538 					break;
1539 				} else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1540 					op2_val = 1;
1541 					break;
1542 				}
1543 			}
1544 			ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BOOL_XOR);
1545 			op2_val = zval_is_true(op2);
1546 		}
1547 	} while (0);
1548 
1549 	ZVAL_BOOL(result, op1_val ^ op2_val);
1550 	return SUCCESS;
1551 }
1552 /* }}} */
1553 
boolean_not_function(zval * result,zval * op1)1554 ZEND_API zend_result ZEND_FASTCALL boolean_not_function(zval *result, zval *op1) /* {{{ */
1555 {
1556 	if (Z_TYPE_P(op1) < IS_TRUE) {
1557 		ZVAL_TRUE(result);
1558 	} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1559 		ZVAL_FALSE(result);
1560 	} else {
1561 		if (Z_ISREF_P(op1)) {
1562 			op1 = Z_REFVAL_P(op1);
1563 			if (Z_TYPE_P(op1) < IS_TRUE) {
1564 				ZVAL_TRUE(result);
1565 				return SUCCESS;
1566 			} else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1567 				ZVAL_FALSE(result);
1568 				return SUCCESS;
1569 			}
1570 		}
1571 		ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1572 
1573 		ZVAL_BOOL(result, !zval_is_true(op1));
1574 	}
1575 	return SUCCESS;
1576 }
1577 /* }}} */
1578 
bitwise_not_function(zval * result,zval * op1)1579 ZEND_API zend_result ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{ */
1580 {
1581 try_again:
1582 	switch (Z_TYPE_P(op1)) {
1583 		case IS_LONG:
1584 			ZVAL_LONG(result, ~Z_LVAL_P(op1));
1585 			return SUCCESS;
1586 		case IS_DOUBLE: {
1587 			zend_long lval = zend_dval_to_lval(Z_DVAL_P(op1));
1588 			if (!zend_is_long_compatible(Z_DVAL_P(op1), lval)) {
1589 				zend_incompatible_double_to_long_error(Z_DVAL_P(op1));
1590 				if (EG(exception)) {
1591 					if (result != op1) {
1592 						ZVAL_UNDEF(result);
1593 					}
1594 					return FAILURE;
1595 				}
1596 			}
1597 			ZVAL_LONG(result, ~lval);
1598 			return SUCCESS;
1599 		}
1600 		case IS_STRING: {
1601 			size_t i;
1602 
1603 			if (Z_STRLEN_P(op1) == 1) {
1604 				zend_uchar not = (zend_uchar) ~*Z_STRVAL_P(op1);
1605 				ZVAL_CHAR(result, not);
1606 			} else {
1607 				ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
1608 				for (i = 0; i < Z_STRLEN_P(op1); i++) {
1609 					Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1610 				}
1611 				Z_STRVAL_P(result)[i] = 0;
1612 			}
1613 			return SUCCESS;
1614 		}
1615 		case IS_REFERENCE:
1616 			op1 = Z_REFVAL_P(op1);
1617 			goto try_again;
1618 		default:
1619 			ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1620 
1621 			if (result != op1) {
1622 				ZVAL_UNDEF(result);
1623 			}
1624 			zend_type_error("Cannot perform bitwise not on %s", zend_zval_value_name(op1));
1625 			return FAILURE;
1626 	}
1627 }
1628 /* }}} */
1629 
bitwise_or_function(zval * result,zval * op1,zval * op2)1630 ZEND_API zend_result ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2) /* {{{ */
1631 {
1632 	zend_long op1_lval, op2_lval;
1633 
1634 	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1635 		ZVAL_LONG(result, Z_LVAL_P(op1) | Z_LVAL_P(op2));
1636 		return SUCCESS;
1637 	}
1638 
1639 	ZVAL_DEREF(op1);
1640 	ZVAL_DEREF(op2);
1641 
1642 	if (Z_TYPE_P(op1) == IS_STRING && EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1643 		zval *longer, *shorter;
1644 		zend_string *str;
1645 		size_t i;
1646 
1647 		if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1648 			if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1649 				zend_uchar or = (zend_uchar) (*Z_STRVAL_P(op1) | *Z_STRVAL_P(op2));
1650 				if (result==op1) {
1651 					zval_ptr_dtor_str(result);
1652 				}
1653 				ZVAL_CHAR(result, or);
1654 				return SUCCESS;
1655 			}
1656 			longer = op1;
1657 			shorter = op2;
1658 		} else {
1659 			longer = op2;
1660 			shorter = op1;
1661 		}
1662 
1663 		str = zend_string_alloc(Z_STRLEN_P(longer), 0);
1664 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1665 			ZSTR_VAL(str)[i] = Z_STRVAL_P(longer)[i] | Z_STRVAL_P(shorter)[i];
1666 		}
1667 		memcpy(ZSTR_VAL(str) + i, Z_STRVAL_P(longer) + i, Z_STRLEN_P(longer) - i + 1);
1668 		if (result==op1) {
1669 			zval_ptr_dtor_str(result);
1670 		}
1671 		ZVAL_NEW_STR(result, str);
1672 		return SUCCESS;
1673 	}
1674 
1675 	if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1676 		bool failed;
1677 		ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR);
1678 		op1_lval = zendi_try_get_long(op1, &failed);
1679 		if (UNEXPECTED(failed)) {
1680 			zend_binop_error("|", op1, op2);
1681 			if (result != op1) {
1682 				ZVAL_UNDEF(result);
1683 			}
1684 			return FAILURE;
1685 		}
1686 	} else {
1687 		op1_lval = Z_LVAL_P(op1);
1688 	}
1689 	if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1690 		bool failed;
1691 		ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR);
1692 		op2_lval = zendi_try_get_long(op2, &failed);
1693 		if (UNEXPECTED(failed)) {
1694 			zend_binop_error("|", op1, op2);
1695 			if (result != op1) {
1696 				ZVAL_UNDEF(result);
1697 			}
1698 			return FAILURE;
1699 		}
1700 	} else {
1701 		op2_lval = Z_LVAL_P(op2);
1702 	}
1703 
1704 	if (op1 == result) {
1705 		zval_ptr_dtor(result);
1706 	}
1707 	ZVAL_LONG(result, op1_lval | op2_lval);
1708 	return SUCCESS;
1709 }
1710 /* }}} */
1711 
bitwise_and_function(zval * result,zval * op1,zval * op2)1712 ZEND_API zend_result ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2) /* {{{ */
1713 {
1714 	zend_long op1_lval, op2_lval;
1715 
1716 	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1717 		ZVAL_LONG(result, Z_LVAL_P(op1) & Z_LVAL_P(op2));
1718 		return SUCCESS;
1719 	}
1720 
1721 	ZVAL_DEREF(op1);
1722 	ZVAL_DEREF(op2);
1723 
1724 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1725 		zval *longer, *shorter;
1726 		zend_string *str;
1727 		size_t i;
1728 
1729 		if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1730 			if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1731 				zend_uchar and = (zend_uchar) (*Z_STRVAL_P(op1) & *Z_STRVAL_P(op2));
1732 				if (result==op1) {
1733 					zval_ptr_dtor_str(result);
1734 				}
1735 				ZVAL_CHAR(result, and);
1736 				return SUCCESS;
1737 			}
1738 			longer = op1;
1739 			shorter = op2;
1740 		} else {
1741 			longer = op2;
1742 			shorter = op1;
1743 		}
1744 
1745 		str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1746 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1747 			ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] & Z_STRVAL_P(longer)[i];
1748 		}
1749 		ZSTR_VAL(str)[i] = 0;
1750 		if (result==op1) {
1751 			zval_ptr_dtor_str(result);
1752 		}
1753 		ZVAL_NEW_STR(result, str);
1754 		return SUCCESS;
1755 	}
1756 
1757 	if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1758 		bool failed;
1759 		ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND);
1760 		op1_lval = zendi_try_get_long(op1, &failed);
1761 		if (UNEXPECTED(failed)) {
1762 			zend_binop_error("&", op1, op2);
1763 			if (result != op1) {
1764 				ZVAL_UNDEF(result);
1765 			}
1766 			return FAILURE;
1767 		}
1768 	} else {
1769 		op1_lval = Z_LVAL_P(op1);
1770 	}
1771 	if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1772 		bool failed;
1773 		ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND);
1774 		op2_lval = zendi_try_get_long(op2, &failed);
1775 		if (UNEXPECTED(failed)) {
1776 			zend_binop_error("&", op1, op2);
1777 			if (result != op1) {
1778 				ZVAL_UNDEF(result);
1779 			}
1780 			return FAILURE;
1781 		}
1782 	} else {
1783 		op2_lval = Z_LVAL_P(op2);
1784 	}
1785 
1786 	if (op1 == result) {
1787 		zval_ptr_dtor(result);
1788 	}
1789 	ZVAL_LONG(result, op1_lval & op2_lval);
1790 	return SUCCESS;
1791 }
1792 /* }}} */
1793 
bitwise_xor_function(zval * result,zval * op1,zval * op2)1794 ZEND_API zend_result ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1795 {
1796 	zend_long op1_lval, op2_lval;
1797 
1798 	if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1799 		ZVAL_LONG(result, Z_LVAL_P(op1) ^ Z_LVAL_P(op2));
1800 		return SUCCESS;
1801 	}
1802 
1803 	ZVAL_DEREF(op1);
1804 	ZVAL_DEREF(op2);
1805 
1806 	if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1807 		zval *longer, *shorter;
1808 		zend_string *str;
1809 		size_t i;
1810 
1811 		if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1812 			if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1813 				zend_uchar xor = (zend_uchar) (*Z_STRVAL_P(op1) ^ *Z_STRVAL_P(op2));
1814 				if (result==op1) {
1815 					zval_ptr_dtor_str(result);
1816 				}
1817 				ZVAL_CHAR(result, xor);
1818 				return SUCCESS;
1819 			}
1820 			longer = op1;
1821 			shorter = op2;
1822 		} else {
1823 			longer = op2;
1824 			shorter = op1;
1825 		}
1826 
1827 		str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1828 		for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1829 			ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] ^ Z_STRVAL_P(longer)[i];
1830 		}
1831 		ZSTR_VAL(str)[i] = 0;
1832 		if (result==op1) {
1833 			zval_ptr_dtor_str(result);
1834 		}
1835 		ZVAL_NEW_STR(result, str);
1836 		return SUCCESS;
1837 	}
1838 
1839 	if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1840 		bool failed;
1841 		ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR);
1842 		op1_lval = zendi_try_get_long(op1, &failed);
1843 		if (UNEXPECTED(failed)) {
1844 			zend_binop_error("^", op1, op2);
1845 			if (result != op1) {
1846 				ZVAL_UNDEF(result);
1847 			}
1848 			return FAILURE;
1849 		}
1850 	} else {
1851 		op1_lval = Z_LVAL_P(op1);
1852 	}
1853 	if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1854 		bool failed;
1855 		ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR);
1856 		op2_lval = zendi_try_get_long(op2, &failed);
1857 		if (UNEXPECTED(failed)) {
1858 			zend_binop_error("^", op1, op2);
1859 			if (result != op1) {
1860 				ZVAL_UNDEF(result);
1861 			}
1862 			return FAILURE;
1863 		}
1864 	} else {
1865 		op2_lval = Z_LVAL_P(op2);
1866 	}
1867 
1868 	if (op1 == result) {
1869 		zval_ptr_dtor(result);
1870 	}
1871 	ZVAL_LONG(result, op1_lval ^ op2_lval);
1872 	return SUCCESS;
1873 }
1874 /* }}} */
1875 
shift_left_function(zval * result,zval * op1,zval * op2)1876 ZEND_API zend_result ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2) /* {{{ */
1877 {
1878 	zend_long op1_lval, op2_lval;
1879 
1880 	convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SL, "<<");
1881 
1882 	/* prevent wrapping quirkiness on some processors where << 64 + x == << x */
1883 	if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1884 		if (EXPECTED(op2_lval > 0)) {
1885 			if (op1 == result) {
1886 				zval_ptr_dtor(result);
1887 			}
1888 			ZVAL_LONG(result, 0);
1889 			return SUCCESS;
1890 		} else {
1891 			if (EG(current_execute_data) && !CG(in_compilation)) {
1892 				zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1893 			} else {
1894 				zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1895 			}
1896 			if (op1 != result) {
1897 				ZVAL_UNDEF(result);
1898 			}
1899 			return FAILURE;
1900 		}
1901 	}
1902 
1903 	if (op1 == result) {
1904 		zval_ptr_dtor(result);
1905 	}
1906 
1907 	/* Perform shift on unsigned numbers to get well-defined wrap behavior. */
1908 	ZVAL_LONG(result, (zend_long) ((zend_ulong) op1_lval << op2_lval));
1909 	return SUCCESS;
1910 }
1911 /* }}} */
1912 
shift_right_function(zval * result,zval * op1,zval * op2)1913 ZEND_API zend_result ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2) /* {{{ */
1914 {
1915 	zend_long op1_lval, op2_lval;
1916 
1917 	convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SR, ">>");
1918 
1919 	/* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */
1920 	if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1921 		if (EXPECTED(op2_lval > 0)) {
1922 			if (op1 == result) {
1923 				zval_ptr_dtor(result);
1924 			}
1925 			ZVAL_LONG(result, (op1_lval < 0) ? -1 : 0);
1926 			return SUCCESS;
1927 		} else {
1928 			if (EG(current_execute_data) && !CG(in_compilation)) {
1929 				zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1930 			} else {
1931 				zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1932 			}
1933 			if (op1 != result) {
1934 				ZVAL_UNDEF(result);
1935 			}
1936 			return FAILURE;
1937 		}
1938 	}
1939 
1940 	if (op1 == result) {
1941 		zval_ptr_dtor(result);
1942 	}
1943 
1944 	ZVAL_LONG(result, op1_lval >> op2_lval);
1945 	return SUCCESS;
1946 }
1947 /* }}} */
1948 
concat_function(zval * result,zval * op1,zval * op2)1949 ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */
1950 {
1951 	zval *orig_op1 = op1;
1952 	zend_string *op1_string, *op2_string;
1953 	bool free_op1_string = false;
1954 	bool free_op2_string = false;
1955 
1956 	do {
1957 		if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
1958 			op1_string = Z_STR_P(op1);
1959 		} else {
1960 	 		if (Z_ISREF_P(op1)) {
1961 	 			op1 = Z_REFVAL_P(op1);
1962 				if (Z_TYPE_P(op1) == IS_STRING) {
1963 					op1_string = Z_STR_P(op1);
1964 					break;
1965 				}
1966 	 		}
1967 			ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT);
1968 			op1_string = zval_get_string_func(op1);
1969 			if (UNEXPECTED(EG(exception))) {
1970 				zend_string_release(op1_string);
1971 				if (orig_op1 != result) {
1972 					ZVAL_UNDEF(result);
1973 				}
1974 				return FAILURE;
1975 			}
1976 			free_op1_string = true;
1977 			if (result == op1) {
1978 				if (UNEXPECTED(op1 == op2)) {
1979 					op2_string = op1_string;
1980 					goto has_op2_string;
1981 				}
1982 			}
1983 		}
1984 	} while (0);
1985 	do {
1986 		if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1987 			op2_string = Z_STR_P(op2);
1988 		} else {
1989 			if (Z_ISREF_P(op2)) {
1990 				op2 = Z_REFVAL_P(op2);
1991 				if (Z_TYPE_P(op2) == IS_STRING) {
1992 					op2_string = Z_STR_P(op2);
1993 					break;
1994 				}
1995 			}
1996 			/* hold an additional reference because a userland function could free this */
1997 			if (!free_op1_string) {
1998 				op1_string = zend_string_copy(op1_string);
1999 				free_op1_string = true;
2000 			}
2001 			ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT);
2002 			op2_string = zval_get_string_func(op2);
2003 			if (UNEXPECTED(EG(exception))) {
2004 				zend_string_release(op1_string);
2005 				zend_string_release(op2_string);
2006 				if (orig_op1 != result) {
2007 					ZVAL_UNDEF(result);
2008 				}
2009 				return FAILURE;
2010 			}
2011 			free_op2_string = true;
2012 		}
2013 	} while (0);
2014 
2015 has_op2_string:;
2016 	if (UNEXPECTED(ZSTR_LEN(op1_string) == 0)) {
2017 		if (EXPECTED(result != op2 || Z_TYPE_P(result) != IS_STRING)) {
2018 			if (result == orig_op1) {
2019 				i_zval_ptr_dtor(result);
2020 			}
2021 			if (free_op2_string) {
2022 				/* transfer ownership of op2_string */
2023 				ZVAL_STR(result, op2_string);
2024 				free_op2_string = false;
2025 			} else {
2026 				ZVAL_STR_COPY(result, op2_string);
2027 			}
2028 		}
2029 	} else if (UNEXPECTED(ZSTR_LEN(op2_string) == 0)) {
2030 		if (EXPECTED(result != op1 || Z_TYPE_P(result) != IS_STRING)) {
2031 			if (result == orig_op1) {
2032 				i_zval_ptr_dtor(result);
2033 			}
2034 			if (free_op1_string) {
2035 				/* transfer ownership of op1_string */
2036 				ZVAL_STR(result, op1_string);
2037 				free_op1_string = false;
2038 			} else {
2039 				ZVAL_STR_COPY(result, op1_string);
2040 			}
2041 		}
2042 	} else {
2043 		size_t op1_len = ZSTR_LEN(op1_string);
2044 		size_t op2_len = ZSTR_LEN(op2_string);
2045 		size_t result_len = op1_len + op2_len;
2046 		zend_string *result_str;
2047 		uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_string, op2_string);
2048 
2049 		if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) {
2050 			if (free_op1_string) zend_string_release(op1_string);
2051 			if (free_op2_string) zend_string_release(op2_string);
2052 			zend_throw_error(NULL, "String size overflow");
2053 			if (orig_op1 != result) {
2054 				ZVAL_UNDEF(result);
2055 			}
2056 			return FAILURE;
2057 		}
2058 
2059 		if (result == op1) {
2060 			/* Destroy the old result first to drop the refcount, such that $x .= ...; may happen in-place. */
2061 			if (free_op1_string) {
2062 				/* op1_string will be used as the result, so we should not free it */
2063 				i_zval_ptr_dtor(result);
2064 				/* Set it to NULL in case that the extension will throw an out-of-memory error.
2065 				 * Otherwise the shutdown sequence will try to free this again. */
2066 				ZVAL_NULL(result);
2067 				free_op1_string = false;
2068 			}
2069 			/* special case, perform operations on result */
2070 			result_str = zend_string_extend(op1_string, result_len, 0);
2071 			/* account for the case where result_str == op1_string == op2_string and the realloc is done */
2072 			if (op1_string == op2_string) {
2073 				if (free_op2_string) {
2074 					zend_string_release(op2_string);
2075 					free_op2_string = false;
2076 				}
2077 				op2_string = result_str;
2078 			}
2079 		} else {
2080 			result_str = zend_string_alloc(result_len, 0);
2081 			memcpy(ZSTR_VAL(result_str), ZSTR_VAL(op1_string), op1_len);
2082 			if (result == orig_op1) {
2083 				i_zval_ptr_dtor(result);
2084 			}
2085 		}
2086 		GC_ADD_FLAGS(result_str, flags);
2087 
2088 		ZVAL_NEW_STR(result, result_str);
2089 		memcpy(ZSTR_VAL(result_str) + op1_len, ZSTR_VAL(op2_string), op2_len);
2090 		ZSTR_VAL(result_str)[result_len] = '\0';
2091 	}
2092 
2093 	if (free_op1_string) zend_string_release(op1_string);
2094 	if (free_op2_string) zend_string_release(op2_string);
2095 
2096 	return SUCCESS;
2097 }
2098 /* }}} */
2099 
string_compare_function_ex(zval * op1,zval * op2,bool case_insensitive)2100 ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, bool case_insensitive) /* {{{ */
2101 {
2102 	zend_string *tmp_str1, *tmp_str2;
2103 	zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2104 	zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2105 	int ret;
2106 
2107 	if (case_insensitive) {
2108 		ret = zend_binary_strcasecmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2109 	} else {
2110 		ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2111 	}
2112 
2113 	zend_tmp_string_release(tmp_str1);
2114 	zend_tmp_string_release(tmp_str2);
2115 	return ret;
2116 }
2117 /* }}} */
2118 
string_compare_function(zval * op1,zval * op2)2119 ZEND_API int ZEND_FASTCALL string_compare_function(zval *op1, zval *op2) /* {{{ */
2120 {
2121 	if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
2122 	    EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
2123 		if (Z_STR_P(op1) == Z_STR_P(op2)) {
2124 			return 0;
2125 		} else {
2126 			return zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
2127 		}
2128 	} else {
2129 		zend_string *tmp_str1, *tmp_str2;
2130 		zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2131 		zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2132 		int ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2133 
2134 		zend_tmp_string_release(tmp_str1);
2135 		zend_tmp_string_release(tmp_str2);
2136 		return ret;
2137 	}
2138 }
2139 /* }}} */
2140 
string_case_compare_function(zval * op1,zval * op2)2141 ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2) /* {{{ */
2142 {
2143 	if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
2144 	    EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
2145 		if (Z_STR_P(op1) == Z_STR_P(op2)) {
2146 			return 0;
2147 		} else {
2148 			return zend_binary_strcasecmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
2149 		}
2150 	} else {
2151 		zend_string *tmp_str1, *tmp_str2;
2152 		zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2153 		zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2154 		int ret = zend_binary_strcasecmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2155 
2156 		zend_tmp_string_release(tmp_str1);
2157 		zend_tmp_string_release(tmp_str2);
2158 		return ret;
2159 	}
2160 }
2161 /* }}} */
2162 
string_locale_compare_function(zval * op1,zval * op2)2163 ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2) /* {{{ */
2164 {
2165 	zend_string *tmp_str1, *tmp_str2;
2166 	zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2167 	zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2168 	int ret = strcoll(ZSTR_VAL(str1), ZSTR_VAL(str2));
2169 
2170 	zend_tmp_string_release(tmp_str1);
2171 	zend_tmp_string_release(tmp_str2);
2172 	return ret;
2173 }
2174 /* }}} */
2175 
numeric_compare_function(zval * op1,zval * op2)2176 ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{ */
2177 {
2178 	double d1, d2;
2179 
2180 	d1 = zval_get_double(op1);
2181 	d2 = zval_get_double(op2);
2182 
2183 	return ZEND_THREEWAY_COMPARE(d1, d2);
2184 }
2185 /* }}} */
2186 
compare_function(zval * result,zval * op1,zval * op2)2187 ZEND_API zend_result ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
2188 {
2189 	ZVAL_LONG(result, zend_compare(op1, op2));
2190 	return SUCCESS;
2191 }
2192 /* }}} */
2193 
compare_long_to_string(zend_long lval,zend_string * str)2194 static int compare_long_to_string(zend_long lval, zend_string *str) /* {{{ */
2195 {
2196 	zend_long str_lval;
2197 	double str_dval;
2198 	uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
2199 
2200 	if (type == IS_LONG) {
2201 		return lval > str_lval ? 1 : lval < str_lval ? -1 : 0;
2202 	}
2203 
2204 	if (type == IS_DOUBLE) {
2205 		return ZEND_THREEWAY_COMPARE((double) lval, str_dval);
2206 	}
2207 
2208 	zend_string *lval_as_str = zend_long_to_str(lval);
2209 	int cmp_result = zend_binary_strcmp(
2210 		ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
2211 	zend_string_release(lval_as_str);
2212 	return ZEND_NORMALIZE_BOOL(cmp_result);
2213 }
2214 /* }}} */
2215 
compare_double_to_string(double dval,zend_string * str)2216 static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
2217 {
2218 	zend_long str_lval;
2219 	double str_dval;
2220 	uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
2221 
2222 	if (type == IS_LONG) {
2223 		return ZEND_THREEWAY_COMPARE(dval, (double) str_lval);
2224 	}
2225 
2226 	if (type == IS_DOUBLE) {
2227 		return ZEND_THREEWAY_COMPARE(dval, str_dval);
2228 	}
2229 
2230 	zend_string *dval_as_str = zend_double_to_str(dval);
2231 	int cmp_result = zend_binary_strcmp(
2232 		ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
2233 	zend_string_release(dval_as_str);
2234 	return ZEND_NORMALIZE_BOOL(cmp_result);
2235 }
2236 /* }}} */
2237 
zend_compare(zval * op1,zval * op2)2238 ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
2239 {
2240 	int converted = 0;
2241 	zval op1_copy, op2_copy;
2242 
2243 	while (1) {
2244 		switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2245 			case TYPE_PAIR(IS_LONG, IS_LONG):
2246 				return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
2247 
2248 			case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2249 				return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), (double)Z_LVAL_P(op2));
2250 
2251 			case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2252 				return ZEND_THREEWAY_COMPARE((double)Z_LVAL_P(op1), Z_DVAL_P(op2));
2253 
2254 			case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2255 				return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), Z_DVAL_P(op2));
2256 
2257 			case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2258 				return zend_compare_arrays(op1, op2);
2259 
2260 			case TYPE_PAIR(IS_NULL, IS_NULL):
2261 			case TYPE_PAIR(IS_NULL, IS_FALSE):
2262 			case TYPE_PAIR(IS_FALSE, IS_NULL):
2263 			case TYPE_PAIR(IS_FALSE, IS_FALSE):
2264 			case TYPE_PAIR(IS_TRUE, IS_TRUE):
2265 				return 0;
2266 
2267 			case TYPE_PAIR(IS_NULL, IS_TRUE):
2268 				return -1;
2269 
2270 			case TYPE_PAIR(IS_TRUE, IS_NULL):
2271 				return 1;
2272 
2273 			case TYPE_PAIR(IS_STRING, IS_STRING):
2274 				if (Z_STR_P(op1) == Z_STR_P(op2)) {
2275 					return 0;
2276 				}
2277 				return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
2278 
2279 			case TYPE_PAIR(IS_NULL, IS_STRING):
2280 				return Z_STRLEN_P(op2) == 0 ? 0 : -1;
2281 
2282 			case TYPE_PAIR(IS_STRING, IS_NULL):
2283 				return Z_STRLEN_P(op1) == 0 ? 0 : 1;
2284 
2285 			case TYPE_PAIR(IS_LONG, IS_STRING):
2286 				return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2));
2287 
2288 			case TYPE_PAIR(IS_STRING, IS_LONG):
2289 				return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1));
2290 
2291 			case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2292 				if (zend_isnan(Z_DVAL_P(op1))) {
2293 					return 1;
2294 				}
2295 
2296 				return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2));
2297 
2298 			case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2299 				if (zend_isnan(Z_DVAL_P(op2))) {
2300 					return 1;
2301 				}
2302 
2303 				return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1));
2304 
2305 			case TYPE_PAIR(IS_OBJECT, IS_NULL):
2306 				return 1;
2307 
2308 			case TYPE_PAIR(IS_NULL, IS_OBJECT):
2309 				return -1;
2310 
2311 			default:
2312 				if (Z_ISREF_P(op1)) {
2313 					op1 = Z_REFVAL_P(op1);
2314 					continue;
2315 				} else if (Z_ISREF_P(op2)) {
2316 					op2 = Z_REFVAL_P(op2);
2317 					continue;
2318 				}
2319 
2320 				if (Z_TYPE_P(op1) == IS_OBJECT
2321 				 && Z_TYPE_P(op2) == IS_OBJECT
2322 				 && Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2323 					return 0;
2324 				} else if (Z_TYPE_P(op1) == IS_OBJECT) {
2325 					return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
2326 				} else if (Z_TYPE_P(op2) == IS_OBJECT) {
2327 					return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
2328 				}
2329 
2330 				if (!converted) {
2331 					if (Z_TYPE_P(op1) < IS_TRUE) {
2332 						return zval_is_true(op2) ? -1 : 0;
2333 					} else if (Z_TYPE_P(op1) == IS_TRUE) {
2334 						return zval_is_true(op2) ? 0 : 1;
2335 					} else if (Z_TYPE_P(op2) < IS_TRUE) {
2336 						return zval_is_true(op1) ? 1 : 0;
2337 					} else if (Z_TYPE_P(op2) == IS_TRUE) {
2338 						return zval_is_true(op1) ? 0 : -1;
2339 					} else {
2340 						op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
2341 						op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
2342 						if (EG(exception)) {
2343 							return 1; /* to stop comparison of arrays */
2344 						}
2345 						converted = 1;
2346 					}
2347 				} else if (Z_TYPE_P(op1)==IS_ARRAY) {
2348 					return 1;
2349 				} else if (Z_TYPE_P(op2)==IS_ARRAY) {
2350 					return -1;
2351 				} else {
2352 					ZEND_UNREACHABLE();
2353 					zend_throw_error(NULL, "Unsupported operand types");
2354 					return 1;
2355 				}
2356 		}
2357 	}
2358 }
2359 /* }}} */
2360 
2361 /* return int to be compatible with compare_func_t */
hash_zval_identical_function(zval * z1,zval * z2)2362 static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */
2363 {
2364 	/* is_identical_function() returns 1 in case of identity and 0 in case
2365 	 * of a difference;
2366 	 * whereas this comparison function is expected to return 0 on identity,
2367 	 * and non zero otherwise.
2368 	 */
2369 	ZVAL_DEREF(z1);
2370 	ZVAL_DEREF(z2);
2371 	return fast_is_not_identical_function(z1, z2);
2372 }
2373 /* }}} */
2374 
zend_is_identical(const zval * op1,const zval * op2)2375 ZEND_API bool ZEND_FASTCALL zend_is_identical(const zval *op1, const zval *op2) /* {{{ */
2376 {
2377 	if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
2378 		return 0;
2379 	}
2380 	switch (Z_TYPE_P(op1)) {
2381 		case IS_NULL:
2382 		case IS_FALSE:
2383 		case IS_TRUE:
2384 			return 1;
2385 		case IS_LONG:
2386 			return (Z_LVAL_P(op1) == Z_LVAL_P(op2));
2387 		case IS_RESOURCE:
2388 			return (Z_RES_P(op1) == Z_RES_P(op2));
2389 		case IS_DOUBLE:
2390 			return (Z_DVAL_P(op1) == Z_DVAL_P(op2));
2391 		case IS_STRING:
2392 			return zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
2393 		case IS_ARRAY:
2394 			return (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
2395 				zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1) == 0);
2396 		case IS_OBJECT:
2397 			return (Z_OBJ_P(op1) == Z_OBJ_P(op2));
2398 		default:
2399 			return 0;
2400 	}
2401 }
2402 /* }}} */
2403 
is_identical_function(zval * result,zval * op1,zval * op2)2404 ZEND_API zend_result ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2405 {
2406 	ZVAL_BOOL(result, zend_is_identical(op1, op2));
2407 	return SUCCESS;
2408 }
2409 /* }}} */
2410 
is_not_identical_function(zval * result,zval * op1,zval * op2)2411 ZEND_API zend_result ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2412 {
2413 	ZVAL_BOOL(result, !zend_is_identical(op1, op2));
2414 	return SUCCESS;
2415 }
2416 /* }}} */
2417 
is_equal_function(zval * result,zval * op1,zval * op2)2418 ZEND_API zend_result ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2419 {
2420 	ZVAL_BOOL(result, zend_compare(op1, op2) == 0);
2421 	return SUCCESS;
2422 }
2423 /* }}} */
2424 
is_not_equal_function(zval * result,zval * op1,zval * op2)2425 ZEND_API zend_result ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2426 {
2427 	ZVAL_BOOL(result, (zend_compare(op1, op2) != 0));
2428 	return SUCCESS;
2429 }
2430 /* }}} */
2431 
is_smaller_function(zval * result,zval * op1,zval * op2)2432 ZEND_API zend_result ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2) /* {{{ */
2433 {
2434 	ZVAL_BOOL(result, (zend_compare(op1, op2) < 0));
2435 	return SUCCESS;
2436 }
2437 /* }}} */
2438 
is_smaller_or_equal_function(zval * result,zval * op1,zval * op2)2439 ZEND_API zend_result ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2440 {
2441 	ZVAL_BOOL(result, (zend_compare(op1, op2) <= 0));
2442 	return SUCCESS;
2443 }
2444 /* }}} */
2445 
zend_class_implements_interface(const zend_class_entry * class_ce,const zend_class_entry * interface_ce)2446 ZEND_API bool ZEND_FASTCALL zend_class_implements_interface(const zend_class_entry *class_ce, const zend_class_entry *interface_ce) /* {{{ */
2447 {
2448 	uint32_t i;
2449 	ZEND_ASSERT(interface_ce->ce_flags & ZEND_ACC_INTERFACE);
2450 
2451 	if (class_ce->num_interfaces) {
2452 		ZEND_ASSERT(class_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2453 		for (i = 0; i < class_ce->num_interfaces; i++) {
2454 			if (class_ce->interfaces[i] == interface_ce) {
2455 				return 1;
2456 			}
2457 		}
2458 	}
2459 	return 0;
2460 }
2461 /* }}} */
2462 
instanceof_function_slow(const zend_class_entry * instance_ce,const zend_class_entry * ce)2463 ZEND_API bool ZEND_FASTCALL instanceof_function_slow(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2464 {
2465 	ZEND_ASSERT(instance_ce != ce && "Should have been checked already");
2466 	if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2467 		uint32_t i;
2468 
2469 		if (instance_ce->num_interfaces) {
2470 			ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2471 			for (i = 0; i < instance_ce->num_interfaces; i++) {
2472 				if (instance_ce->interfaces[i] == ce) {
2473 					return 1;
2474 				}
2475 			}
2476 		}
2477 		return 0;
2478 	} else {
2479 		while (1) {
2480 			instance_ce = instance_ce->parent;
2481 			if (instance_ce == ce) {
2482 				return 1;
2483 			}
2484 			if (instance_ce == NULL) {
2485 				return 0;
2486 			}
2487 		}
2488 	}
2489 }
2490 /* }}} */
2491 
2492 #define LOWER_CASE 1
2493 #define UPPER_CASE 2
2494 #define NUMERIC 3
2495 
zend_string_only_has_ascii_alphanumeric(const zend_string * str)2496 ZEND_API bool zend_string_only_has_ascii_alphanumeric(const zend_string *str)
2497 {
2498 	const char *p = ZSTR_VAL(str);
2499 	const char *e = ZSTR_VAL(str) + ZSTR_LEN(str);
2500 	while (p < e) {
2501 		char c = *p++;
2502 		if (UNEXPECTED( c < '0' || c > 'z' || (c < 'a' && c > 'Z') || (c < 'A' && c > '9') ) ) {
2503 			return false;
2504 		}
2505 	}
2506 	return true;
2507 }
2508 
increment_string(zval * str)2509 static bool ZEND_FASTCALL increment_string(zval *str) /* {{{ */
2510 {
2511 	int carry=0;
2512 	size_t pos=Z_STRLEN_P(str)-1;
2513 	char *s;
2514 	zend_string *t;
2515 	int last=0; /* Shut up the compiler warning */
2516 	int ch;
2517 
2518 	if (UNEXPECTED(Z_STRLEN_P(str) == 0)) {
2519 		zend_error(E_DEPRECATED, "Increment on non-alphanumeric string is deprecated");
2520 		if (EG(exception)) {
2521 			return false;
2522 		}
2523 		/* A userland error handler can change the type from string to something else */
2524 		zval_ptr_dtor(str);
2525 		ZVAL_CHAR(str, '1');
2526 		return true;
2527 	}
2528 
2529 	if (UNEXPECTED(!zend_string_only_has_ascii_alphanumeric(Z_STR_P(str)))) {
2530 		zend_string *zstr = Z_STR_P(str);
2531 		zend_string_addref(zstr);
2532 		zend_error(E_DEPRECATED, "Increment on non-alphanumeric string is deprecated");
2533 		if (EG(exception)) {
2534 			zend_string_release(zstr);
2535 			return false;
2536 		}
2537 		zval_ptr_dtor(str);
2538 		ZVAL_STR(str, zstr);
2539 	}
2540 
2541 	if (!Z_REFCOUNTED_P(str)) {
2542 		Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2543 		Z_TYPE_INFO_P(str) = IS_STRING_EX;
2544 	} else if (Z_REFCOUNT_P(str) > 1) {
2545 		/* Only release string after allocation succeeded. */
2546 		zend_string *orig_str = Z_STR_P(str);
2547 		Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2548 		GC_DELREF(orig_str);
2549 	} else {
2550 		zend_string_forget_hash_val(Z_STR_P(str));
2551 	}
2552 	s = Z_STRVAL_P(str);
2553 
2554 	do {
2555 		ch = s[pos];
2556 		if (ch >= 'a' && ch <= 'z') {
2557 			if (ch == 'z') {
2558 				s[pos] = 'a';
2559 				carry=1;
2560 			} else {
2561 				s[pos]++;
2562 				carry=0;
2563 			}
2564 			last=LOWER_CASE;
2565 		} else if (ch >= 'A' && ch <= 'Z') {
2566 			if (ch == 'Z') {
2567 				s[pos] = 'A';
2568 				carry=1;
2569 			} else {
2570 				s[pos]++;
2571 				carry=0;
2572 			}
2573 			last=UPPER_CASE;
2574 		} else if (ch >= '0' && ch <= '9') {
2575 			if (ch == '9') {
2576 				s[pos] = '0';
2577 				carry=1;
2578 			} else {
2579 				s[pos]++;
2580 				carry=0;
2581 			}
2582 			last = NUMERIC;
2583 		} else {
2584 			carry=0;
2585 			break;
2586 		}
2587 		if (carry == 0) {
2588 			break;
2589 		}
2590 	} while (pos-- > 0);
2591 
2592 	if (carry) {
2593 		t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
2594 		memcpy(ZSTR_VAL(t) + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
2595 		ZSTR_VAL(t)[Z_STRLEN_P(str) + 1] = '\0';
2596 		switch (last) {
2597 			case NUMERIC:
2598 				ZSTR_VAL(t)[0] = '1';
2599 				break;
2600 			case UPPER_CASE:
2601 				ZSTR_VAL(t)[0] = 'A';
2602 				break;
2603 			case LOWER_CASE:
2604 				ZSTR_VAL(t)[0] = 'a';
2605 				break;
2606 		}
2607 		zend_string_free(Z_STR_P(str));
2608 		ZVAL_NEW_STR(str, t);
2609 	}
2610 	return true;
2611 }
2612 /* }}} */
2613 
increment_function(zval * op1)2614 ZEND_API zend_result ZEND_FASTCALL increment_function(zval *op1) /* {{{ */
2615 {
2616 try_again:
2617 	switch (Z_TYPE_P(op1)) {
2618 		case IS_LONG:
2619 			fast_long_increment_function(op1);
2620 			break;
2621 		case IS_DOUBLE:
2622 			Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2623 			break;
2624 		case IS_NULL:
2625 			ZVAL_LONG(op1, 1);
2626 			break;
2627 		case IS_STRING: {
2628 				zend_long lval;
2629 				double dval;
2630 
2631 				switch (is_numeric_str_function(Z_STR_P(op1), &lval, &dval)) {
2632 					case IS_LONG:
2633 						zval_ptr_dtor_str(op1);
2634 						if (lval == ZEND_LONG_MAX) {
2635 							/* switch to double */
2636 							double d = (double)lval;
2637 							ZVAL_DOUBLE(op1, d+1);
2638 						} else {
2639 							ZVAL_LONG(op1, lval+1);
2640 						}
2641 						break;
2642 					case IS_DOUBLE:
2643 						zval_ptr_dtor_str(op1);
2644 						ZVAL_DOUBLE(op1, dval+1);
2645 						break;
2646 					default:
2647 						/* Perl style string increment */
2648 						increment_string(op1);
2649 						if (EG(exception)) {
2650 							return FAILURE;
2651 						}
2652 						break;
2653 				}
2654 			}
2655 			break;
2656 		case IS_FALSE:
2657 		case IS_TRUE: {
2658 			/* Error handler can undef/change type of op1, save it and reset it in case those cases */
2659 			zval copy;
2660 			ZVAL_COPY_VALUE(&copy, op1);
2661 			zend_error(E_WARNING, "Increment on type bool has no effect, this will change in the next major version of PHP");
2662 			zval_ptr_dtor(op1);
2663 			ZVAL_COPY_VALUE(op1, &copy);
2664 			if (EG(exception)) {
2665 				return FAILURE;
2666 			}
2667 			break;
2668 		}
2669 		case IS_REFERENCE:
2670 			op1 = Z_REFVAL_P(op1);
2671 			goto try_again;
2672 		case IS_OBJECT: {
2673 			if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2674 				zval op2;
2675 				ZVAL_LONG(&op2, 1);
2676 				if (Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2) == SUCCESS) {
2677 					return SUCCESS;
2678 				}
2679 			}
2680 			zval tmp;
2681 			if (Z_OBJ_HT_P(op1)->cast_object(Z_OBJ_P(op1), &tmp, _IS_NUMBER) == SUCCESS) {
2682 				ZEND_ASSERT(Z_TYPE(tmp) == IS_LONG || Z_TYPE(tmp) == IS_DOUBLE);
2683 				zval_ptr_dtor(op1);
2684 				ZVAL_COPY_VALUE(op1, &tmp);
2685 				goto try_again;
2686 			}
2687 			ZEND_FALLTHROUGH;
2688 		}
2689 		case IS_RESOURCE:
2690 		case IS_ARRAY:
2691 			zend_type_error("Cannot increment %s", zend_zval_value_name(op1));
2692 			return FAILURE;
2693 		EMPTY_SWITCH_DEFAULT_CASE()
2694 	}
2695 	return SUCCESS;
2696 }
2697 /* }}} */
2698 
decrement_function(zval * op1)2699 ZEND_API zend_result ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */
2700 {
2701 	zend_long lval;
2702 	double dval;
2703 
2704 try_again:
2705 	switch (Z_TYPE_P(op1)) {
2706 		case IS_LONG:
2707 			fast_long_decrement_function(op1);
2708 			break;
2709 		case IS_DOUBLE:
2710 			Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2711 			break;
2712 		case IS_STRING:		/* Like perl we only support string increment */
2713 			if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2714 				zend_error(E_DEPRECATED, "Decrement on empty string is deprecated as non-numeric");
2715 				if (EG(exception)) {
2716 					return FAILURE;
2717 				}
2718 				/* A userland error handler can change the type from string to something else */
2719 				zval_ptr_dtor(op1);
2720 				ZVAL_LONG(op1, -1);
2721 				break;
2722 			}
2723 			switch (is_numeric_str_function(Z_STR_P(op1), &lval, &dval)) {
2724 				case IS_LONG:
2725 					zval_ptr_dtor_str(op1);
2726 					if (lval == ZEND_LONG_MIN) {
2727 						double d = (double)lval;
2728 						ZVAL_DOUBLE(op1, d-1);
2729 					} else {
2730 						ZVAL_LONG(op1, lval-1);
2731 					}
2732 					break;
2733 				case IS_DOUBLE:
2734 					zval_ptr_dtor_str(op1);
2735 					ZVAL_DOUBLE(op1, dval - 1);
2736 					break;
2737 				default: {
2738 					/* Error handler can unset the variable */
2739 					zend_string *zstr = Z_STR_P(op1);
2740 					zend_string_addref(zstr);
2741 					zend_error(E_DEPRECATED, "Decrement on non-numeric string has no effect and is deprecated");
2742 					if (EG(exception)) {
2743 						zend_string_release(zstr);
2744 						return FAILURE;
2745 					}
2746 					zval_ptr_dtor(op1);
2747 					ZVAL_STR(op1, zstr);
2748 				}
2749 			}
2750 			break;
2751 		case IS_NULL: {
2752 			/* Error handler can undef/change type of op1, save it and reset it in case those cases */
2753 			zval copy;
2754 			ZVAL_COPY_VALUE(&copy, op1);
2755 			zend_error(E_WARNING, "Decrement on type null has no effect, this will change in the next major version of PHP");
2756 			zval_ptr_dtor(op1);
2757 			ZVAL_COPY_VALUE(op1, &copy);
2758 			if (EG(exception)) {
2759 				return FAILURE;
2760 			}
2761 			break;
2762 		}
2763 		case IS_FALSE:
2764 		case IS_TRUE: {
2765 			/* Error handler can undef/change type of op1, save it and reset it in case those cases */
2766 			zval copy;
2767 			ZVAL_COPY_VALUE(&copy, op1);
2768 			zend_error(E_WARNING, "Decrement on type bool has no effect, this will change in the next major version of PHP");
2769 			zval_ptr_dtor(op1);
2770 			ZVAL_COPY_VALUE(op1, &copy);
2771 			if (EG(exception)) {
2772 				return FAILURE;
2773 			}
2774 			break;
2775 		}
2776 		case IS_REFERENCE:
2777 			op1 = Z_REFVAL_P(op1);
2778 			goto try_again;
2779 		case IS_OBJECT: {
2780 			if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2781 				zval op2;
2782 				ZVAL_LONG(&op2, 1);
2783 				if (Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2) == SUCCESS) {
2784 					return SUCCESS;
2785 				}
2786 			}
2787 			zval tmp;
2788 			if (Z_OBJ_HT_P(op1)->cast_object(Z_OBJ_P(op1), &tmp, _IS_NUMBER) == SUCCESS) {
2789 				ZEND_ASSERT(Z_TYPE(tmp) == IS_LONG || Z_TYPE(tmp) == IS_DOUBLE);
2790 				zval_ptr_dtor(op1);
2791 				ZVAL_COPY_VALUE(op1, &tmp);
2792 				goto try_again;
2793 			}
2794 			ZEND_FALLTHROUGH;
2795 		}
2796 		case IS_RESOURCE:
2797 		case IS_ARRAY:
2798 			zend_type_error("Cannot decrement %s", zend_zval_value_name(op1));
2799 			return FAILURE;
2800 		EMPTY_SWITCH_DEFAULT_CASE()
2801 	}
2802 
2803 	return SUCCESS;
2804 }
2805 /* }}} */
2806 
zend_is_true(const zval * op)2807 ZEND_API int ZEND_FASTCALL zend_is_true(const zval *op) /* {{{ */
2808 {
2809 	return (int) i_zend_is_true(op);
2810 }
2811 /* }}} */
2812 
zend_object_is_true(const zval * op)2813 ZEND_API bool ZEND_FASTCALL zend_object_is_true(const zval *op) /* {{{ */
2814 {
2815 	zend_object *zobj = Z_OBJ_P(op);
2816 	zval tmp;
2817 	if (zobj->handlers->cast_object(zobj, &tmp, _IS_BOOL) == SUCCESS) {
2818 		return Z_TYPE(tmp) == IS_TRUE;
2819 	}
2820 	zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to bool", ZSTR_VAL(zobj->ce->name));
2821 	return false;
2822 }
2823 /* }}} */
2824 
zend_update_current_locale(void)2825 ZEND_API void zend_update_current_locale(void) /* {{{ */
2826 {
2827 #ifdef ZEND_USE_TOLOWER_L
2828 # if defined(ZEND_WIN32) && defined(_MSC_VER)
2829 	current_locale = _get_current_locale();
2830 # else
2831 	current_locale = uselocale(0);
2832 # endif
2833 #endif
2834 #if defined(ZEND_WIN32) && defined(_MSC_VER)
2835 	if (MB_CUR_MAX > 1) {
2836 		unsigned int cp = ___lc_codepage_func();
2837 		CG(variable_width_locale) = 1;
2838 		// TODO: EUC-* are also ASCII compatible ???
2839 		CG(ascii_compatible_locale) =
2840 			cp == 65001; /* UTF-8 */
2841 	} else {
2842 		CG(variable_width_locale) = 0;
2843 		CG(ascii_compatible_locale) = 1;
2844 	}
2845 #elif defined(MB_CUR_MAX)
2846 	/* Check if current locale uses variable width encoding */
2847 	if (MB_CUR_MAX > 1) {
2848 #if HAVE_NL_LANGINFO
2849 		const char *charmap = nl_langinfo(CODESET);
2850 #else
2851 		char buf[16];
2852 		const char *charmap = NULL;
2853 		const char *locale = setlocale(LC_CTYPE, NULL);
2854 
2855 		if (locale) {
2856 			const char *dot = strchr(locale, '.');
2857 			const char *modifier;
2858 
2859 			if (dot) {
2860 				dot++;
2861 				modifier = strchr(dot, '@');
2862 				if (!modifier) {
2863 					charmap = dot;
2864 				} else if (modifier - dot < sizeof(buf)) {
2865 					memcpy(buf, dot, modifier - dot);
2866                     buf[modifier - dot] = '\0';
2867                     charmap = buf;
2868 				}
2869 			}
2870 		}
2871 #endif
2872 		CG(variable_width_locale) = 1;
2873 		CG(ascii_compatible_locale) = 0;
2874 
2875 		if (charmap) {
2876 			size_t len = strlen(charmap);
2877 			static const char *ascii_compatible_charmaps[] = {
2878 				"utf-8",
2879 				"utf8",
2880 				// TODO: EUC-* are also ASCII compatible ???
2881 				NULL
2882 			};
2883 			const char **p;
2884 			/* Check if current locale is ASCII compatible */
2885 			for (p = ascii_compatible_charmaps; *p; p++) {
2886 				if (zend_binary_strcasecmp(charmap, len, *p, strlen(*p)) == 0) {
2887 					CG(ascii_compatible_locale) = 1;
2888 					break;
2889 				}
2890 			}
2891 		}
2892 
2893 	} else {
2894 		CG(variable_width_locale) = 0;
2895 		CG(ascii_compatible_locale) = 1;
2896 	}
2897 #else
2898 	/* We can't determine current charset. Assume the worst case */
2899 	CG(variable_width_locale) = 1;
2900 	CG(ascii_compatible_locale) = 0;
2901 #endif
2902 }
2903 /* }}} */
2904 
zend_reset_lc_ctype_locale(void)2905 ZEND_API void zend_reset_lc_ctype_locale(void)
2906 {
2907 	/* Use the C.UTF-8 locale so that readline can process UTF-8 input, while not interfering
2908 	 * with single-byte locale-dependent functions used by PHP. */
2909 	if (!setlocale(LC_CTYPE, "C.UTF-8")) {
2910 		setlocale(LC_CTYPE, "C");
2911 	}
2912 }
2913 
zend_str_tolower_impl(char * dest,const char * str,size_t length)2914 static zend_always_inline void zend_str_tolower_impl(char *dest, const char *str, size_t length) /* {{{ */ {
2915 	unsigned char *p = (unsigned char*)str;
2916 	unsigned char *q = (unsigned char*)dest;
2917 	unsigned char *end = p + length;
2918 #ifdef HAVE_BLOCKCONV
2919 	if (length >= BLOCKCONV_STRIDE) {
2920 		BLOCKCONV_INIT_RANGE('A', 'Z');
2921 		BLOCKCONV_INIT_DELTA('a' - 'A');
2922 		do {
2923 			BLOCKCONV_LOAD(p);
2924 			BLOCKCONV_STORE(q);
2925 			p += BLOCKCONV_STRIDE;
2926 			q += BLOCKCONV_STRIDE;
2927 		} while (p + BLOCKCONV_STRIDE <= end);
2928 	}
2929 #endif
2930 	while (p < end) {
2931 		*q++ = zend_tolower_ascii(*p++);
2932 	}
2933 }
2934 /* }}} */
2935 
zend_str_toupper_impl(char * dest,const char * str,size_t length)2936 static zend_always_inline void zend_str_toupper_impl(char *dest, const char *str, size_t length) /* {{{ */ {
2937 	unsigned char *p = (unsigned char*)str;
2938 	unsigned char *q = (unsigned char*)dest;
2939 	unsigned char *end = p + length;
2940 #ifdef HAVE_BLOCKCONV
2941 	if (length >= BLOCKCONV_STRIDE) {
2942 		BLOCKCONV_INIT_RANGE('a', 'z');
2943 		BLOCKCONV_INIT_DELTA('A' - 'a');
2944 		do {
2945 			BLOCKCONV_LOAD(p);
2946 			BLOCKCONV_STORE(q);
2947 			p += BLOCKCONV_STRIDE;
2948 			q += BLOCKCONV_STRIDE;
2949 		} while (p + BLOCKCONV_STRIDE <= end);
2950 	}
2951 #endif
2952 	while (p < end) {
2953 		*q++ = zend_toupper_ascii(*p++);
2954 	}
2955 }
2956 /* }}} */
2957 
zend_str_tolower_copy(char * dest,const char * source,size_t length)2958 ZEND_API char* ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
2959 {
2960 	zend_str_tolower_impl(dest, source, length);
2961 	dest[length] = '\0';
2962 	return dest;
2963 }
2964 /* }}} */
2965 
zend_str_toupper_copy(char * dest,const char * source,size_t length)2966 ZEND_API char* ZEND_FASTCALL zend_str_toupper_copy(char *dest, const char *source, size_t length) /* {{{ */
2967 {
2968 	zend_str_toupper_impl(dest, source, length);
2969 	dest[length] = '\0';
2970 	return dest;
2971 }
2972 /* }}} */
2973 
zend_str_tolower_dup(const char * source,size_t length)2974 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2975 {
2976 	return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2977 }
2978 /* }}} */
2979 
zend_str_toupper_dup(const char * source,size_t length)2980 ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup(const char *source, size_t length) /* {{{ */
2981 {
2982 	return zend_str_toupper_copy((char *)emalloc(length+1), source, length);
2983 }
2984 /* }}} */
2985 
zend_str_tolower(char * str,size_t length)2986 ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length) /* {{{ */
2987 {
2988 	zend_str_tolower_impl(str, (const char*)str, length);
2989 }
2990 /* }}} */
2991 
zend_str_toupper(char * str,size_t length)2992 ZEND_API void ZEND_FASTCALL zend_str_toupper(char *str, size_t length) /* {{{ */
2993 {
2994 	zend_str_toupper_impl(str, (const char*)str, length);
2995 }
2996 /* }}} */
2997 
2998 
zend_str_tolower_dup_ex(const char * source,size_t length)2999 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length) /* {{{ */
3000 {
3001 	const unsigned char *p = (const unsigned char*)source;
3002 	const unsigned char *end = p + length;
3003 
3004 	while (p < end) {
3005 		if (*p != zend_tolower_ascii(*p)) {
3006 			char *res = (char*)emalloc(length + 1);
3007 			unsigned char *r;
3008 
3009 			if (p != (const unsigned char*)source) {
3010 				memcpy(res, source, p - (const unsigned char*)source);
3011 			}
3012 			r = (unsigned char*)p + (res - source);
3013 			zend_str_tolower_impl((char *)r, (const char*)p, end - p);
3014 			res[length] = '\0';
3015 			return res;
3016 		}
3017 		p++;
3018 	}
3019 	return NULL;
3020 }
3021 /* }}} */
3022 
zend_str_toupper_dup_ex(const char * source,size_t length)3023 ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup_ex(const char *source, size_t length) /* {{{ */
3024 {
3025 	const unsigned char *p = (const unsigned char*)source;
3026 	const unsigned char *end = p + length;
3027 
3028 	while (p < end) {
3029 		if (*p != zend_toupper_ascii(*p)) {
3030 			char *res = (char*)emalloc(length + 1);
3031 			unsigned char *r;
3032 
3033 			if (p != (const unsigned char*)source) {
3034 				memcpy(res, source, p - (const unsigned char*)source);
3035 			}
3036 			r = (unsigned char*)p + (res - source);
3037 			zend_str_toupper_impl((char *)r, (const char*)p, end - p);
3038 			res[length] = '\0';
3039 			return res;
3040 		}
3041 		p++;
3042 	}
3043 	return NULL;
3044 }
3045 /* }}} */
3046 
zend_string_tolower_ex(zend_string * str,bool persistent)3047 ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) /* {{{ */
3048 {
3049 	size_t length = ZSTR_LEN(str);
3050 	unsigned char *p = (unsigned char *) ZSTR_VAL(str);
3051 	unsigned char *end = p + length;
3052 
3053 #ifdef HAVE_BLOCKCONV
3054 	BLOCKCONV_INIT_RANGE('A', 'Z');
3055 	while (p + BLOCKCONV_STRIDE <= end) {
3056 		BLOCKCONV_LOAD(p);
3057 		if (BLOCKCONV_FOUND()) {
3058 			zend_string *res = zend_string_alloc(length, persistent);
3059 			memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
3060 			unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
3061 
3062 			/* Lowercase the chunk we already compared. */
3063 			BLOCKCONV_INIT_DELTA('a' - 'A');
3064 			BLOCKCONV_STORE(q);
3065 
3066 			/* Lowercase the rest of the string. */
3067 			p += BLOCKCONV_STRIDE;
3068 			q += BLOCKCONV_STRIDE;
3069 			zend_str_tolower_impl((char *) q, (const char *) p, end - p);
3070 			ZSTR_VAL(res)[length] = '\0';
3071 			return res;
3072 		}
3073 		p += BLOCKCONV_STRIDE;
3074 	}
3075 #endif
3076 
3077 	while (p < end) {
3078 		if (*p != zend_tolower_ascii(*p)) {
3079 			zend_string *res = zend_string_alloc(length, persistent);
3080 			memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
3081 
3082 			unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
3083 			while (p < end) {
3084 				*q++ = zend_tolower_ascii(*p++);
3085 			}
3086 			ZSTR_VAL(res)[length] = '\0';
3087 			return res;
3088 		}
3089 		p++;
3090 	}
3091 
3092 	return zend_string_copy(str);
3093 }
3094 /* }}} */
3095 
zend_string_toupper_ex(zend_string * str,bool persistent)3096 ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent) /* {{{ */
3097 {
3098 	size_t length = ZSTR_LEN(str);
3099 	unsigned char *p = (unsigned char *) ZSTR_VAL(str);
3100 	unsigned char *end = p + length;
3101 
3102 #ifdef HAVE_BLOCKCONV
3103 	BLOCKCONV_INIT_RANGE('a', 'z');
3104 	while (p + BLOCKCONV_STRIDE <= end) {
3105 		BLOCKCONV_LOAD(p);
3106 		if (BLOCKCONV_FOUND()) {
3107 			zend_string *res = zend_string_alloc(length, persistent);
3108 			memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
3109 			unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str));
3110 
3111 			/* Uppercase the chunk we already compared. */
3112 			BLOCKCONV_INIT_DELTA('A' - 'a');
3113 			BLOCKCONV_STORE(q);
3114 
3115 			/* Uppercase the rest of the string. */
3116 			p += BLOCKCONV_STRIDE;
3117 			q += BLOCKCONV_STRIDE;
3118 			zend_str_toupper_impl((char *) q, (const char *) p, end - p);
3119 			ZSTR_VAL(res)[length] = '\0';
3120 			return res;
3121 		}
3122 		p += BLOCKCONV_STRIDE;
3123 	}
3124 #endif
3125 
3126 	while (p < end) {
3127 		if (*p != zend_toupper_ascii(*p)) {
3128 			zend_string *res = zend_string_alloc(length, persistent);
3129 			memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
3130 
3131 			unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str));
3132 			while (p < end) {
3133 				*q++ = zend_toupper_ascii(*p++);
3134 			}
3135 			ZSTR_VAL(res)[length] = '\0';
3136 			return res;
3137 		}
3138 		p++;
3139 	}
3140 
3141 	return zend_string_copy(str);
3142 }
3143 /* }}} */
3144 
zend_binary_strcmp(const char * s1,size_t len1,const char * s2,size_t len2)3145 ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
3146 {
3147 	int retval;
3148 
3149 	if (s1 == s2) {
3150 		return 0;
3151 	}
3152 	retval = memcmp(s1, s2, MIN(len1, len2));
3153 	if (!retval) {
3154 		return ZEND_THREEWAY_COMPARE(len1, len2);
3155 	} else {
3156 		return retval;
3157 	}
3158 }
3159 /* }}} */
3160 
zend_binary_strncmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)3161 ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
3162 {
3163 	int retval;
3164 
3165 	if (s1 == s2) {
3166 		return 0;
3167 	}
3168 	retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
3169 	if (!retval) {
3170 		return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
3171 	} else {
3172 		return retval;
3173 	}
3174 }
3175 /* }}} */
3176 
zend_binary_strcasecmp(const char * s1,size_t len1,const char * s2,size_t len2)3177 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
3178 {
3179 	size_t len;
3180 	int c1, c2;
3181 
3182 	if (s1 == s2) {
3183 		return 0;
3184 	}
3185 
3186 	len = MIN(len1, len2);
3187 	while (len--) {
3188 		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
3189 		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
3190 		if (c1 != c2) {
3191 			return c1 - c2;
3192 		}
3193 	}
3194 
3195 	return ZEND_THREEWAY_COMPARE(len1, len2);
3196 }
3197 /* }}} */
3198 
zend_binary_strncasecmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)3199 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
3200 {
3201 	size_t len;
3202 	int c1, c2;
3203 
3204 	if (s1 == s2) {
3205 		return 0;
3206 	}
3207 	len = MIN(length, MIN(len1, len2));
3208 	while (len--) {
3209 		c1 = zend_tolower_ascii(*(unsigned char *)s1++);
3210 		c2 = zend_tolower_ascii(*(unsigned char *)s2++);
3211 		if (c1 != c2) {
3212 			return c1 - c2;
3213 		}
3214 	}
3215 
3216 	return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
3217 }
3218 /* }}} */
3219 
zend_binary_strcasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2)3220 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
3221 {
3222 	size_t len;
3223 	int c1, c2;
3224 
3225 	if (s1 == s2) {
3226 		return 0;
3227 	}
3228 
3229 	len = MIN(len1, len2);
3230 	while (len--) {
3231 		c1 = zend_tolower((int)*(unsigned char *)s1++);
3232 		c2 = zend_tolower((int)*(unsigned char *)s2++);
3233 		if (c1 != c2) {
3234 			return c1 - c2;
3235 		}
3236 	}
3237 
3238 	return ZEND_THREEWAY_COMPARE(len1, len2);
3239 }
3240 /* }}} */
3241 
zend_binary_strncasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)3242 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
3243 {
3244 	size_t len;
3245 	int c1, c2;
3246 
3247 	if (s1 == s2) {
3248 		return 0;
3249 	}
3250 	len = MIN(length, MIN(len1, len2));
3251 	while (len--) {
3252 		c1 = zend_tolower((int)*(unsigned char *)s1++);
3253 		c2 = zend_tolower((int)*(unsigned char *)s2++);
3254 		if (c1 != c2) {
3255 			return c1 - c2;
3256 		}
3257 	}
3258 
3259 	return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
3260 }
3261 /* }}} */
3262 
zend_binary_zval_strcmp(zval * s1,zval * s2)3263 ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
3264 {
3265 	return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
3266 }
3267 /* }}} */
3268 
zend_binary_zval_strncmp(zval * s1,zval * s2,zval * s3)3269 ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
3270 {
3271 	return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
3272 }
3273 /* }}} */
3274 
zendi_smart_streq(zend_string * s1,zend_string * s2)3275 ZEND_API bool ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2) /* {{{ */
3276 {
3277 	uint8_t ret1, ret2;
3278 	int oflow1, oflow2;
3279 	zend_long lval1 = 0, lval2 = 0;
3280 	double dval1 = 0.0, dval2 = 0.0;
3281 
3282 	if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
3283 		(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
3284 #if ZEND_ULONG_MAX == 0xFFFFFFFF
3285 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
3286 			((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
3287 			|| (oflow1 == -1 && dval1 < -9007199254740991.))) {
3288 #else
3289 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
3290 #endif
3291 			/* both values are integers overflown to the same side, and the
3292 			 * double comparison may have resulted in crucial accuracy lost */
3293 			goto string_cmp;
3294 		}
3295 		if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
3296 			if (ret1 != IS_DOUBLE) {
3297 				if (oflow2) {
3298 					/* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
3299 					return 0;
3300 				}
3301 				dval1 = (double) lval1;
3302 			} else if (ret2 != IS_DOUBLE) {
3303 				if (oflow1) {
3304 					return 0;
3305 				}
3306 				dval2 = (double) lval2;
3307 			} else if (dval1 == dval2 && !zend_finite(dval1)) {
3308 				/* Both values overflowed and have the same sign,
3309 				 * so a numeric comparison would be inaccurate */
3310 				goto string_cmp;
3311 			}
3312 			return dval1 == dval2;
3313 		} else { /* they both have to be long's */
3314 			return lval1 == lval2;
3315 		}
3316 	} else {
3317 string_cmp:
3318 		return zend_string_equal_content(s1, s2);
3319 	}
3320 }
3321 /* }}} */
3322 
3323 ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2) /* {{{ */
3324 {
3325 	uint8_t ret1, ret2;
3326 	int oflow1, oflow2;
3327 	zend_long lval1 = 0, lval2 = 0;
3328 	double dval1 = 0.0, dval2 = 0.0;
3329 
3330 	if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
3331 		(ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
3332 #if ZEND_ULONG_MAX == 0xFFFFFFFF
3333 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
3334 			((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
3335 			|| (oflow1 == -1 && dval1 < -9007199254740991.))) {
3336 #else
3337 		if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
3338 #endif
3339 			/* both values are integers overflowed to the same side, and the
3340 			 * double comparison may have resulted in crucial accuracy lost */
3341 			goto string_cmp;
3342 		}
3343 		if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
3344 			if (ret1 != IS_DOUBLE) {
3345 				if (oflow2) {
3346 					/* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
3347 					return -1 * oflow2;
3348 				}
3349 				dval1 = (double) lval1;
3350 			} else if (ret2 != IS_DOUBLE) {
3351 				if (oflow1) {
3352 					return oflow1;
3353 				}
3354 				dval2 = (double) lval2;
3355 			} else if (dval1 == dval2 && !zend_finite(dval1)) {
3356 				/* Both values overflowed and have the same sign,
3357 				 * so a numeric comparison would be inaccurate */
3358 				goto string_cmp;
3359 			}
3360 			dval1 = dval1 - dval2;
3361 			return ZEND_NORMALIZE_BOOL(dval1);
3362 		} else { /* they both have to be long's */
3363 			return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
3364 		}
3365 	} else {
3366 		int strcmp_ret;
3367 string_cmp:
3368 		strcmp_ret = zend_binary_strcmp(s1->val, s1->len, s2->val, s2->len);
3369 		return ZEND_NORMALIZE_BOOL(strcmp_ret);
3370 	}
3371 }
3372 /* }}} */
3373 
3374 static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */
3375 {
3376 	return zend_compare(z1, z2);
3377 }
3378 /* }}} */
3379 
3380 ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */
3381 {
3382 	return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
3383 }
3384 /* }}} */
3385 
3386 ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */
3387 {
3388 	return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2));
3389 }
3390 /* }}} */
3391 
3392 ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */
3393 {
3394 	if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
3395 		return 0;
3396 	}
3397 
3398 	if (Z_OBJ_HT_P(o1)->compare == NULL) {
3399 		return 1;
3400 	} else {
3401 		return Z_OBJ_HT_P(o1)->compare(o1, o2);
3402 	}
3403 }
3404 /* }}} */
3405 
3406 ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */
3407 {
3408 	if ((zend_ulong)num <= 9) {
3409 		return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3410 	} else {
3411 		char buf[MAX_LENGTH_OF_LONG + 1];
3412 		char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
3413 		zend_string *str =  zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3414 		GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3415 		return str;
3416 	}
3417 }
3418 /* }}} */
3419 
3420 ZEND_API zend_string* ZEND_FASTCALL zend_ulong_to_str(zend_ulong num)
3421 {
3422 	if (num <= 9) {
3423 		return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3424 	} else {
3425 		char buf[MAX_LENGTH_OF_LONG + 1];
3426 		char *res = zend_print_ulong_to_buf(buf + sizeof(buf) - 1, num);
3427 		zend_string *str =  zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3428 		GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3429 		return str;
3430 	}
3431 }
3432 
3433 /* buf points to the END of the buffer */
3434 static zend_always_inline char *zend_print_u64_to_buf(char *buf, uint64_t num64) {
3435 #if SIZEOF_ZEND_LONG == 8
3436 	return zend_print_ulong_to_buf(buf, num64);
3437 #else
3438 	*buf = '\0';
3439 	while (num64 > ZEND_ULONG_MAX) {
3440 		*--buf = (char) (num64 % 10) + '0';
3441 		num64 /= 10;
3442 	}
3443 
3444 	zend_ulong num = (zend_ulong) num64;
3445 	do {
3446 		*--buf = (char) (num % 10) + '0';
3447 		num /= 10;
3448 	} while (num > 0);
3449 	return buf;
3450 #endif
3451 }
3452 
3453 /* buf points to the END of the buffer */
3454 static zend_always_inline char *zend_print_i64_to_buf(char *buf, int64_t num) {
3455 	if (num < 0) {
3456 	    char *result = zend_print_u64_to_buf(buf, ~((uint64_t) num) + 1);
3457 	    *--result = '-';
3458 		return result;
3459 	} else {
3460 	    return zend_print_u64_to_buf(buf, num);
3461 	}
3462 }
3463 
3464 ZEND_API zend_string* ZEND_FASTCALL zend_u64_to_str(uint64_t num)
3465 {
3466 	if (num <= 9) {
3467 		return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3468 	} else {
3469 		char buf[20 + 1];
3470 		char *res = zend_print_u64_to_buf(buf + sizeof(buf) - 1, num);
3471 		zend_string *str =  zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3472 		GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3473 		return str;
3474 	}
3475 }
3476 
3477 ZEND_API zend_string* ZEND_FASTCALL zend_i64_to_str(int64_t num)
3478 {
3479 	if ((uint64_t)num <= 9) {
3480 		return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3481 	} else {
3482 		char buf[20 + 1];
3483 		char *res = zend_print_i64_to_buf(buf + sizeof(buf) - 1, num);
3484 		zend_string *str =  zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3485 		GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3486 		return str;
3487 	}
3488 }
3489 
3490 ZEND_API zend_string* ZEND_FASTCALL zend_double_to_str(double num)
3491 {
3492 	char buf[ZEND_DOUBLE_MAX_LENGTH];
3493 	/* Model snprintf precision behavior. */
3494 	int precision = (int) EG(precision);
3495 	zend_gcvt(num, precision ? precision : 1, '.', 'E', buf);
3496 	zend_string *str =  zend_string_init(buf, strlen(buf), 0);
3497 	GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3498 	return str;
3499 }
3500 
3501 ZEND_API uint8_t ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */
3502 {
3503 	return is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), lval, dval, false);
3504 }
3505 /* }}} */
3506 
3507 ZEND_API uint8_t ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval,
3508 	double *dval, bool allow_errors, int *oflow_info, bool *trailing_data) /* {{{ */
3509 {
3510 	const char *ptr;
3511 	int digits = 0, dp_or_e = 0;
3512 	double local_dval = 0.0;
3513 	uint8_t type;
3514 	zend_ulong tmp_lval = 0;
3515 	int neg = 0;
3516 
3517 	if (!length) {
3518 		return 0;
3519 	}
3520 
3521 	if (oflow_info != NULL) {
3522 		*oflow_info = 0;
3523 	}
3524 	if (trailing_data != NULL) {
3525 		*trailing_data = false;
3526 	}
3527 
3528 	/* Skip any whitespace
3529 	 * This is much faster than the isspace() function */
3530 	while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
3531 		str++;
3532 		length--;
3533 	}
3534 	ptr = str;
3535 
3536 	if (*ptr == '-') {
3537 		neg = 1;
3538 		ptr++;
3539 	} else if (*ptr == '+') {
3540 		ptr++;
3541 	}
3542 
3543 	if (ZEND_IS_DIGIT(*ptr)) {
3544 		/* Skip any leading 0s */
3545 		while (*ptr == '0') {
3546 			ptr++;
3547 		}
3548 
3549 		/* Count the number of digits. If a decimal point/exponent is found,
3550 		 * it's a double. Otherwise, if there's a dval or no need to check for
3551 		 * a full match, stop when there are too many digits for a long */
3552 		for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors)); digits++, ptr++) {
3553 check_digits:
3554 			if (ZEND_IS_DIGIT(*ptr)) {
3555 				tmp_lval = tmp_lval * 10 + (*ptr) - '0';
3556 				continue;
3557 			} else if (*ptr == '.' && dp_or_e < 1) {
3558 				goto process_double;
3559 			} else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
3560 				const char *e = ptr + 1;
3561 
3562 				if (*e == '-' || *e == '+') {
3563 					ptr = e++;
3564 				}
3565 				if (ZEND_IS_DIGIT(*e)) {
3566 					goto process_double;
3567 				}
3568 			}
3569 
3570 			break;
3571 		}
3572 
3573 		if (digits >= MAX_LENGTH_OF_LONG) {
3574 			if (oflow_info != NULL) {
3575 				*oflow_info = *str == '-' ? -1 : 1;
3576 			}
3577 			dp_or_e = -1;
3578 			goto process_double;
3579 		}
3580 	} else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
3581 process_double:
3582 		type = IS_DOUBLE;
3583 
3584 		/* If there's a dval, do the conversion; else continue checking
3585 		 * the digits if we need to check for a full match */
3586 		if (dval) {
3587 			local_dval = zend_strtod(str, &ptr);
3588 		} else if (!allow_errors && dp_or_e != -1) {
3589 			dp_or_e = (*ptr++ == '.') ? 1 : 2;
3590 			goto check_digits;
3591 		}
3592 	} else {
3593 		return 0;
3594 	}
3595 
3596 	if (ptr != str + length) {
3597 		const char *endptr = ptr;
3598 		while (*endptr == ' ' || *endptr == '\t' || *endptr == '\n' || *endptr == '\r' || *endptr == '\v' || *endptr == '\f') {
3599 			endptr++;
3600 			length--;
3601 		}
3602 		if (ptr != str + length) {
3603 			if (!allow_errors) {
3604 				return 0;
3605 			}
3606 			if (trailing_data != NULL) {
3607 				*trailing_data = true;
3608 			}
3609 		}
3610 	}
3611 
3612 	if (type == IS_LONG) {
3613 		if (digits == MAX_LENGTH_OF_LONG - 1) {
3614 			int cmp = strcmp(&ptr[-digits], long_min_digits);
3615 
3616 			if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
3617 				if (dval) {
3618 					*dval = zend_strtod(str, NULL);
3619 				}
3620 				if (oflow_info != NULL) {
3621 					*oflow_info = *str == '-' ? -1 : 1;
3622 				}
3623 
3624 				return IS_DOUBLE;
3625 			}
3626 		}
3627 
3628 		if (lval) {
3629 			if (neg) {
3630 				tmp_lval = -tmp_lval;
3631 			}
3632 			*lval = (zend_long) tmp_lval;
3633 		}
3634 
3635 		return IS_LONG;
3636 	} else {
3637 		if (dval) {
3638 			*dval = local_dval;
3639 		}
3640 
3641 		return IS_DOUBLE;
3642 	}
3643 }
3644 /* }}} */
3645 
3646 /*
3647  * String matching - Sunday algorithm
3648  * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
3649  */
3650 static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
3651 	int i;
3652 
3653 	for (i = 0; i < 256; i++) {
3654 		td[i] = needle_len + 1;
3655 	}
3656 
3657 	if (reverse) {
3658 		for (i = needle_len - 1; i >= 0; i--) {
3659 			td[(unsigned char)needle[i]] = i + 1;
3660 		}
3661 	} else {
3662 		size_t i;
3663 
3664 		for (i = 0; i < needle_len; i++) {
3665 			td[(unsigned char)needle[i]] = (int)needle_len - i;
3666 		}
3667 	}
3668 }
3669 /* }}} */
3670 
3671 ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3672 {
3673 	unsigned int td[256];
3674 	size_t i;
3675 	const char *p;
3676 
3677 	if (needle_len == 0 || (end - haystack) < needle_len) {
3678 		return NULL;
3679 	}
3680 
3681 	zend_memnstr_ex_pre(td, needle, needle_len, 0);
3682 
3683 	p = haystack;
3684 	end -= needle_len;
3685 
3686 	while (p <= end) {
3687 		for (i = 0; i < needle_len; i++) {
3688 			if (needle[i] != p[i]) {
3689 				break;
3690 			}
3691 		}
3692 		if (i == needle_len) {
3693 			return p;
3694 		}
3695 		if (UNEXPECTED(p == end)) {
3696 			return NULL;
3697 		}
3698 		p += td[(unsigned char)(p[needle_len])];
3699 	}
3700 
3701 	return NULL;
3702 }
3703 /* }}} */
3704 
3705 ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3706 {
3707 	unsigned int td[256];
3708 	size_t i;
3709 	const char *p;
3710 
3711 	if (needle_len == 0 || (end - haystack) < needle_len) {
3712 		return NULL;
3713 	}
3714 
3715 	zend_memnstr_ex_pre(td, needle, needle_len, 1);
3716 
3717 	p = end;
3718 	p -= needle_len;
3719 
3720 	while (p >= haystack) {
3721 		for (i = 0; i < needle_len; i++) {
3722 			if (needle[i] != p[i]) {
3723 				break;
3724 			}
3725 		}
3726 
3727 		if (i == needle_len) {
3728 			return (const char *)p;
3729 		}
3730 
3731 		if (UNEXPECTED(p == haystack)) {
3732 			return NULL;
3733 		}
3734 
3735 		p -= td[(unsigned char)(p[-1])];
3736 	}
3737 
3738 	return NULL;
3739 }
3740 /* }}} */
3741 
3742 #if SIZEOF_ZEND_LONG == 4
3743 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d) /* {{{ */
3744 {
3745 	double	two_pow_32 = pow(2., 32.),
3746 			dmod;
3747 
3748 	dmod = fmod(d, two_pow_32);
3749 	if (dmod < 0) {
3750 		/* we're going to make this number positive; call ceil()
3751 		 * to simulate rounding towards 0 of the negative number */
3752 		dmod = ceil(dmod) + two_pow_32;
3753 	}
3754 	return (zend_long)(zend_ulong)dmod;
3755 }
3756 #else
3757 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
3758 {
3759 	double	two_pow_64 = pow(2., 64.),
3760 			dmod;
3761 
3762 	dmod = fmod(d, two_pow_64);
3763 	if (dmod < 0) {
3764 		/* no need to call ceil; original double must have had no
3765 		 * fractional part, hence dmod does not have one either */
3766 		dmod += two_pow_64;
3767 	}
3768 	return (zend_long)(zend_ulong)dmod;
3769 }
3770 /* }}} */
3771 #endif
3772