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