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