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