1 /*
2 +----------------------------------------------------------------------+
3 | Zend Engine |
4 +----------------------------------------------------------------------+
5 | Copyright (c) Zend Technologies Ltd. (http://www.zend.com) |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 2.00 of the Zend license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.zend.com/license/2_00.txt. |
11 | If you did not receive a copy of the Zend license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@zend.com so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Authors: Andi Gutmans <andi@php.net> |
16 | Zeev Suraski <zeev@php.net> |
17 | Dmitry Stogov <dmitry@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 #include <ctype.h>
22
23 #include "zend.h"
24 #include "zend_operators.h"
25 #include "zend_variables.h"
26 #include "zend_globals.h"
27 #include "zend_list.h"
28 #include "zend_API.h"
29 #include "zend_strtod.h"
30 #include "zend_exceptions.h"
31 #include "zend_closures.h"
32
33 #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_INTERNED_STR(op, ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED));
572 break;
573 case IS_OBJECT: {
574 zval tmp;
575
576 if (Z_OBJ_HT_P(op)->cast_object) {
577 if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) {
578 zval_ptr_dtor(op);
579 ZVAL_COPY_VALUE(op, &tmp);
580 return;
581 }
582 } else if (Z_OBJ_HT_P(op)->get) {
583 zval *z = Z_OBJ_HT_P(op)->get(op, &tmp);
584 if (Z_TYPE_P(z) != IS_OBJECT) {
585 zend_string *str = zval_get_string(z);
586 zval_ptr_dtor(z);
587 zval_ptr_dtor(op);
588 ZVAL_STR(op, str);
589 return;
590 }
591 zval_ptr_dtor(z);
592 }
593 if (!EG(exception)) {
594 zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
595 }
596 zval_ptr_dtor(op);
597 ZVAL_EMPTY_STRING(op);
598 break;
599 }
600 case IS_REFERENCE:
601 zend_unwrap_reference(op);
602 goto try_again;
603 EMPTY_SWITCH_DEFAULT_CASE()
604 }
605 }
606 /* }}} */
607
_try_convert_to_string(zval * op)608 ZEND_API zend_bool ZEND_FASTCALL _try_convert_to_string(zval *op)
609 {
610 zend_string *str;
611
612 ZEND_ASSERT(Z_TYPE_P(op) != IS_STRING);
613 str = zval_try_get_string_func(op);
614 if (UNEXPECTED(!str)) {
615 return 0;
616 }
617 zval_ptr_dtor(op);
618 ZVAL_STR(op, str);
619 return 1;
620 }
621
convert_scalar_to_array(zval * op)622 static void convert_scalar_to_array(zval *op) /* {{{ */
623 {
624 HashTable *ht = zend_new_array(1);
625 zend_hash_index_add_new(ht, 0, op);
626 ZVAL_ARR(op, ht);
627 }
628 /* }}} */
629
convert_to_array(zval * op)630 ZEND_API void ZEND_FASTCALL convert_to_array(zval *op) /* {{{ */
631 {
632 try_again:
633 switch (Z_TYPE_P(op)) {
634 case IS_ARRAY:
635 break;
636 /* OBJECTS_OPTIMIZE */
637 case IS_OBJECT:
638 if (Z_OBJCE_P(op) == zend_ce_closure) {
639 convert_scalar_to_array(op);
640 } else {
641 HashTable *obj_ht = zend_get_properties_for(op, ZEND_PROP_PURPOSE_ARRAY_CAST);
642 if (obj_ht) {
643 HashTable *new_obj_ht = zend_proptable_to_symtable(obj_ht,
644 (Z_OBJCE_P(op)->default_properties_count ||
645 Z_OBJ_P(op)->handlers != &std_object_handlers ||
646 GC_IS_RECURSIVE(obj_ht)));
647 zval_ptr_dtor(op);
648 ZVAL_ARR(op, new_obj_ht);
649 zend_release_properties(obj_ht);
650 } else {
651 zval_ptr_dtor(op);
652 /*ZVAL_EMPTY_ARRAY(op);*/
653 array_init(op);
654 }
655 }
656 break;
657 case IS_NULL:
658 /*ZVAL_EMPTY_ARRAY(op);*/
659 array_init(op);
660 break;
661 case IS_REFERENCE:
662 zend_unwrap_reference(op);
663 goto try_again;
664 default:
665 convert_scalar_to_array(op);
666 break;
667 }
668 }
669 /* }}} */
670
convert_to_object(zval * op)671 ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
672 {
673 try_again:
674 switch (Z_TYPE_P(op)) {
675 case IS_ARRAY:
676 {
677 HashTable *ht = zend_symtable_to_proptable(Z_ARR_P(op));
678 zend_object *obj;
679
680 if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) {
681 /* TODO: try not to duplicate immutable arrays as well ??? */
682 ht = zend_array_dup(ht);
683 } else if (ht != Z_ARR_P(op)) {
684 zval_ptr_dtor(op);
685 } else {
686 GC_DELREF(ht);
687 }
688 obj = zend_objects_new(zend_standard_class_def);
689 obj->properties = ht;
690 ZVAL_OBJ(op, obj);
691 break;
692 }
693 case IS_OBJECT:
694 break;
695 case IS_NULL:
696 object_init(op);
697 break;
698 case IS_REFERENCE:
699 zend_unwrap_reference(op);
700 goto try_again;
701 default: {
702 zval tmp;
703 ZVAL_COPY_VALUE(&tmp, op);
704 object_init(op);
705 zend_hash_add_new(Z_OBJPROP_P(op), ZSTR_KNOWN(ZEND_STR_SCALAR), &tmp);
706 break;
707 }
708 }
709 }
710 /* }}} */
711
multi_convert_to_long_ex(int argc,...)712 ZEND_API void multi_convert_to_long_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_long_ex(arg);
722 }
723
724 va_end(ap);
725 }
726 /* }}} */
727
multi_convert_to_double_ex(int argc,...)728 ZEND_API void multi_convert_to_double_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_double_ex(arg);
738 }
739
740 va_end(ap);
741 }
742 /* }}} */
743
multi_convert_to_string_ex(int argc,...)744 ZEND_API void multi_convert_to_string_ex(int argc, ...) /* {{{ */
745 {
746 zval *arg;
747 va_list ap;
748
749 va_start(ap, argc);
750
751 while (argc--) {
752 arg = va_arg(ap, zval *);
753 convert_to_string_ex(arg);
754 }
755
756 va_end(ap);
757 }
758 /* }}} */
759
_zval_get_long_func_ex(zval * op,zend_bool silent)760 static zend_always_inline zend_long ZEND_FASTCALL _zval_get_long_func_ex(zval *op, zend_bool silent) /* {{{ */
761 {
762 try_again:
763 switch (Z_TYPE_P(op)) {
764 case IS_UNDEF:
765 case IS_NULL:
766 case IS_FALSE:
767 return 0;
768 case IS_TRUE:
769 return 1;
770 case IS_RESOURCE:
771 return Z_RES_HANDLE_P(op);
772 case IS_LONG:
773 return Z_LVAL_P(op);
774 case IS_DOUBLE:
775 return zend_dval_to_lval(Z_DVAL_P(op));
776 case IS_STRING:
777 {
778 zend_uchar type;
779 zend_long lval;
780 double dval;
781 if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, silent ? 1 : -1))) {
782 if (!silent) {
783 zend_error(E_WARNING, "A non-numeric value encountered");
784 }
785 return 0;
786 } else if (EXPECTED(type == IS_LONG)) {
787 return lval;
788 } else {
789 /* Previously we used strtol here, not is_numeric_string,
790 * and strtol gives you LONG_MAX/_MIN on overflow.
791 * We use use saturating conversion to emulate strtol()'s
792 * behaviour.
793 */
794 return zend_dval_to_lval_cap(dval);
795 }
796 }
797 case IS_ARRAY:
798 return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
799 case IS_OBJECT:
800 {
801 zval dst;
802 convert_object_to_type(op, &dst, IS_LONG, convert_to_long);
803 if (Z_TYPE(dst) == IS_LONG) {
804 return Z_LVAL(dst);
805 } else {
806 return 1;
807 }
808 }
809 case IS_REFERENCE:
810 op = Z_REFVAL_P(op);
811 goto try_again;
812 EMPTY_SWITCH_DEFAULT_CASE()
813 }
814 return 0;
815 }
816 /* }}} */
817
zval_get_long_func(zval * op)818 ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(zval *op) /* {{{ */
819 {
820 return _zval_get_long_func_ex(op, 1);
821 }
822 /* }}} */
823
_zval_get_long_func_noisy(zval * op)824 static zend_long ZEND_FASTCALL _zval_get_long_func_noisy(zval *op) /* {{{ */
825 {
826 return _zval_get_long_func_ex(op, 0);
827 }
828 /* }}} */
829
zval_get_double_func(zval * op)830 ZEND_API double ZEND_FASTCALL zval_get_double_func(zval *op) /* {{{ */
831 {
832 try_again:
833 switch (Z_TYPE_P(op)) {
834 case IS_NULL:
835 case IS_FALSE:
836 return 0.0;
837 case IS_TRUE:
838 return 1.0;
839 case IS_RESOURCE:
840 return (double) Z_RES_HANDLE_P(op);
841 case IS_LONG:
842 return (double) Z_LVAL_P(op);
843 case IS_DOUBLE:
844 return Z_DVAL_P(op);
845 case IS_STRING:
846 return zend_strtod(Z_STRVAL_P(op), NULL);
847 case IS_ARRAY:
848 return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1.0 : 0.0;
849 case IS_OBJECT:
850 {
851 zval dst;
852 convert_object_to_type(op, &dst, IS_DOUBLE, convert_to_double);
853
854 if (Z_TYPE(dst) == IS_DOUBLE) {
855 return Z_DVAL(dst);
856 } else {
857 return 1.0;
858 }
859 }
860 case IS_REFERENCE:
861 op = Z_REFVAL_P(op);
862 goto try_again;
863 EMPTY_SWITCH_DEFAULT_CASE()
864 }
865 return 0.0;
866 }
867 /* }}} */
868
__zval_get_string_func(zval * op,zend_bool try)869 static zend_always_inline zend_string* __zval_get_string_func(zval *op, zend_bool try) /* {{{ */
870 {
871 try_again:
872 switch (Z_TYPE_P(op)) {
873 case IS_UNDEF:
874 case IS_NULL:
875 case IS_FALSE:
876 return ZSTR_EMPTY_ALLOC();
877 case IS_TRUE:
878 return ZSTR_CHAR('1');
879 case IS_RESOURCE: {
880 return zend_strpprintf(0, "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
881 }
882 case IS_LONG: {
883 return zend_long_to_str(Z_LVAL_P(op));
884 }
885 case IS_DOUBLE: {
886 return zend_strpprintf(0, "%.*G", (int) EG(precision), Z_DVAL_P(op));
887 }
888 case IS_ARRAY:
889 zend_error(E_NOTICE, "Array to string conversion");
890 return (try && UNEXPECTED(EG(exception))) ?
891 NULL : ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
892 case IS_OBJECT: {
893 zval tmp;
894 if (Z_OBJ_HT_P(op)->cast_object) {
895 if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, IS_STRING) == SUCCESS) {
896 return Z_STR(tmp);
897 }
898 } else if (Z_OBJ_HT_P(op)->get) {
899 zval *z = Z_OBJ_HT_P(op)->get(op, &tmp);
900 if (Z_TYPE_P(z) != IS_OBJECT) {
901 zend_string *str = try ? zval_try_get_string(z) : zval_get_string(z);
902 zval_ptr_dtor(z);
903 return str;
904 }
905 zval_ptr_dtor(z);
906 }
907 if (!EG(exception)) {
908 zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
909 }
910 return try ? NULL : ZSTR_EMPTY_ALLOC();
911 }
912 case IS_REFERENCE:
913 op = Z_REFVAL_P(op);
914 goto try_again;
915 case IS_STRING:
916 return zend_string_copy(Z_STR_P(op));
917 EMPTY_SWITCH_DEFAULT_CASE()
918 }
919 return NULL;
920 }
921 /* }}} */
922
zval_get_string_func(zval * op)923 ZEND_API zend_string* ZEND_FASTCALL zval_get_string_func(zval *op) /* {{{ */
924 {
925 return __zval_get_string_func(op, 0);
926 }
927 /* }}} */
928
zval_try_get_string_func(zval * op)929 ZEND_API zend_string* ZEND_FASTCALL zval_try_get_string_func(zval *op) /* {{{ */
930 {
931 return __zval_get_string_func(op, 1);
932 }
933 /* }}} */
934
add_function_array(zval * result,zval * op1,zval * op2)935 static zend_never_inline void ZEND_FASTCALL add_function_array(zval *result, zval *op1, zval *op2) /* {{{ */
936 {
937 if (result == op1 && Z_ARR_P(op1) == Z_ARR_P(op2)) {
938 /* $a += $a */
939 return;
940 }
941 if (result != op1) {
942 ZVAL_ARR(result, zend_array_dup(Z_ARR_P(op1)));
943 } else {
944 SEPARATE_ARRAY(result);
945 }
946 zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
947 }
948 /* }}} */
949
add_function_fast(zval * result,zval * op1,zval * op2)950 static zend_always_inline int add_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
951 {
952 zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
953
954 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
955 fast_long_add_function(result, op1, op2);
956 return SUCCESS;
957 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
958 ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
959 return SUCCESS;
960 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
961 ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
962 return SUCCESS;
963 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
964 ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
965 return SUCCESS;
966 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_ARRAY, IS_ARRAY))) {
967 add_function_array(result, op1, op2);
968 return SUCCESS;
969 } else {
970 return FAILURE;
971 }
972 } /* }}} */
973
add_function_slow(zval * result,zval * op1,zval * op2)974 static zend_never_inline int ZEND_FASTCALL add_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
975 {
976 zval op1_copy, op2_copy;
977 int converted = 0;
978
979 while (1) {
980 if (Z_ISREF_P(op1)) {
981 op1 = Z_REFVAL_P(op1);
982 } else if (Z_ISREF_P(op2)) {
983 op2 = Z_REFVAL_P(op2);
984 } else if (!converted) {
985 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD, add_function);
986
987 if (EXPECTED(op1 != op2)) {
988 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
989 op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
990 } else {
991 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
992 op2 = op1;
993 }
994 if (EG(exception)) {
995 if (result != op1) {
996 ZVAL_UNDEF(result);
997 }
998 return FAILURE;
999 }
1000 converted = 1;
1001 } else {
1002 if (result != op1) {
1003 ZVAL_UNDEF(result);
1004 }
1005 zend_throw_error(NULL, "Unsupported operand types");
1006 return FAILURE; /* unknown datatype */
1007 }
1008 if (add_function_fast(result, op1, op2) == SUCCESS) {
1009 return SUCCESS;
1010 }
1011 }
1012 } /* }}} */
1013
add_function(zval * result,zval * op1,zval * op2)1014 ZEND_API int ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
1015 {
1016 if (add_function_fast(result, op1, op2) == SUCCESS) {
1017 return SUCCESS;
1018 } else {
1019 return add_function_slow(result, op1, op2);
1020 }
1021 }
1022 /* }}} */
1023
sub_function_fast(zval * result,zval * op1,zval * op2)1024 static zend_always_inline int sub_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1025 {
1026 zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1027
1028 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1029 fast_long_sub_function(result, op1, op2);
1030 return SUCCESS;
1031 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1032 ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
1033 return SUCCESS;
1034 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1035 ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
1036 return SUCCESS;
1037 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1038 ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
1039 return SUCCESS;
1040 } else {
1041 return FAILURE;
1042 }
1043 }
1044 /* }}} */
1045
sub_function_slow(zval * result,zval * op1,zval * op2)1046 static zend_never_inline int ZEND_FASTCALL sub_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1047 {
1048 zval op1_copy, op2_copy;
1049 int converted = 0;
1050 while (1) {
1051 if (Z_ISREF_P(op1)) {
1052 op1 = Z_REFVAL_P(op1);
1053 } else if (Z_ISREF_P(op2)) {
1054 op2 = Z_REFVAL_P(op2);
1055 } else if (!converted) {
1056 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB, sub_function);
1057
1058 if (EXPECTED(op1 != op2)) {
1059 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
1060 op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
1061 } else {
1062 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
1063 op2 = op1;
1064 }
1065 if (EG(exception)) {
1066 if (result != op1) {
1067 ZVAL_UNDEF(result);
1068 }
1069 return FAILURE;
1070 }
1071 converted = 1;
1072 } else {
1073 if (result != op1) {
1074 ZVAL_UNDEF(result);
1075 }
1076 zend_throw_error(NULL, "Unsupported operand types");
1077 return FAILURE; /* unknown datatype */
1078 }
1079 if (sub_function_fast(result, op1, op2) == SUCCESS) {
1080 return SUCCESS;
1081 }
1082 }
1083
1084 }
1085 /* }}} */
1086
sub_function(zval * result,zval * op1,zval * op2)1087 ZEND_API int ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* {{{ */
1088 {
1089 if (sub_function_fast(result, op1, op2) == SUCCESS) {
1090 return SUCCESS;
1091 } else {
1092 return sub_function_slow(result, op1, op2);
1093 }
1094 }
1095 /* }}} */
1096
mul_function(zval * result,zval * op1,zval * op2)1097 ZEND_API int ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */
1098 {
1099 zval op1_copy, op2_copy;
1100 int converted = 0;
1101
1102 while (1) {
1103 zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1104
1105 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1106 zend_long overflow;
1107
1108 ZEND_SIGNED_MULTIPLY_LONG(Z_LVAL_P(op1),Z_LVAL_P(op2), Z_LVAL_P(result),Z_DVAL_P(result),overflow);
1109 Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
1110 return SUCCESS;
1111
1112 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1113 ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
1114 return SUCCESS;
1115
1116 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1117 ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
1118 return SUCCESS;
1119
1120 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1121 ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
1122 return SUCCESS;
1123
1124 } else {
1125 if (Z_ISREF_P(op1)) {
1126 op1 = Z_REFVAL_P(op1);
1127 } else if (Z_ISREF_P(op2)) {
1128 op2 = Z_REFVAL_P(op2);
1129 } else if (!converted) {
1130 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL, mul_function);
1131
1132 if (EXPECTED(op1 != op2)) {
1133 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
1134 op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
1135 } else {
1136 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
1137 op2 = op1;
1138 }
1139 if (EG(exception)) {
1140 if (result != op1) {
1141 ZVAL_UNDEF(result);
1142 }
1143 return FAILURE;
1144 }
1145 converted = 1;
1146 } else {
1147 if (result != op1) {
1148 ZVAL_UNDEF(result);
1149 }
1150 zend_throw_error(NULL, "Unsupported operand types");
1151 return FAILURE; /* unknown datatype */
1152 }
1153 }
1154 }
1155 }
1156 /* }}} */
1157
pow_function(zval * result,zval * op1,zval * op2)1158 ZEND_API int ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */
1159 {
1160 zval op1_copy, op2_copy;
1161 int converted = 0;
1162
1163 while (1) {
1164 zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1165
1166 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1167 if (Z_LVAL_P(op2) >= 0) {
1168 zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
1169
1170 if (i == 0) {
1171 ZVAL_LONG(result, 1L);
1172 return SUCCESS;
1173 } else if (l2 == 0) {
1174 ZVAL_LONG(result, 0);
1175 return SUCCESS;
1176 }
1177
1178 while (i >= 1) {
1179 zend_long overflow;
1180 double dval = 0.0;
1181
1182 if (i % 2) {
1183 --i;
1184 ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
1185 if (overflow) {
1186 ZVAL_DOUBLE(result, dval * pow(l2, i));
1187 return SUCCESS;
1188 }
1189 } else {
1190 i /= 2;
1191 ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
1192 if (overflow) {
1193 ZVAL_DOUBLE(result, (double)l1 * pow(dval, i));
1194 return SUCCESS;
1195 }
1196 }
1197 }
1198 /* i == 0 */
1199 ZVAL_LONG(result, l1);
1200 } else {
1201 ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
1202 }
1203 return SUCCESS;
1204
1205 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1206 ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
1207 return SUCCESS;
1208
1209 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1210 ZVAL_DOUBLE(result, pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
1211 return SUCCESS;
1212
1213 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1214 ZVAL_DOUBLE(result, pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
1215 return SUCCESS;
1216
1217 } else {
1218 if (Z_ISREF_P(op1)) {
1219 op1 = Z_REFVAL_P(op1);
1220 } else if (Z_ISREF_P(op2)) {
1221 op2 = Z_REFVAL_P(op2);
1222 } else if (!converted) {
1223 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW, pow_function);
1224
1225 if (EXPECTED(op1 != op2)) {
1226 if (Z_TYPE_P(op1) == IS_ARRAY) {
1227 if (op1 == result) {
1228 zval_ptr_dtor(result);
1229 }
1230 ZVAL_LONG(result, 0);
1231 return SUCCESS;
1232 } else {
1233 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
1234 }
1235 if (Z_TYPE_P(op2) == IS_ARRAY) {
1236 if (op1 == result) {
1237 zval_ptr_dtor(result);
1238 }
1239 ZVAL_LONG(result, 1L);
1240 return SUCCESS;
1241 } else {
1242 op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
1243 }
1244 } else {
1245 if (Z_TYPE_P(op1) == IS_ARRAY) {
1246 if (op1 == result) {
1247 zval_ptr_dtor(result);
1248 }
1249 ZVAL_LONG(result, 0);
1250 return SUCCESS;
1251 } else {
1252 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
1253 }
1254 op2 = op1;
1255 }
1256 if (EG(exception)) {
1257 if (result != op1) {
1258 ZVAL_UNDEF(result);
1259 }
1260 return FAILURE;
1261 }
1262 converted = 1;
1263 } else {
1264 if (result != op1) {
1265 ZVAL_UNDEF(result);
1266 }
1267 zend_throw_error(NULL, "Unsupported operand types");
1268 return FAILURE;
1269 }
1270 }
1271 }
1272 }
1273 /* }}} */
1274
1275 #ifdef __clang__
1276 __attribute__((no_sanitize("float-divide-by-zero")))
1277 #endif
div_function(zval * result,zval * op1,zval * op2)1278 ZEND_API int ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */
1279 {
1280 zval op1_copy, op2_copy;
1281 int converted = 0;
1282
1283 while (1) {
1284 zend_uchar type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1285
1286 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1287 if (Z_LVAL_P(op2) == 0) {
1288 zend_error(E_WARNING, "Division by zero");
1289 ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1) / (double) Z_LVAL_P(op2)));
1290 return SUCCESS;
1291 } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
1292 /* Prevent overflow error/crash */
1293 ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
1294 return SUCCESS;
1295 }
1296 if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
1297 ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
1298 } else {
1299 ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
1300 }
1301 return SUCCESS;
1302
1303 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1304 if (Z_DVAL_P(op2) == 0) {
1305 zend_error(E_WARNING, "Division by zero");
1306 }
1307 ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1308 return SUCCESS;
1309
1310 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1311 if (Z_LVAL_P(op2) == 0) {
1312 zend_error(E_WARNING, "Division by zero");
1313 }
1314 ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1315 return SUCCESS;
1316
1317 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1318 if (Z_DVAL_P(op2) == 0) {
1319 zend_error(E_WARNING, "Division by zero");
1320 }
1321 ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1322 return SUCCESS;
1323
1324 } else {
1325 if (Z_ISREF_P(op1)) {
1326 op1 = Z_REFVAL_P(op1);
1327 } else if (Z_ISREF_P(op2)) {
1328 op2 = Z_REFVAL_P(op2);
1329 } else if (!converted) {
1330 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV, div_function);
1331
1332 if (EXPECTED(op1 != op2)) {
1333 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
1334 op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 0);
1335 } else {
1336 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 0);
1337 op2 = op1;
1338 }
1339 if (EG(exception)) {
1340 if (result != op1) {
1341 ZVAL_UNDEF(result);
1342 }
1343 return FAILURE;
1344 }
1345 converted = 1;
1346 } else {
1347 if (result != op1) {
1348 ZVAL_UNDEF(result);
1349 }
1350 zend_throw_error(NULL, "Unsupported operand types");
1351 return FAILURE; /* unknown datatype */
1352 }
1353 }
1354 }
1355 }
1356 /* }}} */
1357
mod_function(zval * result,zval * op1,zval * op2)1358 ZEND_API int ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* {{{ */
1359 {
1360 zend_long op1_lval, op2_lval;
1361
1362 convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_MOD, mod_function);
1363
1364 if (op2_lval == 0) {
1365 /* modulus by zero */
1366 if (EG(current_execute_data) && !CG(in_compilation)) {
1367 zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
1368 } else {
1369 zend_error_noreturn(E_ERROR, "Modulo by zero");
1370 }
1371 if (op1 != result) {
1372 ZVAL_UNDEF(result);
1373 }
1374 return FAILURE;
1375 }
1376
1377 if (op1 == result) {
1378 zval_ptr_dtor(result);
1379 }
1380
1381 if (op2_lval == -1) {
1382 /* Prevent overflow error/crash if op1==LONG_MIN */
1383 ZVAL_LONG(result, 0);
1384 return SUCCESS;
1385 }
1386
1387 ZVAL_LONG(result, op1_lval % op2_lval);
1388 return SUCCESS;
1389 }
1390 /* }}} */
1391
boolean_xor_function(zval * result,zval * op1,zval * op2)1392 ZEND_API int ZEND_FASTCALL boolean_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1393 {
1394 int op1_val, op2_val;
1395
1396 do {
1397 if (Z_TYPE_P(op1) == IS_FALSE) {
1398 op1_val = 0;
1399 } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1400 op1_val = 1;
1401 } else {
1402 if (Z_ISREF_P(op1)) {
1403 op1 = Z_REFVAL_P(op1);
1404 if (Z_TYPE_P(op1) == IS_FALSE) {
1405 op1_val = 0;
1406 break;
1407 } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1408 op1_val = 1;
1409 break;
1410 }
1411 }
1412 ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BOOL_XOR, boolean_xor_function);
1413 op1_val = zval_is_true(op1);
1414 }
1415 } while (0);
1416 do {
1417 if (Z_TYPE_P(op2) == IS_FALSE) {
1418 op2_val = 0;
1419 } else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1420 op2_val = 1;
1421 } else {
1422 if (Z_ISREF_P(op2)) {
1423 op2 = Z_REFVAL_P(op2);
1424 if (Z_TYPE_P(op2) == IS_FALSE) {
1425 op2_val = 0;
1426 break;
1427 } else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1428 op2_val = 1;
1429 break;
1430 }
1431 }
1432 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BOOL_XOR);
1433 op2_val = zval_is_true(op2);
1434 }
1435 } while (0);
1436
1437 ZVAL_BOOL(result, op1_val ^ op2_val);
1438 return SUCCESS;
1439 }
1440 /* }}} */
1441
boolean_not_function(zval * result,zval * op1)1442 ZEND_API int ZEND_FASTCALL boolean_not_function(zval *result, zval *op1) /* {{{ */
1443 {
1444 if (Z_TYPE_P(op1) < IS_TRUE) {
1445 ZVAL_TRUE(result);
1446 } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1447 ZVAL_FALSE(result);
1448 } else {
1449 if (Z_ISREF_P(op1)) {
1450 op1 = Z_REFVAL_P(op1);
1451 if (Z_TYPE_P(op1) < IS_TRUE) {
1452 ZVAL_TRUE(result);
1453 return SUCCESS;
1454 } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1455 ZVAL_FALSE(result);
1456 return SUCCESS;
1457 }
1458 }
1459 ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1460
1461 ZVAL_BOOL(result, !zval_is_true(op1));
1462 }
1463 return SUCCESS;
1464 }
1465 /* }}} */
1466
bitwise_not_function(zval * result,zval * op1)1467 ZEND_API int ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{ */
1468 {
1469 try_again:
1470 switch (Z_TYPE_P(op1)) {
1471 case IS_LONG:
1472 ZVAL_LONG(result, ~Z_LVAL_P(op1));
1473 return SUCCESS;
1474 case IS_DOUBLE:
1475 ZVAL_LONG(result, ~zend_dval_to_lval(Z_DVAL_P(op1)));
1476 return SUCCESS;
1477 case IS_STRING: {
1478 size_t i;
1479
1480 if (Z_STRLEN_P(op1) == 1) {
1481 zend_uchar not = (zend_uchar) ~*Z_STRVAL_P(op1);
1482 ZVAL_INTERNED_STR(result, ZSTR_CHAR(not));
1483 } else {
1484 ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
1485 for (i = 0; i < Z_STRLEN_P(op1); i++) {
1486 Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1487 }
1488 Z_STRVAL_P(result)[i] = 0;
1489 }
1490 return SUCCESS;
1491 }
1492 case IS_REFERENCE:
1493 op1 = Z_REFVAL_P(op1);
1494 goto try_again;
1495 default:
1496 ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1497
1498 if (result != op1) {
1499 ZVAL_UNDEF(result);
1500 }
1501 zend_throw_error(NULL, "Unsupported operand types");
1502 return FAILURE;
1503 }
1504 }
1505 /* }}} */
1506
bitwise_or_function(zval * result,zval * op1,zval * op2)1507 ZEND_API int ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2) /* {{{ */
1508 {
1509 zend_long op1_lval, op2_lval;
1510
1511 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1512 ZVAL_LONG(result, Z_LVAL_P(op1) | Z_LVAL_P(op2));
1513 return SUCCESS;
1514 }
1515
1516 ZVAL_DEREF(op1);
1517 ZVAL_DEREF(op2);
1518
1519 if (Z_TYPE_P(op1) == IS_STRING && EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1520 zval *longer, *shorter;
1521 zend_string *str;
1522 size_t i;
1523
1524 if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1525 if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1526 zend_uchar or = (zend_uchar) (*Z_STRVAL_P(op1) | *Z_STRVAL_P(op2));
1527 if (result==op1) {
1528 zval_ptr_dtor_str(result);
1529 }
1530 ZVAL_INTERNED_STR(result, ZSTR_CHAR(or));
1531 return SUCCESS;
1532 }
1533 longer = op1;
1534 shorter = op2;
1535 } else {
1536 longer = op2;
1537 shorter = op1;
1538 }
1539
1540 str = zend_string_alloc(Z_STRLEN_P(longer), 0);
1541 for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1542 ZSTR_VAL(str)[i] = Z_STRVAL_P(longer)[i] | Z_STRVAL_P(shorter)[i];
1543 }
1544 memcpy(ZSTR_VAL(str) + i, Z_STRVAL_P(longer) + i, Z_STRLEN_P(longer) - i + 1);
1545 if (result==op1) {
1546 zval_ptr_dtor_str(result);
1547 }
1548 ZVAL_NEW_STR(result, str);
1549 return SUCCESS;
1550 }
1551
1552 if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1553 ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR, bitwise_or_function);
1554 op1_lval = _zval_get_long_func_noisy(op1);
1555 if (UNEXPECTED(EG(exception))) {
1556 if (result != op1) {
1557 ZVAL_UNDEF(result);
1558 }
1559 return FAILURE;
1560 }
1561 } else {
1562 op1_lval = Z_LVAL_P(op1);
1563 }
1564 if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1565 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR);
1566 op2_lval = _zval_get_long_func_noisy(op2);
1567 if (UNEXPECTED(EG(exception))) {
1568 if (result != op1) {
1569 ZVAL_UNDEF(result);
1570 }
1571 return FAILURE;
1572 }
1573 } else {
1574 op2_lval = Z_LVAL_P(op2);
1575 }
1576
1577 if (op1 == result) {
1578 zval_ptr_dtor(result);
1579 }
1580 ZVAL_LONG(result, op1_lval | op2_lval);
1581 return SUCCESS;
1582 }
1583 /* }}} */
1584
bitwise_and_function(zval * result,zval * op1,zval * op2)1585 ZEND_API int ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2) /* {{{ */
1586 {
1587 zend_long op1_lval, op2_lval;
1588
1589 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1590 ZVAL_LONG(result, Z_LVAL_P(op1) & Z_LVAL_P(op2));
1591 return SUCCESS;
1592 }
1593
1594 ZVAL_DEREF(op1);
1595 ZVAL_DEREF(op2);
1596
1597 if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1598 zval *longer, *shorter;
1599 zend_string *str;
1600 size_t i;
1601
1602 if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1603 if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1604 zend_uchar and = (zend_uchar) (*Z_STRVAL_P(op1) & *Z_STRVAL_P(op2));
1605 if (result==op1) {
1606 zval_ptr_dtor_str(result);
1607 }
1608 ZVAL_INTERNED_STR(result, ZSTR_CHAR(and));
1609 return SUCCESS;
1610 }
1611 longer = op1;
1612 shorter = op2;
1613 } else {
1614 longer = op2;
1615 shorter = op1;
1616 }
1617
1618 str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1619 for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1620 ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] & Z_STRVAL_P(longer)[i];
1621 }
1622 ZSTR_VAL(str)[i] = 0;
1623 if (result==op1) {
1624 zval_ptr_dtor_str(result);
1625 }
1626 ZVAL_NEW_STR(result, str);
1627 return SUCCESS;
1628 }
1629
1630 if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1631 ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND, bitwise_and_function);
1632 op1_lval = _zval_get_long_func_noisy(op1);
1633 if (UNEXPECTED(EG(exception))) {
1634 if (result != op1) {
1635 ZVAL_UNDEF(result);
1636 }
1637 return FAILURE;
1638 }
1639 } else {
1640 op1_lval = Z_LVAL_P(op1);
1641 }
1642 if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1643 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND);
1644 op2_lval = _zval_get_long_func_noisy(op2);
1645 if (UNEXPECTED(EG(exception))) {
1646 if (result != op1) {
1647 ZVAL_UNDEF(result);
1648 }
1649 return FAILURE;
1650 }
1651 } else {
1652 op2_lval = Z_LVAL_P(op2);
1653 }
1654
1655 if (op1 == result) {
1656 zval_ptr_dtor(result);
1657 }
1658 ZVAL_LONG(result, op1_lval & op2_lval);
1659 return SUCCESS;
1660 }
1661 /* }}} */
1662
bitwise_xor_function(zval * result,zval * op1,zval * op2)1663 ZEND_API int ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1664 {
1665 zend_long op1_lval, op2_lval;
1666
1667 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1668 ZVAL_LONG(result, Z_LVAL_P(op1) ^ Z_LVAL_P(op2));
1669 return SUCCESS;
1670 }
1671
1672 ZVAL_DEREF(op1);
1673 ZVAL_DEREF(op2);
1674
1675 if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1676 zval *longer, *shorter;
1677 zend_string *str;
1678 size_t i;
1679
1680 if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1681 if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1682 zend_uchar xor = (zend_uchar) (*Z_STRVAL_P(op1) ^ *Z_STRVAL_P(op2));
1683 if (result==op1) {
1684 zval_ptr_dtor_str(result);
1685 }
1686 ZVAL_INTERNED_STR(result, ZSTR_CHAR(xor));
1687 return SUCCESS;
1688 }
1689 longer = op1;
1690 shorter = op2;
1691 } else {
1692 longer = op2;
1693 shorter = op1;
1694 }
1695
1696 str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1697 for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1698 ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] ^ Z_STRVAL_P(longer)[i];
1699 }
1700 ZSTR_VAL(str)[i] = 0;
1701 if (result==op1) {
1702 zval_ptr_dtor_str(result);
1703 }
1704 ZVAL_NEW_STR(result, str);
1705 return SUCCESS;
1706 }
1707
1708 if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1709 ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR, bitwise_xor_function);
1710 op1_lval = _zval_get_long_func_noisy(op1);
1711 if (UNEXPECTED(EG(exception))) {
1712 if (result != op1) {
1713 ZVAL_UNDEF(result);
1714 }
1715 return FAILURE;
1716 }
1717 } else {
1718 op1_lval = Z_LVAL_P(op1);
1719 }
1720 if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1721 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR);
1722 op2_lval = _zval_get_long_func_noisy(op2);
1723 if (UNEXPECTED(EG(exception))) {
1724 if (result != op1) {
1725 ZVAL_UNDEF(result);
1726 }
1727 return FAILURE;
1728 }
1729 } else {
1730 op2_lval = Z_LVAL_P(op2);
1731 }
1732
1733 if (op1 == result) {
1734 zval_ptr_dtor(result);
1735 }
1736 ZVAL_LONG(result, op1_lval ^ op2_lval);
1737 return SUCCESS;
1738 }
1739 /* }}} */
1740
shift_left_function(zval * result,zval * op1,zval * op2)1741 ZEND_API int ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2) /* {{{ */
1742 {
1743 zend_long op1_lval, op2_lval;
1744
1745 convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SL, shift_left_function);
1746
1747 /* prevent wrapping quirkiness on some processors where << 64 + x == << x */
1748 if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1749 if (EXPECTED(op2_lval > 0)) {
1750 if (op1 == result) {
1751 zval_ptr_dtor(result);
1752 }
1753 ZVAL_LONG(result, 0);
1754 return SUCCESS;
1755 } else {
1756 if (EG(current_execute_data) && !CG(in_compilation)) {
1757 zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1758 } else {
1759 zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1760 }
1761 if (op1 != result) {
1762 ZVAL_UNDEF(result);
1763 }
1764 return FAILURE;
1765 }
1766 }
1767
1768 if (op1 == result) {
1769 zval_ptr_dtor(result);
1770 }
1771
1772 /* Perform shift on unsigned numbers to get well-defined wrap behavior. */
1773 ZVAL_LONG(result, (zend_long) ((zend_ulong) op1_lval << op2_lval));
1774 return SUCCESS;
1775 }
1776 /* }}} */
1777
shift_right_function(zval * result,zval * op1,zval * op2)1778 ZEND_API int ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2) /* {{{ */
1779 {
1780 zend_long op1_lval, op2_lval;
1781
1782 convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SR, shift_right_function);
1783
1784 /* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */
1785 if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1786 if (EXPECTED(op2_lval > 0)) {
1787 if (op1 == result) {
1788 zval_ptr_dtor(result);
1789 }
1790 ZVAL_LONG(result, (op1_lval < 0) ? -1 : 0);
1791 return SUCCESS;
1792 } else {
1793 if (EG(current_execute_data) && !CG(in_compilation)) {
1794 zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1795 } else {
1796 zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1797 }
1798 if (op1 != result) {
1799 ZVAL_UNDEF(result);
1800 }
1801 return FAILURE;
1802 }
1803 }
1804
1805 if (op1 == result) {
1806 zval_ptr_dtor(result);
1807 }
1808
1809 ZVAL_LONG(result, op1_lval >> op2_lval);
1810 return SUCCESS;
1811 }
1812 /* }}} */
1813
concat_function(zval * result,zval * op1,zval * op2)1814 ZEND_API int ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */
1815 {
1816 zval *orig_op1 = op1;
1817 zval op1_copy, op2_copy;
1818
1819 ZVAL_UNDEF(&op1_copy);
1820 ZVAL_UNDEF(&op2_copy);
1821
1822 do {
1823 if (UNEXPECTED(Z_TYPE_P(op1) != IS_STRING)) {
1824 if (Z_ISREF_P(op1)) {
1825 op1 = Z_REFVAL_P(op1);
1826 if (Z_TYPE_P(op1) == IS_STRING) break;
1827 }
1828 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT, concat_function);
1829 ZVAL_STR(&op1_copy, zval_get_string_func(op1));
1830 if (UNEXPECTED(EG(exception))) {
1831 zval_ptr_dtor_str(&op1_copy);
1832 if (orig_op1 != result) {
1833 ZVAL_UNDEF(result);
1834 }
1835 return FAILURE;
1836 }
1837 if (result == op1) {
1838 if (UNEXPECTED(op1 == op2)) {
1839 op2 = &op1_copy;
1840 }
1841 }
1842 op1 = &op1_copy;
1843 }
1844 } while (0);
1845 do {
1846 if (UNEXPECTED(Z_TYPE_P(op2) != IS_STRING)) {
1847 if (Z_ISREF_P(op2)) {
1848 op2 = Z_REFVAL_P(op2);
1849 if (Z_TYPE_P(op2) == IS_STRING) break;
1850 }
1851 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT);
1852 ZVAL_STR(&op2_copy, zval_get_string_func(op2));
1853 if (UNEXPECTED(EG(exception))) {
1854 zval_ptr_dtor_str(&op1_copy);
1855 zval_ptr_dtor_str(&op2_copy);
1856 if (orig_op1 != result) {
1857 ZVAL_UNDEF(result);
1858 }
1859 return FAILURE;
1860 }
1861 op2 = &op2_copy;
1862 }
1863 } while (0);
1864
1865 if (UNEXPECTED(Z_STRLEN_P(op1) == 0)) {
1866 if (EXPECTED(result != op2)) {
1867 if (result == orig_op1) {
1868 i_zval_ptr_dtor(result);
1869 }
1870 ZVAL_COPY(result, op2);
1871 }
1872 } else if (UNEXPECTED(Z_STRLEN_P(op2) == 0)) {
1873 if (EXPECTED(result != op1)) {
1874 if (result == orig_op1) {
1875 i_zval_ptr_dtor(result);
1876 }
1877 ZVAL_COPY(result, op1);
1878 }
1879 } else {
1880 size_t op1_len = Z_STRLEN_P(op1);
1881 size_t op2_len = Z_STRLEN_P(op2);
1882 size_t result_len = op1_len + op2_len;
1883 zend_string *result_str;
1884
1885 if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) {
1886 zend_throw_error(NULL, "String size overflow");
1887 zval_ptr_dtor_str(&op1_copy);
1888 zval_ptr_dtor_str(&op2_copy);
1889 if (orig_op1 != result) {
1890 ZVAL_UNDEF(result);
1891 }
1892 return FAILURE;
1893 }
1894
1895 if (result == op1 && Z_REFCOUNTED_P(result)) {
1896 /* special case, perform operations on result */
1897 result_str = zend_string_extend(Z_STR_P(result), result_len, 0);
1898 } else {
1899 result_str = zend_string_alloc(result_len, 0);
1900 memcpy(ZSTR_VAL(result_str), Z_STRVAL_P(op1), op1_len);
1901 if (result == orig_op1) {
1902 i_zval_ptr_dtor(result);
1903 }
1904 }
1905
1906 /* This has to happen first to account for the cases where result == op1 == op2 and
1907 * the realloc is done. In this case this line will also update Z_STRVAL_P(op2) to
1908 * point to the new string. The first op2_len bytes of result will still be the same. */
1909 ZVAL_NEW_STR(result, result_str);
1910
1911 memcpy(ZSTR_VAL(result_str) + op1_len, Z_STRVAL_P(op2), op2_len);
1912 ZSTR_VAL(result_str)[result_len] = '\0';
1913 }
1914
1915 zval_ptr_dtor_str(&op1_copy);
1916 zval_ptr_dtor_str(&op2_copy);
1917 return SUCCESS;
1918 }
1919 /* }}} */
1920
string_compare_function_ex(zval * op1,zval * op2,zend_bool case_insensitive)1921 ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, zend_bool case_insensitive) /* {{{ */
1922 {
1923 zend_string *tmp_str1, *tmp_str2;
1924 zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
1925 zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
1926 int ret;
1927
1928 if (case_insensitive) {
1929 ret = zend_binary_strcasecmp_l(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1));
1930 } else {
1931 ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
1932 }
1933
1934 zend_tmp_string_release(tmp_str1);
1935 zend_tmp_string_release(tmp_str2);
1936 return ret;
1937 }
1938 /* }}} */
1939
string_compare_function(zval * op1,zval * op2)1940 ZEND_API int ZEND_FASTCALL string_compare_function(zval *op1, zval *op2) /* {{{ */
1941 {
1942 if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1943 EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1944 if (Z_STR_P(op1) == Z_STR_P(op2)) {
1945 return 0;
1946 } else {
1947 return zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1948 }
1949 } else {
1950 zend_string *tmp_str1, *tmp_str2;
1951 zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
1952 zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
1953 int ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
1954
1955 zend_tmp_string_release(tmp_str1);
1956 zend_tmp_string_release(tmp_str2);
1957 return ret;
1958 }
1959 }
1960 /* }}} */
1961
string_case_compare_function(zval * op1,zval * op2)1962 ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2) /* {{{ */
1963 {
1964 if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
1965 EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1966 if (Z_STR_P(op1) == Z_STR_P(op2)) {
1967 return 0;
1968 } else {
1969 return zend_binary_strcasecmp_l(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
1970 }
1971 } else {
1972 zend_string *tmp_str1, *tmp_str2;
1973 zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
1974 zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
1975 int ret = zend_binary_strcasecmp_l(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str1));
1976
1977 zend_tmp_string_release(tmp_str1);
1978 zend_tmp_string_release(tmp_str2);
1979 return ret;
1980 }
1981 }
1982 /* }}} */
1983
string_locale_compare_function(zval * op1,zval * op2)1984 ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2) /* {{{ */
1985 {
1986 zend_string *tmp_str1, *tmp_str2;
1987 zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
1988 zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
1989 int ret = strcoll(ZSTR_VAL(str1), ZSTR_VAL(str2));
1990
1991 zend_tmp_string_release(tmp_str1);
1992 zend_tmp_string_release(tmp_str2);
1993 return ret;
1994 }
1995 /* }}} */
1996
numeric_compare_function(zval * op1,zval * op2)1997 ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{ */
1998 {
1999 double d1, d2;
2000
2001 d1 = zval_get_double(op1);
2002 d2 = zval_get_double(op2);
2003
2004 return ZEND_NORMALIZE_BOOL(d1 - d2);
2005 }
2006 /* }}} */
2007
zend_free_obj_get_result(zval * op)2008 static zend_always_inline void zend_free_obj_get_result(zval *op) /* {{{ */
2009 {
2010 ZEND_ASSERT(!Z_REFCOUNTED_P(op) || Z_REFCOUNT_P(op) != 0);
2011 zval_ptr_dtor(op);
2012 }
2013 /* }}} */
2014
convert_compare_result_to_long(zval * result)2015 static void ZEND_FASTCALL convert_compare_result_to_long(zval *result) /* {{{ */
2016 {
2017 if (Z_TYPE_P(result) == IS_DOUBLE) {
2018 ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2019 } else {
2020 convert_to_long(result);
2021 }
2022 }
2023 /* }}} */
2024
compare_function(zval * result,zval * op1,zval * op2)2025 ZEND_API int ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
2026 {
2027 int ret;
2028 int converted = 0;
2029 zval op1_copy, op2_copy;
2030 zval *op_free, tmp_free;
2031
2032 while (1) {
2033 switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2034 case TYPE_PAIR(IS_LONG, IS_LONG):
2035 ZVAL_LONG(result, Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0));
2036 return SUCCESS;
2037
2038 case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2039 Z_DVAL_P(result) = Z_DVAL_P(op1) - (double)Z_LVAL_P(op2);
2040 ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2041 return SUCCESS;
2042
2043 case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2044 Z_DVAL_P(result) = (double)Z_LVAL_P(op1) - Z_DVAL_P(op2);
2045 ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2046 return SUCCESS;
2047
2048 case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2049 if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
2050 ZVAL_LONG(result, 0);
2051 } else {
2052 Z_DVAL_P(result) = Z_DVAL_P(op1) - Z_DVAL_P(op2);
2053 ZVAL_LONG(result, ZEND_NORMALIZE_BOOL(Z_DVAL_P(result)));
2054 }
2055 return SUCCESS;
2056
2057 case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2058 ZVAL_LONG(result, zend_compare_arrays(op1, op2));
2059 return SUCCESS;
2060
2061 case TYPE_PAIR(IS_NULL, IS_NULL):
2062 case TYPE_PAIR(IS_NULL, IS_FALSE):
2063 case TYPE_PAIR(IS_FALSE, IS_NULL):
2064 case TYPE_PAIR(IS_FALSE, IS_FALSE):
2065 case TYPE_PAIR(IS_TRUE, IS_TRUE):
2066 ZVAL_LONG(result, 0);
2067 return SUCCESS;
2068
2069 case TYPE_PAIR(IS_NULL, IS_TRUE):
2070 ZVAL_LONG(result, -1);
2071 return SUCCESS;
2072
2073 case TYPE_PAIR(IS_TRUE, IS_NULL):
2074 ZVAL_LONG(result, 1);
2075 return SUCCESS;
2076
2077 case TYPE_PAIR(IS_STRING, IS_STRING):
2078 if (Z_STR_P(op1) == Z_STR_P(op2)) {
2079 ZVAL_LONG(result, 0);
2080 return SUCCESS;
2081 }
2082 ZVAL_LONG(result, zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2)));
2083 return SUCCESS;
2084
2085 case TYPE_PAIR(IS_NULL, IS_STRING):
2086 ZVAL_LONG(result, Z_STRLEN_P(op2) == 0 ? 0 : -1);
2087 return SUCCESS;
2088
2089 case TYPE_PAIR(IS_STRING, IS_NULL):
2090 ZVAL_LONG(result, Z_STRLEN_P(op1) == 0 ? 0 : 1);
2091 return SUCCESS;
2092
2093 case TYPE_PAIR(IS_OBJECT, IS_NULL):
2094 ZVAL_LONG(result, 1);
2095 return SUCCESS;
2096
2097 case TYPE_PAIR(IS_NULL, IS_OBJECT):
2098 ZVAL_LONG(result, -1);
2099 return SUCCESS;
2100
2101 default:
2102 if (Z_ISREF_P(op1)) {
2103 op1 = Z_REFVAL_P(op1);
2104 continue;
2105 } else if (Z_ISREF_P(op2)) {
2106 op2 = Z_REFVAL_P(op2);
2107 continue;
2108 }
2109
2110 if (Z_TYPE_P(op1) == IS_OBJECT && Z_OBJ_HANDLER_P(op1, compare)) {
2111 ret = Z_OBJ_HANDLER_P(op1, compare)(result, op1, op2);
2112 if (UNEXPECTED(Z_TYPE_P(result) != IS_LONG)) {
2113 convert_compare_result_to_long(result);
2114 }
2115 return ret;
2116 } else if (Z_TYPE_P(op2) == IS_OBJECT && Z_OBJ_HANDLER_P(op2, compare)) {
2117 ret = Z_OBJ_HANDLER_P(op2, compare)(result, op1, op2);
2118 if (UNEXPECTED(Z_TYPE_P(result) != IS_LONG)) {
2119 convert_compare_result_to_long(result);
2120 }
2121 return ret;
2122 }
2123
2124 if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
2125 if (Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2126 /* object handles are identical, apparently this is the same object */
2127 ZVAL_LONG(result, 0);
2128 return SUCCESS;
2129 }
2130 if (Z_OBJ_HANDLER_P(op1, compare_objects) == Z_OBJ_HANDLER_P(op2, compare_objects)) {
2131 ZVAL_LONG(result, Z_OBJ_HANDLER_P(op1, compare_objects)(op1, op2));
2132 return SUCCESS;
2133 }
2134 }
2135 if (Z_TYPE_P(op1) == IS_OBJECT) {
2136 if (Z_OBJ_HT_P(op1)->get) {
2137 zval rv;
2138 op_free = Z_OBJ_HT_P(op1)->get(op1, &rv);
2139 ret = compare_function(result, op_free, op2);
2140 zend_free_obj_get_result(op_free);
2141 return ret;
2142 } else if (Z_TYPE_P(op2) != IS_OBJECT && Z_OBJ_HT_P(op1)->cast_object) {
2143 ZVAL_UNDEF(&tmp_free);
2144 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) {
2145 ZVAL_LONG(result, 1);
2146 zend_free_obj_get_result(&tmp_free);
2147 return SUCCESS;
2148 }
2149 ret = compare_function(result, &tmp_free, op2);
2150 zend_free_obj_get_result(&tmp_free);
2151 return ret;
2152 }
2153 }
2154 if (Z_TYPE_P(op2) == IS_OBJECT) {
2155 if (Z_OBJ_HT_P(op2)->get) {
2156 zval rv;
2157 op_free = Z_OBJ_HT_P(op2)->get(op2, &rv);
2158 ret = compare_function(result, op1, op_free);
2159 zend_free_obj_get_result(op_free);
2160 return ret;
2161 } else if (Z_TYPE_P(op1) != IS_OBJECT && Z_OBJ_HT_P(op2)->cast_object) {
2162 ZVAL_UNDEF(&tmp_free);
2163 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) {
2164 ZVAL_LONG(result, -1);
2165 zend_free_obj_get_result(&tmp_free);
2166 return SUCCESS;
2167 }
2168 ret = compare_function(result, op1, &tmp_free);
2169 zend_free_obj_get_result(&tmp_free);
2170 return ret;
2171 } else if (Z_TYPE_P(op1) == IS_OBJECT) {
2172 ZVAL_LONG(result, 1);
2173 return SUCCESS;
2174 }
2175 }
2176 if (!converted) {
2177 if (Z_TYPE_P(op1) < IS_TRUE) {
2178 ZVAL_LONG(result, zval_is_true(op2) ? -1 : 0);
2179 return SUCCESS;
2180 } else if (Z_TYPE_P(op1) == IS_TRUE) {
2181 ZVAL_LONG(result, zval_is_true(op2) ? 0 : 1);
2182 return SUCCESS;
2183 } else if (Z_TYPE_P(op2) < IS_TRUE) {
2184 ZVAL_LONG(result, zval_is_true(op1) ? 1 : 0);
2185 return SUCCESS;
2186 } else if (Z_TYPE_P(op2) == IS_TRUE) {
2187 ZVAL_LONG(result, zval_is_true(op1) ? 0 : -1);
2188 return SUCCESS;
2189 } else {
2190 op1 = zendi_convert_scalar_to_number(op1, &op1_copy, result, 1);
2191 op2 = zendi_convert_scalar_to_number(op2, &op2_copy, result, 1);
2192 if (EG(exception)) {
2193 if (result != op1) {
2194 ZVAL_UNDEF(result);
2195 }
2196 return FAILURE;
2197 }
2198 converted = 1;
2199 }
2200 } else if (Z_TYPE_P(op1)==IS_ARRAY) {
2201 ZVAL_LONG(result, 1);
2202 return SUCCESS;
2203 } else if (Z_TYPE_P(op2)==IS_ARRAY) {
2204 ZVAL_LONG(result, -1);
2205 return SUCCESS;
2206 } else {
2207 ZEND_ASSERT(0);
2208 zend_throw_error(NULL, "Unsupported operand types");
2209 if (result != op1) {
2210 ZVAL_UNDEF(result);
2211 }
2212 return FAILURE;
2213 }
2214 }
2215 }
2216 }
2217 /* }}} */
2218
hash_zval_identical_function(zval * z1,zval * z2)2219 static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */
2220 {
2221 /* is_identical_function() returns 1 in case of identity and 0 in case
2222 * of a difference;
2223 * whereas this comparison function is expected to return 0 on identity,
2224 * and non zero otherwise.
2225 */
2226 ZVAL_DEREF(z1);
2227 ZVAL_DEREF(z2);
2228 return fast_is_not_identical_function(z1, z2);
2229 }
2230 /* }}} */
2231
zend_is_identical(zval * op1,zval * op2)2232 ZEND_API zend_bool ZEND_FASTCALL zend_is_identical(zval *op1, zval *op2) /* {{{ */
2233 {
2234 if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
2235 return 0;
2236 }
2237 switch (Z_TYPE_P(op1)) {
2238 case IS_NULL:
2239 case IS_FALSE:
2240 case IS_TRUE:
2241 return 1;
2242 case IS_LONG:
2243 return (Z_LVAL_P(op1) == Z_LVAL_P(op2));
2244 case IS_RESOURCE:
2245 return (Z_RES_P(op1) == Z_RES_P(op2));
2246 case IS_DOUBLE:
2247 return (Z_DVAL_P(op1) == Z_DVAL_P(op2));
2248 case IS_STRING:
2249 return zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
2250 case IS_ARRAY:
2251 return (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
2252 zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1) == 0);
2253 case IS_OBJECT:
2254 return (Z_OBJ_P(op1) == Z_OBJ_P(op2));
2255 default:
2256 return 0;
2257 }
2258 }
2259 /* }}} */
2260
is_identical_function(zval * result,zval * op1,zval * op2)2261 ZEND_API int ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2262 {
2263 ZVAL_BOOL(result, zend_is_identical(op1, op2));
2264 return SUCCESS;
2265 }
2266 /* }}} */
2267
is_not_identical_function(zval * result,zval * op1,zval * op2)2268 ZEND_API int ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2269 {
2270 ZVAL_BOOL(result, !zend_is_identical(op1, op2));
2271 return SUCCESS;
2272 }
2273 /* }}} */
2274
is_equal_function(zval * result,zval * op1,zval * op2)2275 ZEND_API int ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2276 {
2277 if (compare_function(result, op1, op2) == FAILURE) {
2278 return FAILURE;
2279 }
2280 ZVAL_BOOL(result, (Z_LVAL_P(result) == 0));
2281 return SUCCESS;
2282 }
2283 /* }}} */
2284
is_not_equal_function(zval * result,zval * op1,zval * op2)2285 ZEND_API int ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2286 {
2287 if (compare_function(result, op1, op2) == FAILURE) {
2288 return FAILURE;
2289 }
2290 ZVAL_BOOL(result, (Z_LVAL_P(result) != 0));
2291 return SUCCESS;
2292 }
2293 /* }}} */
2294
is_smaller_function(zval * result,zval * op1,zval * op2)2295 ZEND_API int ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2) /* {{{ */
2296 {
2297 if (compare_function(result, op1, op2) == FAILURE) {
2298 return FAILURE;
2299 }
2300 ZVAL_BOOL(result, (Z_LVAL_P(result) < 0));
2301 return SUCCESS;
2302 }
2303 /* }}} */
2304
is_smaller_or_equal_function(zval * result,zval * op1,zval * op2)2305 ZEND_API int ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2306 {
2307 if (compare_function(result, op1, op2) == FAILURE) {
2308 return FAILURE;
2309 }
2310 ZVAL_BOOL(result, (Z_LVAL_P(result) <= 0));
2311 return SUCCESS;
2312 }
2313 /* }}} */
2314
instanceof_class(const zend_class_entry * instance_ce,const zend_class_entry * ce)2315 static zend_always_inline zend_bool instanceof_class(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2316 {
2317 do {
2318 if (instance_ce == ce) {
2319 return 1;
2320 }
2321 instance_ce = instance_ce->parent;
2322 } while (instance_ce);
2323 return 0;
2324 }
2325 /* }}} */
2326
instanceof_interface(const zend_class_entry * instance_ce,const zend_class_entry * ce)2327 static zend_bool ZEND_FASTCALL instanceof_interface(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2328 {
2329 uint32_t i;
2330
2331 if (instance_ce->num_interfaces) {
2332 ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2333 for (i = 0; i < instance_ce->num_interfaces; i++) {
2334 if (instance_ce->interfaces[i] == ce) {
2335 return 1;
2336 }
2337 }
2338 }
2339 return instance_ce == ce;
2340 }
2341 /* }}} */
2342
2343 // TODO: It would make more sense to expose instanceof_class + instanceof_interface instead
instanceof_function_ex(const zend_class_entry * instance_ce,const zend_class_entry * ce,zend_bool is_interface)2344 ZEND_API zend_bool ZEND_FASTCALL instanceof_function_ex(const zend_class_entry *instance_ce, const zend_class_entry *ce, zend_bool is_interface) /* {{{ */
2345 {
2346 if (is_interface) {
2347 ZEND_ASSERT(ce->ce_flags & ZEND_ACC_INTERFACE);
2348 return instanceof_interface(instance_ce, ce);
2349 } else {
2350 ZEND_ASSERT(!(ce->ce_flags & ZEND_ACC_INTERFACE));
2351 return instanceof_class(instance_ce, ce);
2352 }
2353 }
2354 /* }}} */
2355
instanceof_function(const zend_class_entry * instance_ce,const zend_class_entry * ce)2356 ZEND_API zend_bool ZEND_FASTCALL instanceof_function(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2357 {
2358 if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2359 return instanceof_interface(instance_ce, ce);
2360 } else {
2361 return instanceof_class(instance_ce, ce);
2362 }
2363 }
2364 /* }}} */
2365
2366 #define LOWER_CASE 1
2367 #define UPPER_CASE 2
2368 #define NUMERIC 3
2369
increment_string(zval * str)2370 static void ZEND_FASTCALL increment_string(zval *str) /* {{{ */
2371 {
2372 int carry=0;
2373 size_t pos=Z_STRLEN_P(str)-1;
2374 char *s;
2375 zend_string *t;
2376 int last=0; /* Shut up the compiler warning */
2377 int ch;
2378
2379 if (Z_STRLEN_P(str) == 0) {
2380 zval_ptr_dtor_str(str);
2381 ZVAL_INTERNED_STR(str, ZSTR_CHAR('1'));
2382 return;
2383 }
2384
2385 if (!Z_REFCOUNTED_P(str)) {
2386 Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2387 Z_TYPE_INFO_P(str) = IS_STRING_EX;
2388 } else if (Z_REFCOUNT_P(str) > 1) {
2389 Z_DELREF_P(str);
2390 Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2391 } else {
2392 zend_string_forget_hash_val(Z_STR_P(str));
2393 }
2394 s = Z_STRVAL_P(str);
2395
2396 do {
2397 ch = s[pos];
2398 if (ch >= 'a' && ch <= 'z') {
2399 if (ch == 'z') {
2400 s[pos] = 'a';
2401 carry=1;
2402 } else {
2403 s[pos]++;
2404 carry=0;
2405 }
2406 last=LOWER_CASE;
2407 } else if (ch >= 'A' && ch <= 'Z') {
2408 if (ch == 'Z') {
2409 s[pos] = 'A';
2410 carry=1;
2411 } else {
2412 s[pos]++;
2413 carry=0;
2414 }
2415 last=UPPER_CASE;
2416 } else if (ch >= '0' && ch <= '9') {
2417 if (ch == '9') {
2418 s[pos] = '0';
2419 carry=1;
2420 } else {
2421 s[pos]++;
2422 carry=0;
2423 }
2424 last = NUMERIC;
2425 } else {
2426 carry=0;
2427 break;
2428 }
2429 if (carry == 0) {
2430 break;
2431 }
2432 } while (pos-- > 0);
2433
2434 if (carry) {
2435 t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
2436 memcpy(ZSTR_VAL(t) + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
2437 ZSTR_VAL(t)[Z_STRLEN_P(str) + 1] = '\0';
2438 switch (last) {
2439 case NUMERIC:
2440 ZSTR_VAL(t)[0] = '1';
2441 break;
2442 case UPPER_CASE:
2443 ZSTR_VAL(t)[0] = 'A';
2444 break;
2445 case LOWER_CASE:
2446 ZSTR_VAL(t)[0] = 'a';
2447 break;
2448 }
2449 zend_string_free(Z_STR_P(str));
2450 ZVAL_NEW_STR(str, t);
2451 }
2452 }
2453 /* }}} */
2454
increment_function(zval * op1)2455 ZEND_API int ZEND_FASTCALL increment_function(zval *op1) /* {{{ */
2456 {
2457 try_again:
2458 switch (Z_TYPE_P(op1)) {
2459 case IS_LONG:
2460 fast_long_increment_function(op1);
2461 break;
2462 case IS_DOUBLE:
2463 Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2464 break;
2465 case IS_NULL:
2466 ZVAL_LONG(op1, 1);
2467 break;
2468 case IS_STRING: {
2469 zend_long lval;
2470 double dval;
2471
2472 switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2473 case IS_LONG:
2474 zval_ptr_dtor_str(op1);
2475 if (lval == ZEND_LONG_MAX) {
2476 /* switch to double */
2477 double d = (double)lval;
2478 ZVAL_DOUBLE(op1, d+1);
2479 } else {
2480 ZVAL_LONG(op1, lval+1);
2481 }
2482 break;
2483 case IS_DOUBLE:
2484 zval_ptr_dtor_str(op1);
2485 ZVAL_DOUBLE(op1, dval+1);
2486 break;
2487 default:
2488 /* Perl style string increment */
2489 increment_string(op1);
2490 break;
2491 }
2492 }
2493 break;
2494 case IS_OBJECT:
2495 if (Z_OBJ_HANDLER_P(op1, get)
2496 && Z_OBJ_HANDLER_P(op1, set)) {
2497 /* proxy object */
2498 zval rv;
2499 zval *val;
2500
2501 val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
2502 Z_TRY_ADDREF_P(val);
2503 increment_function(val);
2504 Z_OBJ_HANDLER_P(op1, set)(op1, val);
2505 zval_ptr_dtor(val);
2506 } else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2507 zval op2;
2508 int res;
2509
2510 ZVAL_LONG(&op2, 1);
2511 res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2);
2512
2513 return res;
2514 }
2515 return FAILURE;
2516 case IS_REFERENCE:
2517 op1 = Z_REFVAL_P(op1);
2518 goto try_again;
2519 default:
2520 return FAILURE;
2521 }
2522 return SUCCESS;
2523 }
2524 /* }}} */
2525
decrement_function(zval * op1)2526 ZEND_API int ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */
2527 {
2528 zend_long lval;
2529 double dval;
2530
2531 try_again:
2532 switch (Z_TYPE_P(op1)) {
2533 case IS_LONG:
2534 fast_long_decrement_function(op1);
2535 break;
2536 case IS_DOUBLE:
2537 Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2538 break;
2539 case IS_STRING: /* Like perl we only support string increment */
2540 if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2541 zval_ptr_dtor_str(op1);
2542 ZVAL_LONG(op1, -1);
2543 break;
2544 }
2545 switch (is_numeric_string(Z_STRVAL_P(op1), Z_STRLEN_P(op1), &lval, &dval, 0)) {
2546 case IS_LONG:
2547 zval_ptr_dtor_str(op1);
2548 if (lval == ZEND_LONG_MIN) {
2549 double d = (double)lval;
2550 ZVAL_DOUBLE(op1, d-1);
2551 } else {
2552 ZVAL_LONG(op1, lval-1);
2553 }
2554 break;
2555 case IS_DOUBLE:
2556 zval_ptr_dtor_str(op1);
2557 ZVAL_DOUBLE(op1, dval - 1);
2558 break;
2559 }
2560 break;
2561 case IS_OBJECT:
2562 if (Z_OBJ_HANDLER_P(op1, get)
2563 && Z_OBJ_HANDLER_P(op1, set)) {
2564 /* proxy object */
2565 zval rv;
2566 zval *val;
2567
2568 val = Z_OBJ_HANDLER_P(op1, get)(op1, &rv);
2569 Z_TRY_ADDREF_P(val);
2570 decrement_function(val);
2571 Z_OBJ_HANDLER_P(op1, set)(op1, val);
2572 zval_ptr_dtor(val);
2573 } else if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2574 zval op2;
2575 int res;
2576
2577 ZVAL_LONG(&op2, 1);
2578 res = Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2);
2579
2580 return res;
2581 }
2582 return FAILURE;
2583 case IS_REFERENCE:
2584 op1 = Z_REFVAL_P(op1);
2585 goto try_again;
2586 default:
2587 return FAILURE;
2588 }
2589
2590 return SUCCESS;
2591 }
2592 /* }}} */
2593
zend_is_true(zval * op)2594 ZEND_API int ZEND_FASTCALL zend_is_true(zval *op) /* {{{ */
2595 {
2596 return i_zend_is_true(op);
2597 }
2598 /* }}} */
2599
zend_object_is_true(zval * op)2600 ZEND_API int ZEND_FASTCALL zend_object_is_true(zval *op) /* {{{ */
2601 {
2602 if (Z_OBJ_HT_P(op)->cast_object) {
2603 zval tmp;
2604 if (Z_OBJ_HT_P(op)->cast_object(op, &tmp, _IS_BOOL) == SUCCESS) {
2605 return Z_TYPE(tmp) == IS_TRUE;
2606 }
2607 zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to bool", ZSTR_VAL(Z_OBJ_P(op)->ce->name));
2608 } else if (Z_OBJ_HT_P(op)->get) {
2609 int result;
2610 zval rv;
2611 zval *tmp = Z_OBJ_HT_P(op)->get(op, &rv);
2612
2613 if (Z_TYPE_P(tmp) != IS_OBJECT) {
2614 /* for safety - avoid loop */
2615 result = i_zend_is_true(tmp);
2616 zval_ptr_dtor(tmp);
2617 return result;
2618 }
2619 }
2620 return 1;
2621 }
2622 /* }}} */
2623
2624 #ifdef ZEND_USE_TOLOWER_L
zend_update_current_locale(void)2625 ZEND_API void zend_update_current_locale(void) /* {{{ */
2626 {
2627 current_locale = _get_current_locale();
2628 }
2629 /* }}} */
2630 #endif
2631
zend_str_tolower_copy(char * dest,const char * source,size_t length)2632 ZEND_API char* ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
2633 {
2634 register unsigned char *str = (unsigned char*)source;
2635 register unsigned char *result = (unsigned char*)dest;
2636 register unsigned char *end = str + length;
2637
2638 while (str < end) {
2639 *result++ = zend_tolower_ascii(*str++);
2640 }
2641 *result = '\0';
2642
2643 return dest;
2644 }
2645 /* }}} */
2646
zend_str_tolower_dup(const char * source,size_t length)2647 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2648 {
2649 return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2650 }
2651 /* }}} */
2652
zend_str_tolower(char * str,size_t length)2653 ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length) /* {{{ */
2654 {
2655 register unsigned char *p = (unsigned char*)str;
2656 register unsigned char *end = p + length;
2657
2658 while (p < end) {
2659 *p = zend_tolower_ascii(*p);
2660 p++;
2661 }
2662 }
2663 /* }}} */
2664
zend_str_tolower_dup_ex(const char * source,size_t length)2665 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length) /* {{{ */
2666 {
2667 register const unsigned char *p = (const unsigned char*)source;
2668 register const unsigned char *end = p + length;
2669
2670 while (p < end) {
2671 if (*p != zend_tolower_ascii(*p)) {
2672 char *res = (char*)emalloc(length + 1);
2673 register unsigned char *r;
2674
2675 if (p != (const unsigned char*)source) {
2676 memcpy(res, source, p - (const unsigned char*)source);
2677 }
2678 r = (unsigned char*)p + (res - source);
2679 while (p < end) {
2680 *r = zend_tolower_ascii(*p);
2681 p++;
2682 r++;
2683 }
2684 *r = '\0';
2685 return res;
2686 }
2687 p++;
2688 }
2689 return NULL;
2690 }
2691 /* }}} */
2692
zend_string_tolower_ex(zend_string * str,int persistent)2693 ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, int persistent) /* {{{ */
2694 {
2695 register unsigned char *p = (unsigned char*)ZSTR_VAL(str);
2696 register unsigned char *end = p + ZSTR_LEN(str);
2697
2698 while (p < end) {
2699 if (*p != zend_tolower_ascii(*p)) {
2700 zend_string *res = zend_string_alloc(ZSTR_LEN(str), persistent);
2701 register unsigned char *r;
2702
2703 if (p != (unsigned char*)ZSTR_VAL(str)) {
2704 memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*)ZSTR_VAL(str));
2705 }
2706 r = p + (ZSTR_VAL(res) - ZSTR_VAL(str));
2707 while (p < end) {
2708 *r = zend_tolower_ascii(*p);
2709 p++;
2710 r++;
2711 }
2712 *r = '\0';
2713 return res;
2714 }
2715 p++;
2716 }
2717 return zend_string_copy(str);
2718 }
2719 /* }}} */
2720
zend_binary_strcmp(const char * s1,size_t len1,const char * s2,size_t len2)2721 ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2722 {
2723 int retval;
2724
2725 if (s1 == s2) {
2726 return 0;
2727 }
2728 retval = memcmp(s1, s2, MIN(len1, len2));
2729 if (!retval) {
2730 return (int)(len1 - len2);
2731 } else {
2732 return retval;
2733 }
2734 }
2735 /* }}} */
2736
zend_binary_strncmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)2737 ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2738 {
2739 int retval;
2740
2741 if (s1 == s2) {
2742 return 0;
2743 }
2744 retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
2745 if (!retval) {
2746 return (int)(MIN(length, len1) - MIN(length, len2));
2747 } else {
2748 return retval;
2749 }
2750 }
2751 /* }}} */
2752
zend_binary_strcasecmp(const char * s1,size_t len1,const char * s2,size_t len2)2753 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2754 {
2755 size_t len;
2756 int c1, c2;
2757
2758 if (s1 == s2) {
2759 return 0;
2760 }
2761
2762 len = MIN(len1, len2);
2763 while (len--) {
2764 c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2765 c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2766 if (c1 != c2) {
2767 return c1 - c2;
2768 }
2769 }
2770
2771 return (int)(len1 - len2);
2772 }
2773 /* }}} */
2774
zend_binary_strncasecmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)2775 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2776 {
2777 size_t len;
2778 int c1, c2;
2779
2780 if (s1 == s2) {
2781 return 0;
2782 }
2783 len = MIN(length, MIN(len1, len2));
2784 while (len--) {
2785 c1 = zend_tolower_ascii(*(unsigned char *)s1++);
2786 c2 = zend_tolower_ascii(*(unsigned char *)s2++);
2787 if (c1 != c2) {
2788 return c1 - c2;
2789 }
2790 }
2791
2792 return (int)(MIN(length, len1) - MIN(length, len2));
2793 }
2794 /* }}} */
2795
zend_binary_strcasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2)2796 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
2797 {
2798 size_t len;
2799 int c1, c2;
2800
2801 if (s1 == s2) {
2802 return 0;
2803 }
2804
2805 len = MIN(len1, len2);
2806 while (len--) {
2807 c1 = zend_tolower((int)*(unsigned char *)s1++);
2808 c2 = zend_tolower((int)*(unsigned char *)s2++);
2809 if (c1 != c2) {
2810 return c1 - c2;
2811 }
2812 }
2813
2814 return (int)(len1 - len2);
2815 }
2816 /* }}} */
2817
zend_binary_strncasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)2818 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
2819 {
2820 size_t len;
2821 int c1, c2;
2822
2823 if (s1 == s2) {
2824 return 0;
2825 }
2826 len = MIN(length, MIN(len1, len2));
2827 while (len--) {
2828 c1 = zend_tolower((int)*(unsigned char *)s1++);
2829 c2 = zend_tolower((int)*(unsigned char *)s2++);
2830 if (c1 != c2) {
2831 return c1 - c2;
2832 }
2833 }
2834
2835 return (int)(MIN(length, len1) - MIN(length, len2));
2836 }
2837 /* }}} */
2838
zend_binary_zval_strcmp(zval * s1,zval * s2)2839 ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
2840 {
2841 return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2842 }
2843 /* }}} */
2844
zend_binary_zval_strncmp(zval * s1,zval * s2,zval * s3)2845 ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2846 {
2847 return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
2848 }
2849 /* }}} */
2850
zend_binary_zval_strcasecmp(zval * s1,zval * s2)2851 ZEND_API int ZEND_FASTCALL zend_binary_zval_strcasecmp(zval *s1, zval *s2) /* {{{ */
2852 {
2853 return zend_binary_strcasecmp_l(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
2854 }
2855 /* }}} */
2856
zend_binary_zval_strncasecmp(zval * s1,zval * s2,zval * s3)2857 ZEND_API int ZEND_FASTCALL zend_binary_zval_strncasecmp(zval *s1, zval *s2, zval *s3) /* {{{ */
2858 {
2859 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));
2860 }
2861 /* }}} */
2862
zendi_smart_streq(zend_string * s1,zend_string * s2)2863 ZEND_API int ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2) /* {{{ */
2864 {
2865 int ret1, ret2;
2866 int oflow1, oflow2;
2867 zend_long lval1 = 0, lval2 = 0;
2868 double dval1 = 0.0, dval2 = 0.0;
2869
2870 if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, 0, &oflow1)) &&
2871 (ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, 0, &oflow2))) {
2872 #if ZEND_ULONG_MAX == 0xFFFFFFFF
2873 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2874 ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2875 || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2876 #else
2877 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2878 #endif
2879 /* both values are integers overflown to the same side, and the
2880 * double comparison may have resulted in crucial accuracy lost */
2881 goto string_cmp;
2882 }
2883 if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
2884 if (ret1 != IS_DOUBLE) {
2885 if (oflow2) {
2886 /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2887 return 0;
2888 }
2889 dval1 = (double) lval1;
2890 } else if (ret2 != IS_DOUBLE) {
2891 if (oflow1) {
2892 return 0;
2893 }
2894 dval2 = (double) lval2;
2895 } else if (dval1 == dval2 && !zend_finite(dval1)) {
2896 /* Both values overflowed and have the same sign,
2897 * so a numeric comparison would be inaccurate */
2898 goto string_cmp;
2899 }
2900 return dval1 == dval2;
2901 } else { /* they both have to be long's */
2902 return lval1 == lval2;
2903 }
2904 } else {
2905 string_cmp:
2906 return zend_string_equal_content(s1, s2);
2907 }
2908 }
2909 /* }}} */
2910
2911 ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2) /* {{{ */
2912 {
2913 int ret1, ret2;
2914 int oflow1, oflow2;
2915 zend_long lval1 = 0, lval2 = 0;
2916 double dval1 = 0.0, dval2 = 0.0;
2917
2918 if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, 0, &oflow1)) &&
2919 (ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, 0, &oflow2))) {
2920 #if ZEND_ULONG_MAX == 0xFFFFFFFF
2921 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
2922 ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
2923 || (oflow1 == -1 && dval1 < -9007199254740991.))) {
2924 #else
2925 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
2926 #endif
2927 /* both values are integers overflown to the same side, and the
2928 * double comparison may have resulted in crucial accuracy lost */
2929 goto string_cmp;
2930 }
2931 if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
2932 if (ret1 != IS_DOUBLE) {
2933 if (oflow2) {
2934 /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
2935 return -1 * oflow2;
2936 }
2937 dval1 = (double) lval1;
2938 } else if (ret2 != IS_DOUBLE) {
2939 if (oflow1) {
2940 return oflow1;
2941 }
2942 dval2 = (double) lval2;
2943 } else if (dval1 == dval2 && !zend_finite(dval1)) {
2944 /* Both values overflowed and have the same sign,
2945 * so a numeric comparison would be inaccurate */
2946 goto string_cmp;
2947 }
2948 dval1 = dval1 - dval2;
2949 return ZEND_NORMALIZE_BOOL(dval1);
2950 } else { /* they both have to be long's */
2951 return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
2952 }
2953 } else {
2954 int strcmp_ret;
2955 string_cmp:
2956 strcmp_ret = zend_binary_strcmp(s1->val, s1->len, s2->val, s2->len);
2957 return ZEND_NORMALIZE_BOOL(strcmp_ret);
2958 }
2959 }
2960 /* }}} */
2961
2962 static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */
2963 {
2964 zval result;
2965
2966 if (compare_function(&result, z1, z2)==FAILURE) {
2967 return 1;
2968 }
2969 return Z_LVAL(result);
2970 }
2971 /* }}} */
2972
2973 ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */
2974 {
2975 return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
2976 }
2977 /* }}} */
2978
2979 ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */
2980 {
2981 return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2));
2982 }
2983 /* }}} */
2984
2985 ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */
2986 {
2987 if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
2988 return 0;
2989 }
2990
2991 if (Z_OBJ_HT_P(o1)->compare_objects == NULL) {
2992 return 1;
2993 } else {
2994 return Z_OBJ_HT_P(o1)->compare_objects(o1, o2);
2995 }
2996 }
2997 /* }}} */
2998
2999 ZEND_API void ZEND_FASTCALL zend_locale_sprintf_double(zval *op ZEND_FILE_LINE_DC) /* {{{ */
3000 {
3001 zend_string *str;
3002
3003 str = zend_strpprintf(0, "%.*G", (int) EG(precision), (double)Z_DVAL_P(op));
3004 ZVAL_NEW_STR(op, str);
3005 }
3006 /* }}} */
3007
3008 ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */
3009 {
3010 if ((zend_ulong)num <= 9) {
3011 return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3012 } else {
3013 char buf[MAX_LENGTH_OF_LONG + 1];
3014 char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
3015 return zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3016 }
3017 }
3018 /* }}} */
3019
3020 ZEND_API zend_uchar ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */ {
3021 return is_numeric_string_ex(ZSTR_VAL(str), ZSTR_LEN(str), lval, dval, -1, NULL);
3022 }
3023 /* }}} */
3024
3025 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) /* {{{ */
3026 {
3027 const char *ptr;
3028 int digits = 0, dp_or_e = 0;
3029 double local_dval = 0.0;
3030 zend_uchar type;
3031 zend_ulong tmp_lval = 0;
3032 int neg = 0;
3033
3034 if (!length) {
3035 return 0;
3036 }
3037
3038 if (oflow_info != NULL) {
3039 *oflow_info = 0;
3040 }
3041
3042 /* Skip any whitespace
3043 * This is much faster than the isspace() function */
3044 while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
3045 str++;
3046 length--;
3047 }
3048 ptr = str;
3049
3050 if (*ptr == '-') {
3051 neg = 1;
3052 ptr++;
3053 } else if (*ptr == '+') {
3054 ptr++;
3055 }
3056
3057 if (ZEND_IS_DIGIT(*ptr)) {
3058 /* Skip any leading 0s */
3059 while (*ptr == '0') {
3060 ptr++;
3061 }
3062
3063 /* Count the number of digits. If a decimal point/exponent is found,
3064 * it's a double. Otherwise, if there's a dval or no need to check for
3065 * a full match, stop when there are too many digits for a long */
3066 for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors == 1)); digits++, ptr++) {
3067 check_digits:
3068 if (ZEND_IS_DIGIT(*ptr)) {
3069 tmp_lval = tmp_lval * 10 + (*ptr) - '0';
3070 continue;
3071 } else if (*ptr == '.' && dp_or_e < 1) {
3072 goto process_double;
3073 } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
3074 const char *e = ptr + 1;
3075
3076 if (*e == '-' || *e == '+') {
3077 ptr = e++;
3078 }
3079 if (ZEND_IS_DIGIT(*e)) {
3080 goto process_double;
3081 }
3082 }
3083
3084 break;
3085 }
3086
3087 if (digits >= MAX_LENGTH_OF_LONG) {
3088 if (oflow_info != NULL) {
3089 *oflow_info = *str == '-' ? -1 : 1;
3090 }
3091 dp_or_e = -1;
3092 goto process_double;
3093 }
3094 } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
3095 process_double:
3096 type = IS_DOUBLE;
3097
3098 /* If there's a dval, do the conversion; else continue checking
3099 * the digits if we need to check for a full match */
3100 if (dval) {
3101 local_dval = zend_strtod(str, &ptr);
3102 } else if (allow_errors != 1 && dp_or_e != -1) {
3103 dp_or_e = (*ptr++ == '.') ? 1 : 2;
3104 goto check_digits;
3105 }
3106 } else {
3107 return 0;
3108 }
3109
3110 if (ptr != str + length) {
3111 if (!allow_errors) {
3112 return 0;
3113 }
3114 if (allow_errors == -1) {
3115 zend_error(E_NOTICE, "A non well formed numeric value encountered");
3116 if (EG(exception)) {
3117 return 0;
3118 }
3119 }
3120 }
3121
3122 if (type == IS_LONG) {
3123 if (digits == MAX_LENGTH_OF_LONG - 1) {
3124 int cmp = strcmp(&ptr[-digits], long_min_digits);
3125
3126 if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
3127 if (dval) {
3128 *dval = zend_strtod(str, NULL);
3129 }
3130 if (oflow_info != NULL) {
3131 *oflow_info = *str == '-' ? -1 : 1;
3132 }
3133
3134 return IS_DOUBLE;
3135 }
3136 }
3137
3138 if (lval) {
3139 if (neg) {
3140 tmp_lval = -tmp_lval;
3141 }
3142 *lval = (zend_long) tmp_lval;
3143 }
3144
3145 return IS_LONG;
3146 } else {
3147 if (dval) {
3148 *dval = local_dval;
3149 }
3150
3151 return IS_DOUBLE;
3152 }
3153 }
3154 /* }}} */
3155
3156 /*
3157 * String matching - Sunday algorithm
3158 * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
3159 */
3160 static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
3161 int i;
3162
3163 for (i = 0; i < 256; i++) {
3164 td[i] = needle_len + 1;
3165 }
3166
3167 if (reverse) {
3168 for (i = needle_len - 1; i >= 0; i--) {
3169 td[(unsigned char)needle[i]] = i + 1;
3170 }
3171 } else {
3172 size_t i;
3173
3174 for (i = 0; i < needle_len; i++) {
3175 td[(unsigned char)needle[i]] = (int)needle_len - i;
3176 }
3177 }
3178 }
3179 /* }}} */
3180
3181 ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3182 {
3183 unsigned int td[256];
3184 register size_t i;
3185 register const char *p;
3186
3187 if (needle_len == 0 || (end - haystack) < needle_len) {
3188 return NULL;
3189 }
3190
3191 zend_memnstr_ex_pre(td, needle, needle_len, 0);
3192
3193 p = haystack;
3194 end -= needle_len;
3195
3196 while (p <= end) {
3197 for (i = 0; i < needle_len; i++) {
3198 if (needle[i] != p[i]) {
3199 break;
3200 }
3201 }
3202 if (i == needle_len) {
3203 return p;
3204 }
3205 if (UNEXPECTED(p == end)) {
3206 return NULL;
3207 }
3208 p += td[(unsigned char)(p[needle_len])];
3209 }
3210
3211 return NULL;
3212 }
3213 /* }}} */
3214
3215 ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3216 {
3217 unsigned int td[256];
3218 register size_t i;
3219 register const char *p;
3220
3221 if (needle_len == 0 || (end - haystack) < needle_len) {
3222 return NULL;
3223 }
3224
3225 zend_memnstr_ex_pre(td, needle, needle_len, 1);
3226
3227 p = end;
3228 p -= needle_len;
3229
3230 while (p >= haystack) {
3231 for (i = 0; i < needle_len; i++) {
3232 if (needle[i] != p[i]) {
3233 break;
3234 }
3235 }
3236
3237 if (i == needle_len) {
3238 return (const char *)p;
3239 }
3240
3241 if (UNEXPECTED(p == haystack)) {
3242 return NULL;
3243 }
3244
3245 p -= td[(unsigned char)(p[-1])];
3246 }
3247
3248 return NULL;
3249 }
3250 /* }}} */
3251
3252 #if !ZEND_DVAL_TO_LVAL_CAST_OK
3253 # if SIZEOF_ZEND_LONG == 4
3254 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
3255 {
3256 double two_pow_32 = pow(2., 32.),
3257 dmod;
3258
3259 dmod = fmod(d, two_pow_32);
3260 if (dmod < 0) {
3261 /* we're going to make this number positive; call ceil()
3262 * to simulate rounding towards 0 of the negative number */
3263 dmod = ceil(dmod) + two_pow_32;
3264 }
3265 return (zend_long)(zend_ulong)dmod;
3266 }
3267 #else
3268 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
3269 {
3270 double two_pow_64 = pow(2., 64.),
3271 dmod;
3272
3273 dmod = fmod(d, two_pow_64);
3274 if (dmod < 0) {
3275 /* no need to call ceil; original double must have had no
3276 * fractional part, hence dmod does not have one either */
3277 dmod += two_pow_64;
3278 }
3279 return (zend_long)(zend_ulong)dmod;
3280 }
3281 #endif
3282 #endif
3283