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