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