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