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