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