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