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