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