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