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