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