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(str2));
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(str2));
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_reset_lc_ctype_locale(void)2665 ZEND_API void zend_reset_lc_ctype_locale(void)
2666 {
2667 /* Use the C.UTF-8 locale so that readline can process UTF-8 input, while not interfering
2668 * with single-byte locale-dependent functions used by PHP. */
2669 if (!setlocale(LC_CTYPE, "C.UTF-8")) {
2670 setlocale(LC_CTYPE, "C");
2671 }
2672 }
2673
zend_str_tolower_impl(char * dest,const char * str,size_t length)2674 static zend_always_inline void zend_str_tolower_impl(char *dest, const char *str, size_t length) /* {{{ */ {
2675 unsigned char *p = (unsigned char*)str;
2676 unsigned char *q = (unsigned char*)dest;
2677 unsigned char *end = p + length;
2678 #ifdef __SSE2__
2679 if (length >= 16) {
2680 const __m128i _A = _mm_set1_epi8('A' - 1);
2681 const __m128i Z_ = _mm_set1_epi8('Z' + 1);
2682 const __m128i delta = _mm_set1_epi8('a' - 'A');
2683 do {
2684 __m128i op = _mm_loadu_si128((__m128i*)p);
2685 __m128i gt = _mm_cmpgt_epi8(op, _A);
2686 __m128i lt = _mm_cmplt_epi8(op, Z_);
2687 __m128i mingle = _mm_and_si128(gt, lt);
2688 __m128i add = _mm_and_si128(mingle, delta);
2689 __m128i lower = _mm_add_epi8(op, add);
2690 _mm_storeu_si128((__m128i *)q, lower);
2691 p += 16;
2692 q += 16;
2693 } while (p + 16 <= end);
2694 }
2695 #endif
2696 while (p < end) {
2697 *q++ = zend_tolower_ascii(*p++);
2698 }
2699 }
2700 /* }}} */
2701
zend_str_tolower_copy(char * dest,const char * source,size_t length)2702 ZEND_API char* ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
2703 {
2704 zend_str_tolower_impl(dest, source, length);
2705 dest[length] = '\0';
2706 return dest;
2707 }
2708 /* }}} */
2709
zend_str_tolower_dup(const char * source,size_t length)2710 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2711 {
2712 return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2713 }
2714 /* }}} */
2715
zend_str_tolower(char * str,size_t length)2716 ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length) /* {{{ */
2717 {
2718 zend_str_tolower_impl(str, (const char*)str, length);
2719 }
2720 /* }}} */
2721
zend_str_tolower_dup_ex(const char * source,size_t length)2722 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length) /* {{{ */
2723 {
2724 const unsigned char *p = (const unsigned char*)source;
2725 const unsigned char *end = p + length;
2726
2727 while (p < end) {
2728 if (*p != zend_tolower_ascii(*p)) {
2729 char *res = (char*)emalloc(length + 1);
2730 unsigned char *r;
2731
2732 if (p != (const unsigned char*)source) {
2733 memcpy(res, source, p - (const unsigned char*)source);
2734 }
2735 r = (unsigned char*)p + (res - source);
2736 zend_str_tolower_impl((char *)r, (const char*)p, end - p);
2737 res[length] = '\0';
2738 return res;
2739 }
2740 p++;
2741 }
2742 return NULL;
2743 }
2744 /* }}} */
2745
zend_string_tolower_ex(zend_string * str,bool persistent)2746 ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) /* {{{ */
2747 {
2748 size_t length = ZSTR_LEN(str);
2749 unsigned char *p = (unsigned char *) ZSTR_VAL(str);
2750 unsigned char *end = p + length;
2751
2752 #ifdef __SSE2__
2753 while (p + 16 <= end) {
2754 const __m128i _A = _mm_set1_epi8('A' - 1);
2755 const __m128i Z_ = _mm_set1_epi8('Z' + 1);
2756 __m128i op = _mm_loadu_si128((__m128i*)p);
2757 __m128i gt = _mm_cmpgt_epi8(op, _A);
2758 __m128i lt = _mm_cmplt_epi8(op, Z_);
2759 __m128i mingle = _mm_and_si128(gt, lt);
2760 if (_mm_movemask_epi8(mingle)) {
2761 zend_string *res = zend_string_alloc(length, persistent);
2762 memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
2763 unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
2764
2765 /* Lowercase the chunk we already compared. */
2766 const __m128i delta = _mm_set1_epi8('a' - 'A');
2767 __m128i add = _mm_and_si128(mingle, delta);
2768 __m128i lower = _mm_add_epi8(op, add);
2769 _mm_storeu_si128((__m128i *) q, lower);
2770
2771 /* Lowercase the rest of the string. */
2772 p += 16; q += 16;
2773 zend_str_tolower_impl((char *) q, (const char *) p, end - p);
2774 ZSTR_VAL(res)[length] = '\0';
2775 return res;
2776 }
2777 p += 16;
2778 }
2779 #endif
2780
2781 while (p < end) {
2782 if (*p != zend_tolower_ascii(*p)) {
2783 zend_string *res = zend_string_alloc(length, persistent);
2784 memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
2785
2786 unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
2787 while (p < end) {
2788 *q++ = zend_tolower_ascii(*p++);
2789 }
2790 ZSTR_VAL(res)[length] = '\0';
2791 return res;
2792 }
2793 p++;
2794 }
2795
2796 return zend_string_copy(str);
2797 }
2798 /* }}} */
2799
zend_binary_strcmp(const char * s1,size_t len1,const char * s2,size_t len2)2800 ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2801 {
2802 int retval;
2803
2804 if (s1 == s2) {
2805 return 0;
2806 }
2807 retval = memcmp(s1, s2, MIN(len1, len2));
2808 if (!retval) {
2809 return (int)(len1 - len2);
2810 } else {
2811 return retval;
2812 }
2813 }
2814 /* }}} */
2815
zend_binary_strncmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)2816 ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2817 {
2818 int retval;
2819
2820 if (s1 == s2) {
2821 return 0;
2822 }
2823 retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2824 if (!retval) {
2825 return (int)(MIN(length, len1) - MIN(length, len2));
2826 } else {
2827 return retval;
2828 }
2829 }
2830 /* }}} */
2831
zend_binary_strcasecmp(const char * s1,size_t len1,const char * s2,size_t len2)2832 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2833 {
2834 size_t len;
2835 int c1, c2;
2836
2837 if (s1 == s2) {
2838 return 0;
2839 }
2840
2841 len = MIN(len1, len2);
2842 while (len--) {
2843 c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2844 c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2845 if (c1 != c2) {
2846 return c1 - c2;
2847 }
2848 }
2849
2850 return (int)(len1 - len2);
2851 }
2852 /* }}} */
2853
zend_binary_strncasecmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)2854 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2855 {
2856 size_t len;
2857 int c1, c2;
2858
2859 if (s1 == s2) {
2860 return 0;
2861 }
2862 len = MIN(length, MIN(len1, len2));
2863 while (len--) {
2864 c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2865 c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2866 if (c1 != c2) {
2867 return c1 - c2;
2868 }
2869 }
2870
2871 return (int)(MIN(length, len1) - MIN(length, len2));
2872 }
2873 /* }}} */
2874
zend_binary_strcasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2)2875 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2876 {
2877 size_t len;
2878 int c1, c2;
2879
2880 if (s1 == s2) {
2881 return 0;
2882 }
2883
2884 len = MIN(len1, len2);
2885 while (len--) {
2886 c1 = zend_tolower((int)*(unsigned char *)s1++);
2887 c2 = zend_tolower((int)*(unsigned char *)s2++);
2888 if (c1 != c2) {
2889 return c1 - c2;
2890 }
2891 }
2892
2893 return (int)(len1 - len2);
2894 }
2895 /* }}} */
2896
zend_binary_strncasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)2897 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2898 {
2899 size_t len;
2900 int c1, c2;
2901
2902 if (s1 == s2) {
2903 return 0;
2904 }
2905 len = MIN(length, MIN(len1, len2));
2906 while (len--) {
2907 c1 = zend_tolower((int)*(unsigned char *)s1++);
2908 c2 = zend_tolower((int)*(unsigned char *)s2++);
2909 if (c1 != c2) {
2910 return c1 - c2;
2911 }
2912 }
2913
2914 return (int)(MIN(length, len1) - MIN(length, len2));
2915 }
2916 /* }}} */
2917
zend_binary_zval_strcmp(zval * s1,zval * s2)2918 ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2919 {
2920 return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2921 }
2922 /* }}} */
2923
zend_binary_zval_strncmp(zval * s1,zval * s2,zval * s3)2924 ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2925 {
2926 return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2927 }
2928 /* }}} */
2929
zend_binary_zval_strcasecmp(zval * s1,zval * s2)2930 ZEND_API int ZEND_FASTCALL zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2931 {
2932 return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2933 }
2934 /* }}} */
2935
zend_binary_zval_strncasecmp(zval * s1,zval * s2,zval * s3)2936 ZEND_API int ZEND_FASTCALL zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2937 {
2938 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));
2939 }
2940 /* }}} */
2941
zendi_smart_streq(zend_string * s1,zend_string * s2)2942 ZEND_API bool ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2) /* {{{ */
2943 {
2944 zend_uchar ret1, ret2;
2945 int oflow1, oflow2;
2946 zend_long lval1 = 0, lval2 = 0;
2947 double dval1 = 0.0, dval2 = 0.0;
2948
2949 if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
2950 (ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
2951 #if ZEND_ULONG_MAX == 0xFFFFFFFF
2952 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2953 ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2954 || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2955 #else
2956 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2957 #endif
2958 /* both values are integers overflown to the same side, and the
2959 * double comparison may have resulted in crucial accuracy lost */
2960 goto string_cmp;
2961 }
2962 if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
2963 if (ret1 != IS_DOUBLE) {
2964 if (oflow2) {
2965 /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2966 return 0;
2967 }
2968 dval1 = (double) lval1;
2969 } else if (ret2 != IS_DOUBLE) {
2970 if (oflow1) {
2971 return 0;
2972 }
2973 dval2 = (double) lval2;
2974 } else if (dval1 == dval2 && !zend_finite(dval1)) {
2975 /* Both values overflowed and have the same sign,
2976 * so a numeric comparison would be inaccurate */
2977 goto string_cmp;
2978 }
2979 return dval1 == dval2;
2980 } else { /* they both have to be long's */
2981 return lval1 == lval2;
2982 }
2983 } else {
2984 string_cmp:
2985 return zend_string_equal_content(s1, s2);
2986 }
2987 }
2988 /* }}} */
2989
2990 ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2) /* {{{ */
2991 {
2992 zend_uchar ret1, ret2;
2993 int oflow1, oflow2;
2994 zend_long lval1 = 0, lval2 = 0;
2995 double dval1 = 0.0, dval2 = 0.0;
2996
2997 if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
2998 (ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
2999 #if ZEND_ULONG_MAX == 0xFFFFFFFF
3000 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
3001 ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
3002 || (oflow1 == -1 && dval1 < -9007199254740991.))) {
3003 #else
3004 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
3005 #endif
3006 /* both values are integers overflowed to the same side, and the
3007 * double comparison may have resulted in crucial accuracy lost */
3008 goto string_cmp;
3009 }
3010 if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
3011 if (ret1 != IS_DOUBLE) {
3012 if (oflow2) {
3013 /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
3014 return -1 * oflow2;
3015 }
3016 dval1 = (double) lval1;
3017 } else if (ret2 != IS_DOUBLE) {
3018 if (oflow1) {
3019 return oflow1;
3020 }
3021 dval2 = (double) lval2;
3022 } else if (dval1 == dval2 && !zend_finite(dval1)) {
3023 /* Both values overflowed and have the same sign,
3024 * so a numeric comparison would be inaccurate */
3025 goto string_cmp;
3026 }
3027 dval1 = dval1 - dval2;
3028 return ZEND_NORMALIZE_BOOL(dval1);
3029 } else { /* they both have to be long's */
3030 return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
3031 }
3032 } else {
3033 int strcmp_ret;
3034 string_cmp:
3035 strcmp_ret = zend_binary_strcmp(s1->val, s1->len, s2->val, s2->len);
3036 return ZEND_NORMALIZE_BOOL(strcmp_ret);
3037 }
3038 }
3039 /* }}} */
3040
3041 static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */
3042 {
3043 return zend_compare(z1, z2);
3044 }
3045 /* }}} */
3046
3047 ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */
3048 {
3049 return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
3050 }
3051 /* }}} */
3052
3053 ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */
3054 {
3055 return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2));
3056 }
3057 /* }}} */
3058
3059 ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */
3060 {
3061 if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
3062 return 0;
3063 }
3064
3065 if (Z_OBJ_HT_P(o1)->compare == NULL) {
3066 return 1;
3067 } else {
3068 return Z_OBJ_HT_P(o1)->compare(o1, o2);
3069 }
3070 }
3071 /* }}} */
3072
3073 ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */
3074 {
3075 if ((zend_ulong)num <= 9) {
3076 return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3077 } else {
3078 char buf[MAX_LENGTH_OF_LONG + 1];
3079 char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
3080 return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3081 }
3082 }
3083 /* }}} */
3084
3085 ZEND_API zend_string* ZEND_FASTCALL zend_ulong_to_str(zend_ulong num)
3086 {
3087 if (num <= 9) {
3088 return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3089 } else {
3090 char buf[MAX_LENGTH_OF_LONG + 1];
3091 char *res = zend_print_ulong_to_buf(buf + sizeof(buf) - 1, num);
3092 return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3093 }
3094 }
3095
3096 /* buf points to the END of the buffer */
3097 static zend_always_inline char *zend_print_u64_to_buf(char *buf, uint64_t num64) {
3098 #if SIZEOF_ZEND_LONG == 8
3099 return zend_print_ulong_to_buf(buf, num64);
3100 #else
3101 *buf = '\0';
3102 while (num64 > ZEND_ULONG_MAX) {
3103 *--buf = (char) (num64 % 10) + '0';
3104 num64 /= 10;
3105 }
3106
3107 zend_ulong num = (zend_ulong) num64;
3108 do {
3109 *--buf = (char) (num % 10) + '0';
3110 num /= 10;
3111 } while (num > 0);
3112 return buf;
3113 #endif
3114 }
3115
3116 /* buf points to the END of the buffer */
3117 static zend_always_inline char *zend_print_i64_to_buf(char *buf, int64_t num) {
3118 if (num < 0) {
3119 char *result = zend_print_u64_to_buf(buf, ~((uint64_t) num) + 1);
3120 *--result = '-';
3121 return result;
3122 } else {
3123 return zend_print_u64_to_buf(buf, num);
3124 }
3125 }
3126
3127 ZEND_API zend_string* ZEND_FASTCALL zend_u64_to_str(uint64_t num)
3128 {
3129 if (num <= 9) {
3130 return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3131 } else {
3132 char buf[20 + 1];
3133 char *res = zend_print_u64_to_buf(buf + sizeof(buf) - 1, num);
3134 return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3135 }
3136 }
3137
3138 ZEND_API zend_string* ZEND_FASTCALL zend_i64_to_str(int64_t num)
3139 {
3140 if ((uint64_t)num <= 9) {
3141 return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3142 } else {
3143 char buf[20 + 1];
3144 char *res = zend_print_i64_to_buf(buf + sizeof(buf) - 1, num);
3145 return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3146 }
3147 }
3148
3149 ZEND_API zend_string* ZEND_FASTCALL zend_double_to_str(double num)
3150 {
3151 char buf[ZEND_DOUBLE_MAX_LENGTH];
3152 /* Model snprintf precision behavior. */
3153 int precision = (int) EG(precision);
3154 zend_gcvt(num, precision ? precision : 1, '.', 'E', buf);
3155 return zend_string_init(buf, strlen(buf), 0);
3156 }
3157
3158 ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */
3159 {
3160 return is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), lval, dval, false);
3161 }
3162 /* }}} */
3163
3164 ZEND_API zend_uchar ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval,
3165 double *dval, bool allow_errors, int *oflow_info, bool *trailing_data) /* {{{ */
3166 {
3167 const char *ptr;
3168 int digits = 0, dp_or_e = 0;
3169 double local_dval = 0.0;
3170 zend_uchar type;
3171 zend_ulong tmp_lval = 0;
3172 int neg = 0;
3173
3174 if (!length) {
3175 return 0;
3176 }
3177
3178 if (oflow_info != NULL) {
3179 *oflow_info = 0;
3180 }
3181 if (trailing_data != NULL) {
3182 *trailing_data = false;
3183 }
3184
3185 /* Skip any whitespace
3186 * This is much faster than the isspace() function */
3187 while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
3188 str++;
3189 length--;
3190 }
3191 ptr = str;
3192
3193 if (*ptr == '-') {
3194 neg = 1;
3195 ptr++;
3196 } else if (*ptr == '+') {
3197 ptr++;
3198 }
3199
3200 if (ZEND_IS_DIGIT(*ptr)) {
3201 /* Skip any leading 0s */
3202 while (*ptr == '0') {
3203 ptr++;
3204 }
3205
3206 /* Count the number of digits. If a decimal point/exponent is found,
3207 * it's a double. Otherwise, if there's a dval or no need to check for
3208 * a full match, stop when there are too many digits for a long */
3209 for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors)); digits++, ptr++) {
3210 check_digits:
3211 if (ZEND_IS_DIGIT(*ptr)) {
3212 tmp_lval = tmp_lval * 10 + (*ptr) - '0';
3213 continue;
3214 } else if (*ptr == '.' && dp_or_e < 1) {
3215 goto process_double;
3216 } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
3217 const char *e = ptr + 1;
3218
3219 if (*e == '-' || *e == '+') {
3220 ptr = e++;
3221 }
3222 if (ZEND_IS_DIGIT(*e)) {
3223 goto process_double;
3224 }
3225 }
3226
3227 break;
3228 }
3229
3230 if (digits >= MAX_LENGTH_OF_LONG) {
3231 if (oflow_info != NULL) {
3232 *oflow_info = *str == '-' ? -1 : 1;
3233 }
3234 dp_or_e = -1;
3235 goto process_double;
3236 }
3237 } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
3238 process_double:
3239 type = IS_DOUBLE;
3240
3241 /* If there's a dval, do the conversion; else continue checking
3242 * the digits if we need to check for a full match */
3243 if (dval) {
3244 local_dval = zend_strtod(str, &ptr);
3245 } else if (!allow_errors && dp_or_e != -1) {
3246 dp_or_e = (*ptr++ == '.') ? 1 : 2;
3247 goto check_digits;
3248 }
3249 } else {
3250 return 0;
3251 }
3252
3253 if (ptr != str + length) {
3254 const char *endptr = ptr;
3255 while (*endptr == ' ' || *endptr == '\t' || *endptr == '\n' || *endptr == '\r' || *endptr == '\v' || *endptr == '\f') {
3256 endptr++;
3257 length--;
3258 }
3259 if (ptr != str + length) {
3260 if (!allow_errors) {
3261 return 0;
3262 }
3263 if (trailing_data != NULL) {
3264 *trailing_data = true;
3265 }
3266 }
3267 }
3268
3269 if (type == IS_LONG) {
3270 if (digits == MAX_LENGTH_OF_LONG - 1) {
3271 int cmp = strcmp(&ptr[-digits], long_min_digits);
3272
3273 if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
3274 if (dval) {
3275 *dval = zend_strtod(str, NULL);
3276 }
3277 if (oflow_info != NULL) {
3278 *oflow_info = *str == '-' ? -1 : 1;
3279 }
3280
3281 return IS_DOUBLE;
3282 }
3283 }
3284
3285 if (lval) {
3286 if (neg) {
3287 tmp_lval = -tmp_lval;
3288 }
3289 *lval = (zend_long) tmp_lval;
3290 }
3291
3292 return IS_LONG;
3293 } else {
3294 if (dval) {
3295 *dval = local_dval;
3296 }
3297
3298 return IS_DOUBLE;
3299 }
3300 }
3301 /* }}} */
3302
3303 /*
3304 * String matching - Sunday algorithm
3305 * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
3306 */
3307 static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
3308 int i;
3309
3310 for (i = 0; i < 256; i++) {
3311 td[i] = needle_len + 1;
3312 }
3313
3314 if (reverse) {
3315 for (i = needle_len - 1; i >= 0; i--) {
3316 td[(unsigned char)needle[i]] = i + 1;
3317 }
3318 } else {
3319 size_t i;
3320
3321 for (i = 0; i < needle_len; i++) {
3322 td[(unsigned char)needle[i]] = (int)needle_len - i;
3323 }
3324 }
3325 }
3326 /* }}} */
3327
3328 ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3329 {
3330 unsigned int td[256];
3331 size_t i;
3332 const char *p;
3333
3334 if (needle_len == 0 || (end - haystack) < needle_len) {
3335 return NULL;
3336 }
3337
3338 zend_memnstr_ex_pre(td, needle, needle_len, 0);
3339
3340 p = haystack;
3341 end -= needle_len;
3342
3343 while (p <= end) {
3344 for (i = 0; i < needle_len; i++) {
3345 if (needle[i] != p[i]) {
3346 break;
3347 }
3348 }
3349 if (i == needle_len) {
3350 return p;
3351 }
3352 if (UNEXPECTED(p == end)) {
3353 return NULL;
3354 }
3355 p += td[(unsigned char)(p[needle_len])];
3356 }
3357
3358 return NULL;
3359 }
3360 /* }}} */
3361
3362 ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3363 {
3364 unsigned int td[256];
3365 size_t i;
3366 const char *p;
3367
3368 if (needle_len == 0 || (end - haystack) < needle_len) {
3369 return NULL;
3370 }
3371
3372 zend_memnstr_ex_pre(td, needle, needle_len, 1);
3373
3374 p = end;
3375 p -= needle_len;
3376
3377 while (p >= haystack) {
3378 for (i = 0; i < needle_len; i++) {
3379 if (needle[i] != p[i]) {
3380 break;
3381 }
3382 }
3383
3384 if (i == needle_len) {
3385 return (const char *)p;
3386 }
3387
3388 if (UNEXPECTED(p == haystack)) {
3389 return NULL;
3390 }
3391
3392 p -= td[(unsigned char)(p[-1])];
3393 }
3394
3395 return NULL;
3396 }
3397 /* }}} */
3398
3399 #if SIZEOF_ZEND_LONG == 4
3400 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d) /* {{{ */
3401 {
3402 double two_pow_32 = pow(2., 32.),
3403 dmod;
3404
3405 dmod = fmod(d, two_pow_32);
3406 if (dmod < 0) {
3407 /* we're going to make this number positive; call ceil()
3408 * to simulate rounding towards 0 of the negative number */
3409 dmod = ceil(dmod) + two_pow_32;
3410 }
3411 return (zend_long)(zend_ulong)dmod;
3412 }
3413 #else
3414 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
3415 {
3416 double two_pow_64 = pow(2., 64.),
3417 dmod;
3418
3419 dmod = fmod(d, two_pow_64);
3420 if (dmod < 0) {
3421 /* no need to call ceil; original double must have had no
3422 * fractional part, hence dmod does not have one either */
3423 dmod += two_pow_64;
3424 }
3425 return (zend_long)(zend_ulong)dmod;
3426 }
3427 /* }}} */
3428 #endif
3429