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