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