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 (ZEND_STD_BUILD_OBJECT_PROPERTIES_ARRAY_COMPATIBLE(op)) {
816 /* Optimized version without rebuilding properties HashTable */
817 HashTable *ht = zend_std_build_object_properties_array(Z_OBJ_P(op));
818 OBJ_RELEASE(Z_OBJ_P(op));
819 ZVAL_ARR(op, ht);
820 } else {
821 HashTable *obj_ht = zend_get_properties_for(op, ZEND_PROP_PURPOSE_ARRAY_CAST);
822 if (obj_ht) {
823 HashTable *new_obj_ht = zend_proptable_to_symtable(obj_ht,
824 (Z_OBJCE_P(op)->default_properties_count ||
825 Z_OBJ_P(op)->handlers != &std_object_handlers ||
826 GC_IS_RECURSIVE(obj_ht)));
827 zval_ptr_dtor(op);
828 ZVAL_ARR(op, new_obj_ht);
829 zend_release_properties(obj_ht);
830 } else {
831 zval_ptr_dtor(op);
832 /*ZVAL_EMPTY_ARRAY(op);*/
833 array_init(op);
834 }
835 }
836 break;
837 case IS_NULL:
838 /*ZVAL_EMPTY_ARRAY(op);*/
839 array_init(op);
840 break;
841 case IS_REFERENCE:
842 zend_unwrap_reference(op);
843 goto try_again;
844 default:
845 convert_scalar_to_array(op);
846 break;
847 }
848 }
849 /* }}} */
850
convert_to_object(zval * op)851 ZEND_API void ZEND_FASTCALL convert_to_object(zval *op) /* {{{ */
852 {
853 try_again:
854 switch (Z_TYPE_P(op)) {
855 case IS_ARRAY:
856 {
857 HashTable *ht = zend_symtable_to_proptable(Z_ARR_P(op));
858 zend_object *obj;
859
860 if (GC_FLAGS(ht) & IS_ARRAY_IMMUTABLE) {
861 /* TODO: try not to duplicate immutable arrays as well ??? */
862 ht = zend_array_dup(ht);
863 } else if (ht != Z_ARR_P(op)) {
864 zval_ptr_dtor(op);
865 } else {
866 GC_DELREF(ht);
867 }
868 obj = zend_objects_new(zend_standard_class_def);
869 obj->properties = ht;
870 ZVAL_OBJ(op, obj);
871 break;
872 }
873 case IS_OBJECT:
874 break;
875 case IS_NULL:
876 object_init(op);
877 break;
878 case IS_REFERENCE:
879 zend_unwrap_reference(op);
880 goto try_again;
881 default: {
882 zval tmp;
883 ZVAL_COPY_VALUE(&tmp, op);
884 object_init(op);
885 zend_hash_add_new(Z_OBJPROP_P(op), ZSTR_KNOWN(ZEND_STR_SCALAR), &tmp);
886 break;
887 }
888 }
889 }
890 /* }}} */
891
zend_incompatible_double_to_long_error(double d)892 ZEND_API void ZEND_COLD zend_incompatible_double_to_long_error(double d)
893 {
894 zend_error_unchecked(E_DEPRECATED, "Implicit conversion from float %.*H to int loses precision", -1, d);
895 }
zend_incompatible_string_to_long_error(const zend_string * s)896 ZEND_API void ZEND_COLD zend_incompatible_string_to_long_error(const zend_string *s)
897 {
898 zend_error(E_DEPRECATED, "Implicit conversion from float-string \"%s\" to int loses precision", ZSTR_VAL(s));
899 }
900
zval_get_long_func(const zval * op,bool is_strict)901 ZEND_API zend_long ZEND_FASTCALL zval_get_long_func(const zval *op, bool is_strict) /* {{{ */
902 {
903 try_again:
904 switch (Z_TYPE_P(op)) {
905 case IS_UNDEF:
906 case IS_NULL:
907 case IS_FALSE:
908 return 0;
909 case IS_TRUE:
910 return 1;
911 case IS_RESOURCE:
912 return Z_RES_HANDLE_P(op);
913 case IS_LONG:
914 return Z_LVAL_P(op);
915 case IS_DOUBLE: {
916 double dval = Z_DVAL_P(op);
917 zend_long lval = zend_dval_to_lval(dval);
918 if (UNEXPECTED(is_strict)) {
919 if (!zend_is_long_compatible(dval, lval)) {
920 zend_incompatible_double_to_long_error(dval);
921 }
922 }
923 return lval;
924 }
925 case IS_STRING:
926 {
927 uint8_t type;
928 zend_long lval;
929 double dval;
930 if (0 == (type = is_numeric_string(Z_STRVAL_P(op), Z_STRLEN_P(op), &lval, &dval, true))) {
931 return 0;
932 } else if (EXPECTED(type == IS_LONG)) {
933 return lval;
934 } else {
935 /* Previously we used strtol here, not is_numeric_string,
936 * and strtol gives you LONG_MAX/_MIN on overflow.
937 * We use saturating conversion to emulate strtol()'s
938 * behaviour.
939 */
940 /* Most usages are expected to not be (int) casts */
941 lval = zend_dval_to_lval_cap(dval);
942 if (UNEXPECTED(is_strict)) {
943 if (!zend_is_long_compatible(dval, lval)) {
944 zend_incompatible_string_to_long_error(Z_STR_P(op));
945 }
946 }
947 return lval;
948 }
949 }
950 case IS_ARRAY:
951 return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1 : 0;
952 case IS_OBJECT:
953 {
954 zval dst;
955 convert_object_to_type(op, &dst, IS_LONG);
956 if (Z_TYPE(dst) == IS_LONG) {
957 return Z_LVAL(dst);
958 } else {
959 return 1;
960 }
961 }
962 case IS_REFERENCE:
963 op = Z_REFVAL_P(op);
964 goto try_again;
965 EMPTY_SWITCH_DEFAULT_CASE()
966 }
967 return 0;
968 }
969 /* }}} */
970
zval_get_double_func(const zval * op)971 ZEND_API double ZEND_FASTCALL zval_get_double_func(const zval *op) /* {{{ */
972 {
973 try_again:
974 switch (Z_TYPE_P(op)) {
975 case IS_NULL:
976 case IS_FALSE:
977 return 0.0;
978 case IS_TRUE:
979 return 1.0;
980 case IS_RESOURCE:
981 return (double) Z_RES_HANDLE_P(op);
982 case IS_LONG:
983 return (double) Z_LVAL_P(op);
984 case IS_DOUBLE:
985 return Z_DVAL_P(op);
986 case IS_STRING:
987 return zend_strtod(Z_STRVAL_P(op), NULL);
988 case IS_ARRAY:
989 return zend_hash_num_elements(Z_ARRVAL_P(op)) ? 1.0 : 0.0;
990 case IS_OBJECT:
991 {
992 zval dst;
993 convert_object_to_type(op, &dst, IS_DOUBLE);
994
995 if (Z_TYPE(dst) == IS_DOUBLE) {
996 return Z_DVAL(dst);
997 } else {
998 return 1.0;
999 }
1000 }
1001 case IS_REFERENCE:
1002 op = Z_REFVAL_P(op);
1003 goto try_again;
1004 EMPTY_SWITCH_DEFAULT_CASE()
1005 }
1006 return 0.0;
1007 }
1008 /* }}} */
1009
__zval_get_string_func(zval * op,bool try)1010 static zend_always_inline zend_string* __zval_get_string_func(zval *op, bool try) /* {{{ */
1011 {
1012 try_again:
1013 switch (Z_TYPE_P(op)) {
1014 case IS_UNDEF:
1015 case IS_NULL:
1016 case IS_FALSE:
1017 return ZSTR_EMPTY_ALLOC();
1018 case IS_TRUE:
1019 return ZSTR_CHAR('1');
1020 case IS_RESOURCE:
1021 return zend_strpprintf(0, "Resource id #" ZEND_LONG_FMT, (zend_long)Z_RES_HANDLE_P(op));
1022 case IS_LONG:
1023 return zend_long_to_str(Z_LVAL_P(op));
1024 case IS_DOUBLE:
1025 return zend_double_to_str(Z_DVAL_P(op));
1026 case IS_ARRAY:
1027 zend_error(E_WARNING, "Array to string conversion");
1028 return (try && UNEXPECTED(EG(exception))) ?
1029 NULL : ZSTR_KNOWN(ZEND_STR_ARRAY_CAPITALIZED);
1030 case IS_OBJECT: {
1031 zval tmp;
1032 if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), &tmp, IS_STRING) == SUCCESS) {
1033 return Z_STR(tmp);
1034 }
1035 if (!EG(exception)) {
1036 zend_throw_error(NULL, "Object of class %s could not be converted to string", ZSTR_VAL(Z_OBJCE_P(op)->name));
1037 }
1038 return try ? NULL : ZSTR_EMPTY_ALLOC();
1039 }
1040 case IS_REFERENCE:
1041 op = Z_REFVAL_P(op);
1042 goto try_again;
1043 case IS_STRING:
1044 return zend_string_copy(Z_STR_P(op));
1045 EMPTY_SWITCH_DEFAULT_CASE()
1046 }
1047 return NULL;
1048 }
1049 /* }}} */
1050
zval_get_string_func(zval * op)1051 ZEND_API zend_string* ZEND_FASTCALL zval_get_string_func(zval *op) /* {{{ */
1052 {
1053 return __zval_get_string_func(op, 0);
1054 }
1055 /* }}} */
1056
zval_try_get_string_func(zval * op)1057 ZEND_API zend_string* ZEND_FASTCALL zval_try_get_string_func(zval *op) /* {{{ */
1058 {
1059 return __zval_get_string_func(op, 1);
1060 }
1061 /* }}} */
1062
zend_binop_error(const char * operator,zval * op1,zval * op2)1063 static ZEND_COLD zend_never_inline void ZEND_FASTCALL zend_binop_error(const char *operator, zval *op1, zval *op2) /* {{{ */ {
1064 if (EG(exception)) {
1065 return;
1066 }
1067
1068 zend_type_error("Unsupported operand types: %s %s %s",
1069 zend_zval_type_name(op1), operator, zend_zval_type_name(op2));
1070 }
1071 /* }}} */
1072
add_function_array(zval * result,zval * op1,zval * op2)1073 static zend_never_inline void ZEND_FASTCALL add_function_array(zval *result, zval *op1, zval *op2) /* {{{ */
1074 {
1075 if (result == op1 && Z_ARR_P(op1) == Z_ARR_P(op2)) {
1076 /* $a += $a */
1077 return;
1078 }
1079 if (result != op1) {
1080 ZVAL_ARR(result, zend_array_dup(Z_ARR_P(op1)));
1081 } else {
1082 SEPARATE_ARRAY(result);
1083 }
1084 zend_hash_merge(Z_ARRVAL_P(result), Z_ARRVAL_P(op2), zval_add_ref, 0);
1085 }
1086 /* }}} */
1087
add_function_fast(zval * result,zval * op1,zval * op2)1088 static zend_always_inline zend_result add_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1089 {
1090 uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1091
1092 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1093 fast_long_add_function(result, op1, op2);
1094 return SUCCESS;
1095 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1096 ZVAL_DOUBLE(result, Z_DVAL_P(op1) + Z_DVAL_P(op2));
1097 return SUCCESS;
1098 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1099 ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) + Z_DVAL_P(op2));
1100 return SUCCESS;
1101 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1102 ZVAL_DOUBLE(result, Z_DVAL_P(op1) + ((double)Z_LVAL_P(op2)));
1103 return SUCCESS;
1104 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_ARRAY, IS_ARRAY))) {
1105 add_function_array(result, op1, op2);
1106 return SUCCESS;
1107 } else {
1108 return FAILURE;
1109 }
1110 } /* }}} */
1111
add_function_slow(zval * result,zval * op1,zval * op2)1112 static zend_never_inline zend_result ZEND_FASTCALL add_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1113 {
1114 ZVAL_DEREF(op1);
1115 ZVAL_DEREF(op2);
1116 if (add_function_fast(result, op1, op2) == SUCCESS) {
1117 return SUCCESS;
1118 }
1119
1120 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_ADD);
1121
1122 zval op1_copy, op2_copy;
1123 if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1124 || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1125 zend_binop_error("+", op1, op2);
1126 if (result != op1) {
1127 ZVAL_UNDEF(result);
1128 }
1129 return FAILURE;
1130 }
1131
1132 if (result == op1) {
1133 zval_ptr_dtor(result);
1134 }
1135
1136 if (add_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
1137 return SUCCESS;
1138 }
1139
1140 ZEND_ASSERT(0 && "Operation must succeed");
1141 return FAILURE;
1142 } /* }}} */
1143
add_function(zval * result,zval * op1,zval * op2)1144 ZEND_API zend_result ZEND_FASTCALL add_function(zval *result, zval *op1, zval *op2) /* {{{ */
1145 {
1146 if (add_function_fast(result, op1, op2) == SUCCESS) {
1147 return SUCCESS;
1148 } else {
1149 return add_function_slow(result, op1, op2);
1150 }
1151 }
1152 /* }}} */
1153
sub_function_fast(zval * result,zval * op1,zval * op2)1154 static zend_always_inline zend_result sub_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1155 {
1156 uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1157
1158 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1159 fast_long_sub_function(result, op1, op2);
1160 return SUCCESS;
1161 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1162 ZVAL_DOUBLE(result, Z_DVAL_P(op1) - Z_DVAL_P(op2));
1163 return SUCCESS;
1164 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1165 ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) - Z_DVAL_P(op2));
1166 return SUCCESS;
1167 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1168 ZVAL_DOUBLE(result, Z_DVAL_P(op1) - ((double)Z_LVAL_P(op2)));
1169 return SUCCESS;
1170 } else {
1171 return FAILURE;
1172 }
1173 }
1174 /* }}} */
1175
sub_function_slow(zval * result,zval * op1,zval * op2)1176 static zend_never_inline zend_result ZEND_FASTCALL sub_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1177 {
1178 ZVAL_DEREF(op1);
1179 ZVAL_DEREF(op2);
1180 if (sub_function_fast(result, op1, op2) == SUCCESS) {
1181 return SUCCESS;
1182 }
1183
1184 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_SUB);
1185
1186 zval op1_copy, op2_copy;
1187 if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1188 || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1189 zend_binop_error("-", op1, op2);
1190 if (result != op1) {
1191 ZVAL_UNDEF(result);
1192 }
1193 return FAILURE;
1194 }
1195
1196 if (result == op1) {
1197 zval_ptr_dtor(result);
1198 }
1199
1200 if (sub_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
1201 return SUCCESS;
1202 }
1203
1204 ZEND_ASSERT(0 && "Operation must succeed");
1205 return FAILURE;
1206 }
1207 /* }}} */
1208
sub_function(zval * result,zval * op1,zval * op2)1209 ZEND_API zend_result ZEND_FASTCALL sub_function(zval *result, zval *op1, zval *op2) /* {{{ */
1210 {
1211 if (sub_function_fast(result, op1, op2) == SUCCESS) {
1212 return SUCCESS;
1213 } else {
1214 return sub_function_slow(result, op1, op2);
1215 }
1216 }
1217 /* }}} */
1218
mul_function_fast(zval * result,zval * op1,zval * op2)1219 static zend_always_inline zend_result mul_function_fast(zval *result, zval *op1, zval *op2) /* {{{ */
1220 {
1221 uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1222
1223 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1224 zend_long overflow;
1225 ZEND_SIGNED_MULTIPLY_LONG(
1226 Z_LVAL_P(op1), Z_LVAL_P(op2),
1227 Z_LVAL_P(result), Z_DVAL_P(result), overflow);
1228 Z_TYPE_INFO_P(result) = overflow ? IS_DOUBLE : IS_LONG;
1229 return SUCCESS;
1230 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1231 ZVAL_DOUBLE(result, Z_DVAL_P(op1) * Z_DVAL_P(op2));
1232 return SUCCESS;
1233 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1234 ZVAL_DOUBLE(result, ((double)Z_LVAL_P(op1)) * Z_DVAL_P(op2));
1235 return SUCCESS;
1236 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1237 ZVAL_DOUBLE(result, Z_DVAL_P(op1) * ((double)Z_LVAL_P(op2)));
1238 return SUCCESS;
1239 } else {
1240 return FAILURE;
1241 }
1242 }
1243 /* }}} */
1244
mul_function_slow(zval * result,zval * op1,zval * op2)1245 static zend_never_inline zend_result ZEND_FASTCALL mul_function_slow(zval *result, zval *op1, zval *op2) /* {{{ */
1246 {
1247 ZVAL_DEREF(op1);
1248 ZVAL_DEREF(op2);
1249 if (mul_function_fast(result, op1, op2) == SUCCESS) {
1250 return SUCCESS;
1251 }
1252
1253 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_MUL);
1254
1255 zval op1_copy, op2_copy;
1256 if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1257 || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1258 zend_binop_error("*", op1, op2);
1259 if (result != op1) {
1260 ZVAL_UNDEF(result);
1261 }
1262 return FAILURE;
1263 }
1264
1265 if (result == op1) {
1266 zval_ptr_dtor(result);
1267 }
1268
1269 if (mul_function_fast(result, &op1_copy, &op2_copy) == SUCCESS) {
1270 return SUCCESS;
1271 }
1272
1273 ZEND_ASSERT(0 && "Operation must succeed");
1274 return FAILURE;
1275 }
1276 /* }}} */
1277
mul_function(zval * result,zval * op1,zval * op2)1278 ZEND_API zend_result ZEND_FASTCALL mul_function(zval *result, zval *op1, zval *op2) /* {{{ */
1279 {
1280 if (mul_function_fast(result, op1, op2) == SUCCESS) {
1281 return SUCCESS;
1282 } else {
1283 return mul_function_slow(result, op1, op2);
1284 }
1285 }
1286 /* }}} */
1287
zend_power_base_0_exponent_lt_0_error(void)1288 static void ZEND_COLD zend_power_base_0_exponent_lt_0_error(void)
1289 {
1290 zend_error(E_DEPRECATED, "Power of base 0 and negative exponent is deprecated");
1291 }
1292
safe_pow(double base,double exponent)1293 static double safe_pow(double base, double exponent)
1294 {
1295 if (UNEXPECTED(base == 0.0 && exponent < 0.0)) {
1296 zend_power_base_0_exponent_lt_0_error();
1297 }
1298
1299 return pow(base, exponent);
1300 }
1301
pow_function_base(zval * result,zval * op1,zval * op2)1302 static zend_result ZEND_FASTCALL pow_function_base(zval *result, zval *op1, zval *op2) /* {{{ */
1303 {
1304 uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1305
1306 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1307 if (Z_LVAL_P(op2) >= 0) {
1308 zend_long l1 = 1, l2 = Z_LVAL_P(op1), i = Z_LVAL_P(op2);
1309
1310 if (i == 0) {
1311 ZVAL_LONG(result, 1L);
1312 return SUCCESS;
1313 } else if (l2 == 0) {
1314 ZVAL_LONG(result, 0);
1315 return SUCCESS;
1316 }
1317
1318 while (i >= 1) {
1319 zend_long overflow;
1320 double dval = 0.0;
1321
1322 if (i % 2) {
1323 --i;
1324 ZEND_SIGNED_MULTIPLY_LONG(l1, l2, l1, dval, overflow);
1325 if (overflow) {
1326 ZVAL_DOUBLE(result, dval * safe_pow(l2, i));
1327 return SUCCESS;
1328 }
1329 } else {
1330 i /= 2;
1331 ZEND_SIGNED_MULTIPLY_LONG(l2, l2, l2, dval, overflow);
1332 if (overflow) {
1333 ZVAL_DOUBLE(result, (double)l1 * safe_pow(dval, i));
1334 return SUCCESS;
1335 }
1336 }
1337 }
1338 /* i == 0 */
1339 ZVAL_LONG(result, l1);
1340 } else {
1341 ZVAL_DOUBLE(result, safe_pow((double)Z_LVAL_P(op1), (double)Z_LVAL_P(op2)));
1342 }
1343 return SUCCESS;
1344 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1345 ZVAL_DOUBLE(result, safe_pow(Z_DVAL_P(op1), Z_DVAL_P(op2)));
1346 return SUCCESS;
1347 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1348 ZVAL_DOUBLE(result, safe_pow((double)Z_LVAL_P(op1), Z_DVAL_P(op2)));
1349 return SUCCESS;
1350 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1351 ZVAL_DOUBLE(result, safe_pow(Z_DVAL_P(op1), (double)Z_LVAL_P(op2)));
1352 return SUCCESS;
1353 } else {
1354 return FAILURE;
1355 }
1356 }
1357 /* }}} */
1358
pow_function(zval * result,zval * op1,zval * op2)1359 ZEND_API zend_result ZEND_FASTCALL pow_function(zval *result, zval *op1, zval *op2) /* {{{ */
1360 {
1361 ZVAL_DEREF(op1);
1362 ZVAL_DEREF(op2);
1363 if (pow_function_base(result, op1, op2) == SUCCESS) {
1364 return SUCCESS;
1365 }
1366
1367 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_POW);
1368
1369 zval op1_copy, op2_copy;
1370 if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1371 || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1372 zend_binop_error("**", op1, op2);
1373 if (result != op1) {
1374 ZVAL_UNDEF(result);
1375 }
1376 return FAILURE;
1377 }
1378
1379 if (result == op1) {
1380 zval_ptr_dtor(result);
1381 }
1382
1383 if (pow_function_base(result, &op1_copy, &op2_copy) == SUCCESS) {
1384 return SUCCESS;
1385 }
1386
1387 ZEND_ASSERT(0 && "Operation must succeed");
1388 return FAILURE;
1389 }
1390 /* }}} */
1391
1392 /* Returns SUCCESS/TYPES_NOT_HANDLED/DIV_BY_ZERO */
1393 #define TYPES_NOT_HANDLED 1
1394 #define DIV_BY_ZERO 2
div_function_base(zval * result,zval * op1,zval * op2)1395 static int ZEND_FASTCALL div_function_base(zval *result, zval *op1, zval *op2) /* {{{ */
1396 {
1397 uint8_t type_pair = TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2));
1398
1399 if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_LONG))) {
1400 if (Z_LVAL_P(op2) == 0) {
1401 return DIV_BY_ZERO;
1402 } else if (Z_LVAL_P(op2) == -1 && Z_LVAL_P(op1) == ZEND_LONG_MIN) {
1403 /* Prevent overflow error/crash */
1404 ZVAL_DOUBLE(result, (double) ZEND_LONG_MIN / -1);
1405 return SUCCESS;
1406 }
1407 if (Z_LVAL_P(op1) % Z_LVAL_P(op2) == 0) { /* integer */
1408 ZVAL_LONG(result, Z_LVAL_P(op1) / Z_LVAL_P(op2));
1409 } else {
1410 ZVAL_DOUBLE(result, ((double) Z_LVAL_P(op1)) / Z_LVAL_P(op2));
1411 }
1412 return SUCCESS;
1413 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_DOUBLE))) {
1414 if (Z_DVAL_P(op2) == 0) {
1415 return DIV_BY_ZERO;
1416 }
1417 ZVAL_DOUBLE(result, Z_DVAL_P(op1) / Z_DVAL_P(op2));
1418 return SUCCESS;
1419 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_DOUBLE, IS_LONG))) {
1420 if (Z_LVAL_P(op2) == 0) {
1421 return DIV_BY_ZERO;
1422 }
1423 ZVAL_DOUBLE(result, Z_DVAL_P(op1) / (double)Z_LVAL_P(op2));
1424 return SUCCESS;
1425 } else if (EXPECTED(type_pair == TYPE_PAIR(IS_LONG, IS_DOUBLE))) {
1426 if (Z_DVAL_P(op2) == 0) {
1427 return DIV_BY_ZERO;
1428 }
1429 ZVAL_DOUBLE(result, (double)Z_LVAL_P(op1) / Z_DVAL_P(op2));
1430 return SUCCESS;
1431 } else {
1432 return TYPES_NOT_HANDLED;
1433 }
1434 }
1435 /* }}} */
1436
div_function(zval * result,zval * op1,zval * op2)1437 ZEND_API zend_result ZEND_FASTCALL div_function(zval *result, zval *op1, zval *op2) /* {{{ */
1438 {
1439 ZVAL_DEREF(op1);
1440 ZVAL_DEREF(op2);
1441
1442 int retval = div_function_base(result, op1, op2);
1443 if (EXPECTED(retval == SUCCESS)) {
1444 return SUCCESS;
1445 }
1446
1447 if (UNEXPECTED(retval == DIV_BY_ZERO)) {
1448 goto div_by_zero;
1449 }
1450
1451 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_DIV);
1452
1453 zval result_copy, op1_copy, op2_copy;
1454 if (UNEXPECTED(zendi_try_convert_scalar_to_number(op1, &op1_copy) == FAILURE)
1455 || UNEXPECTED(zendi_try_convert_scalar_to_number(op2, &op2_copy) == FAILURE)) {
1456 zend_binop_error("/", op1, op2);
1457 if (result != op1) {
1458 ZVAL_UNDEF(result);
1459 }
1460 return FAILURE;
1461 }
1462
1463 retval = div_function_base(&result_copy, &op1_copy, &op2_copy);
1464 if (retval == SUCCESS) {
1465 if (result == op1) {
1466 zval_ptr_dtor(result);
1467 }
1468 ZVAL_COPY_VALUE(result, &result_copy);
1469 return SUCCESS;
1470 }
1471
1472 div_by_zero:
1473 ZEND_ASSERT(retval == DIV_BY_ZERO && "TYPES_NOT_HANDLED should not occur here");
1474 if (result != op1) {
1475 ZVAL_UNDEF(result);
1476 }
1477 zend_throw_error(zend_ce_division_by_zero_error, "Division by zero");
1478 return FAILURE;
1479 }
1480 /* }}} */
1481
mod_function(zval * result,zval * op1,zval * op2)1482 ZEND_API zend_result ZEND_FASTCALL mod_function(zval *result, zval *op1, zval *op2) /* {{{ */
1483 {
1484 zend_long op1_lval, op2_lval;
1485
1486 convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_MOD, "%");
1487
1488 if (op2_lval == 0) {
1489 /* modulus by zero */
1490 if (EG(current_execute_data) && !CG(in_compilation)) {
1491 zend_throw_exception_ex(zend_ce_division_by_zero_error, 0, "Modulo by zero");
1492 } else {
1493 zend_error_noreturn(E_ERROR, "Modulo by zero");
1494 }
1495 if (op1 != result) {
1496 ZVAL_UNDEF(result);
1497 }
1498 return FAILURE;
1499 }
1500
1501 if (op1 == result) {
1502 zval_ptr_dtor(result);
1503 }
1504
1505 if (op2_lval == -1) {
1506 /* Prevent overflow error/crash if op1==LONG_MIN */
1507 ZVAL_LONG(result, 0);
1508 return SUCCESS;
1509 }
1510
1511 ZVAL_LONG(result, op1_lval % op2_lval);
1512 return SUCCESS;
1513 }
1514 /* }}} */
1515
boolean_xor_function(zval * result,zval * op1,zval * op2)1516 ZEND_API zend_result ZEND_FASTCALL boolean_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1517 {
1518 int op1_val, op2_val;
1519
1520 do {
1521 if (Z_TYPE_P(op1) == IS_FALSE) {
1522 op1_val = 0;
1523 } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1524 op1_val = 1;
1525 } else {
1526 if (Z_ISREF_P(op1)) {
1527 op1 = Z_REFVAL_P(op1);
1528 if (Z_TYPE_P(op1) == IS_FALSE) {
1529 op1_val = 0;
1530 break;
1531 } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1532 op1_val = 1;
1533 break;
1534 }
1535 }
1536 ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BOOL_XOR);
1537 op1_val = zval_is_true(op1);
1538 }
1539 } while (0);
1540 do {
1541 if (Z_TYPE_P(op2) == IS_FALSE) {
1542 op2_val = 0;
1543 } else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1544 op2_val = 1;
1545 } else {
1546 if (Z_ISREF_P(op2)) {
1547 op2 = Z_REFVAL_P(op2);
1548 if (Z_TYPE_P(op2) == IS_FALSE) {
1549 op2_val = 0;
1550 break;
1551 } else if (EXPECTED(Z_TYPE_P(op2) == IS_TRUE)) {
1552 op2_val = 1;
1553 break;
1554 }
1555 }
1556 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BOOL_XOR);
1557 op2_val = zval_is_true(op2);
1558 }
1559 } while (0);
1560
1561 ZVAL_BOOL(result, op1_val ^ op2_val);
1562 return SUCCESS;
1563 }
1564 /* }}} */
1565
boolean_not_function(zval * result,zval * op1)1566 ZEND_API zend_result ZEND_FASTCALL boolean_not_function(zval *result, zval *op1) /* {{{ */
1567 {
1568 if (Z_TYPE_P(op1) < IS_TRUE) {
1569 ZVAL_TRUE(result);
1570 } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1571 ZVAL_FALSE(result);
1572 } else {
1573 if (Z_ISREF_P(op1)) {
1574 op1 = Z_REFVAL_P(op1);
1575 if (Z_TYPE_P(op1) < IS_TRUE) {
1576 ZVAL_TRUE(result);
1577 return SUCCESS;
1578 } else if (EXPECTED(Z_TYPE_P(op1) == IS_TRUE)) {
1579 ZVAL_FALSE(result);
1580 return SUCCESS;
1581 }
1582 }
1583 ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BOOL_NOT);
1584
1585 ZVAL_BOOL(result, !zval_is_true(op1));
1586 }
1587 return SUCCESS;
1588 }
1589 /* }}} */
1590
bitwise_not_function(zval * result,zval * op1)1591 ZEND_API zend_result ZEND_FASTCALL bitwise_not_function(zval *result, zval *op1) /* {{{ */
1592 {
1593 try_again:
1594 switch (Z_TYPE_P(op1)) {
1595 case IS_LONG:
1596 ZVAL_LONG(result, ~Z_LVAL_P(op1));
1597 return SUCCESS;
1598 case IS_DOUBLE: {
1599 zend_long lval = zend_dval_to_lval(Z_DVAL_P(op1));
1600 if (!zend_is_long_compatible(Z_DVAL_P(op1), lval)) {
1601 zend_incompatible_double_to_long_error(Z_DVAL_P(op1));
1602 if (EG(exception)) {
1603 if (result != op1) {
1604 ZVAL_UNDEF(result);
1605 }
1606 return FAILURE;
1607 }
1608 }
1609 ZVAL_LONG(result, ~lval);
1610 return SUCCESS;
1611 }
1612 case IS_STRING: {
1613 size_t i;
1614
1615 if (Z_STRLEN_P(op1) == 1) {
1616 zend_uchar not = (zend_uchar) ~*Z_STRVAL_P(op1);
1617 ZVAL_CHAR(result, not);
1618 } else {
1619 ZVAL_NEW_STR(result, zend_string_alloc(Z_STRLEN_P(op1), 0));
1620 for (i = 0; i < Z_STRLEN_P(op1); i++) {
1621 Z_STRVAL_P(result)[i] = ~Z_STRVAL_P(op1)[i];
1622 }
1623 Z_STRVAL_P(result)[i] = 0;
1624 }
1625 return SUCCESS;
1626 }
1627 case IS_REFERENCE:
1628 op1 = Z_REFVAL_P(op1);
1629 goto try_again;
1630 default:
1631 ZEND_TRY_UNARY_OBJECT_OPERATION(ZEND_BW_NOT);
1632
1633 if (result != op1) {
1634 ZVAL_UNDEF(result);
1635 }
1636 zend_type_error("Cannot perform bitwise not on %s", zend_zval_value_name(op1));
1637 return FAILURE;
1638 }
1639 }
1640 /* }}} */
1641
bitwise_or_function(zval * result,zval * op1,zval * op2)1642 ZEND_API zend_result ZEND_FASTCALL bitwise_or_function(zval *result, zval *op1, zval *op2) /* {{{ */
1643 {
1644 zend_long op1_lval, op2_lval;
1645
1646 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1647 ZVAL_LONG(result, Z_LVAL_P(op1) | Z_LVAL_P(op2));
1648 return SUCCESS;
1649 }
1650
1651 ZVAL_DEREF(op1);
1652 ZVAL_DEREF(op2);
1653
1654 if (Z_TYPE_P(op1) == IS_STRING && EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1655 zval *longer, *shorter;
1656 zend_string *str;
1657 size_t i;
1658
1659 if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1660 if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1661 zend_uchar or = (zend_uchar) (*Z_STRVAL_P(op1) | *Z_STRVAL_P(op2));
1662 if (result==op1) {
1663 zval_ptr_dtor_str(result);
1664 }
1665 ZVAL_CHAR(result, or);
1666 return SUCCESS;
1667 }
1668 longer = op1;
1669 shorter = op2;
1670 } else {
1671 longer = op2;
1672 shorter = op1;
1673 }
1674
1675 str = zend_string_alloc(Z_STRLEN_P(longer), 0);
1676 for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1677 ZSTR_VAL(str)[i] = Z_STRVAL_P(longer)[i] | Z_STRVAL_P(shorter)[i];
1678 }
1679 memcpy(ZSTR_VAL(str) + i, Z_STRVAL_P(longer) + i, Z_STRLEN_P(longer) - i + 1);
1680 if (result==op1) {
1681 zval_ptr_dtor_str(result);
1682 }
1683 ZVAL_NEW_STR(result, str);
1684 return SUCCESS;
1685 }
1686
1687 if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1688 bool failed;
1689 ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_OR);
1690 op1_lval = zendi_try_get_long(op1, &failed);
1691 if (UNEXPECTED(failed)) {
1692 zend_binop_error("|", op1, op2);
1693 if (result != op1) {
1694 ZVAL_UNDEF(result);
1695 }
1696 return FAILURE;
1697 }
1698 } else {
1699 op1_lval = Z_LVAL_P(op1);
1700 }
1701 if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1702 bool failed;
1703 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_OR);
1704 op2_lval = zendi_try_get_long(op2, &failed);
1705 if (UNEXPECTED(failed)) {
1706 zend_binop_error("|", op1, op2);
1707 if (result != op1) {
1708 ZVAL_UNDEF(result);
1709 }
1710 return FAILURE;
1711 }
1712 } else {
1713 op2_lval = Z_LVAL_P(op2);
1714 }
1715
1716 if (op1 == result) {
1717 zval_ptr_dtor(result);
1718 }
1719 ZVAL_LONG(result, op1_lval | op2_lval);
1720 return SUCCESS;
1721 }
1722 /* }}} */
1723
bitwise_and_function(zval * result,zval * op1,zval * op2)1724 ZEND_API zend_result ZEND_FASTCALL bitwise_and_function(zval *result, zval *op1, zval *op2) /* {{{ */
1725 {
1726 zend_long op1_lval, op2_lval;
1727
1728 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1729 ZVAL_LONG(result, Z_LVAL_P(op1) & Z_LVAL_P(op2));
1730 return SUCCESS;
1731 }
1732
1733 ZVAL_DEREF(op1);
1734 ZVAL_DEREF(op2);
1735
1736 if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1737 zval *longer, *shorter;
1738 zend_string *str;
1739 size_t i;
1740
1741 if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1742 if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1743 zend_uchar and = (zend_uchar) (*Z_STRVAL_P(op1) & *Z_STRVAL_P(op2));
1744 if (result==op1) {
1745 zval_ptr_dtor_str(result);
1746 }
1747 ZVAL_CHAR(result, and);
1748 return SUCCESS;
1749 }
1750 longer = op1;
1751 shorter = op2;
1752 } else {
1753 longer = op2;
1754 shorter = op1;
1755 }
1756
1757 str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1758 for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1759 ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] & Z_STRVAL_P(longer)[i];
1760 }
1761 ZSTR_VAL(str)[i] = 0;
1762 if (result==op1) {
1763 zval_ptr_dtor_str(result);
1764 }
1765 ZVAL_NEW_STR(result, str);
1766 return SUCCESS;
1767 }
1768
1769 if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1770 bool failed;
1771 ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_AND);
1772 op1_lval = zendi_try_get_long(op1, &failed);
1773 if (UNEXPECTED(failed)) {
1774 zend_binop_error("&", op1, op2);
1775 if (result != op1) {
1776 ZVAL_UNDEF(result);
1777 }
1778 return FAILURE;
1779 }
1780 } else {
1781 op1_lval = Z_LVAL_P(op1);
1782 }
1783 if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1784 bool failed;
1785 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_AND);
1786 op2_lval = zendi_try_get_long(op2, &failed);
1787 if (UNEXPECTED(failed)) {
1788 zend_binop_error("&", op1, op2);
1789 if (result != op1) {
1790 ZVAL_UNDEF(result);
1791 }
1792 return FAILURE;
1793 }
1794 } else {
1795 op2_lval = Z_LVAL_P(op2);
1796 }
1797
1798 if (op1 == result) {
1799 zval_ptr_dtor(result);
1800 }
1801 ZVAL_LONG(result, op1_lval & op2_lval);
1802 return SUCCESS;
1803 }
1804 /* }}} */
1805
bitwise_xor_function(zval * result,zval * op1,zval * op2)1806 ZEND_API zend_result ZEND_FASTCALL bitwise_xor_function(zval *result, zval *op1, zval *op2) /* {{{ */
1807 {
1808 zend_long op1_lval, op2_lval;
1809
1810 if (EXPECTED(Z_TYPE_P(op1) == IS_LONG) && EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
1811 ZVAL_LONG(result, Z_LVAL_P(op1) ^ Z_LVAL_P(op2));
1812 return SUCCESS;
1813 }
1814
1815 ZVAL_DEREF(op1);
1816 ZVAL_DEREF(op2);
1817
1818 if (Z_TYPE_P(op1) == IS_STRING && Z_TYPE_P(op2) == IS_STRING) {
1819 zval *longer, *shorter;
1820 zend_string *str;
1821 size_t i;
1822
1823 if (EXPECTED(Z_STRLEN_P(op1) >= Z_STRLEN_P(op2))) {
1824 if (EXPECTED(Z_STRLEN_P(op1) == Z_STRLEN_P(op2)) && Z_STRLEN_P(op1) == 1) {
1825 zend_uchar xor = (zend_uchar) (*Z_STRVAL_P(op1) ^ *Z_STRVAL_P(op2));
1826 if (result==op1) {
1827 zval_ptr_dtor_str(result);
1828 }
1829 ZVAL_CHAR(result, xor);
1830 return SUCCESS;
1831 }
1832 longer = op1;
1833 shorter = op2;
1834 } else {
1835 longer = op2;
1836 shorter = op1;
1837 }
1838
1839 str = zend_string_alloc(Z_STRLEN_P(shorter), 0);
1840 for (i = 0; i < Z_STRLEN_P(shorter); i++) {
1841 ZSTR_VAL(str)[i] = Z_STRVAL_P(shorter)[i] ^ Z_STRVAL_P(longer)[i];
1842 }
1843 ZSTR_VAL(str)[i] = 0;
1844 if (result==op1) {
1845 zval_ptr_dtor_str(result);
1846 }
1847 ZVAL_NEW_STR(result, str);
1848 return SUCCESS;
1849 }
1850
1851 if (UNEXPECTED(Z_TYPE_P(op1) != IS_LONG)) {
1852 bool failed;
1853 ZEND_TRY_BINARY_OP1_OBJECT_OPERATION(ZEND_BW_XOR);
1854 op1_lval = zendi_try_get_long(op1, &failed);
1855 if (UNEXPECTED(failed)) {
1856 zend_binop_error("^", op1, op2);
1857 if (result != op1) {
1858 ZVAL_UNDEF(result);
1859 }
1860 return FAILURE;
1861 }
1862 } else {
1863 op1_lval = Z_LVAL_P(op1);
1864 }
1865 if (UNEXPECTED(Z_TYPE_P(op2) != IS_LONG)) {
1866 bool failed;
1867 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_BW_XOR);
1868 op2_lval = zendi_try_get_long(op2, &failed);
1869 if (UNEXPECTED(failed)) {
1870 zend_binop_error("^", op1, op2);
1871 if (result != op1) {
1872 ZVAL_UNDEF(result);
1873 }
1874 return FAILURE;
1875 }
1876 } else {
1877 op2_lval = Z_LVAL_P(op2);
1878 }
1879
1880 if (op1 == result) {
1881 zval_ptr_dtor(result);
1882 }
1883 ZVAL_LONG(result, op1_lval ^ op2_lval);
1884 return SUCCESS;
1885 }
1886 /* }}} */
1887
shift_left_function(zval * result,zval * op1,zval * op2)1888 ZEND_API zend_result ZEND_FASTCALL shift_left_function(zval *result, zval *op1, zval *op2) /* {{{ */
1889 {
1890 zend_long op1_lval, op2_lval;
1891
1892 convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SL, "<<");
1893
1894 /* prevent wrapping quirkiness on some processors where << 64 + x == << x */
1895 if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1896 if (EXPECTED(op2_lval > 0)) {
1897 if (op1 == result) {
1898 zval_ptr_dtor(result);
1899 }
1900 ZVAL_LONG(result, 0);
1901 return SUCCESS;
1902 } else {
1903 if (EG(current_execute_data) && !CG(in_compilation)) {
1904 zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1905 } else {
1906 zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1907 }
1908 if (op1 != result) {
1909 ZVAL_UNDEF(result);
1910 }
1911 return FAILURE;
1912 }
1913 }
1914
1915 if (op1 == result) {
1916 zval_ptr_dtor(result);
1917 }
1918
1919 /* Perform shift on unsigned numbers to get well-defined wrap behavior. */
1920 ZVAL_LONG(result, (zend_long) ((zend_ulong) op1_lval << op2_lval));
1921 return SUCCESS;
1922 }
1923 /* }}} */
1924
shift_right_function(zval * result,zval * op1,zval * op2)1925 ZEND_API zend_result ZEND_FASTCALL shift_right_function(zval *result, zval *op1, zval *op2) /* {{{ */
1926 {
1927 zend_long op1_lval, op2_lval;
1928
1929 convert_op1_op2_long(op1, op1_lval, op2, op2_lval, result, ZEND_SR, ">>");
1930
1931 /* prevent wrapping quirkiness on some processors where >> 64 + x == >> x */
1932 if (UNEXPECTED((zend_ulong)op2_lval >= SIZEOF_ZEND_LONG * 8)) {
1933 if (EXPECTED(op2_lval > 0)) {
1934 if (op1 == result) {
1935 zval_ptr_dtor(result);
1936 }
1937 ZVAL_LONG(result, (op1_lval < 0) ? -1 : 0);
1938 return SUCCESS;
1939 } else {
1940 if (EG(current_execute_data) && !CG(in_compilation)) {
1941 zend_throw_exception_ex(zend_ce_arithmetic_error, 0, "Bit shift by negative number");
1942 } else {
1943 zend_error_noreturn(E_ERROR, "Bit shift by negative number");
1944 }
1945 if (op1 != result) {
1946 ZVAL_UNDEF(result);
1947 }
1948 return FAILURE;
1949 }
1950 }
1951
1952 if (op1 == result) {
1953 zval_ptr_dtor(result);
1954 }
1955
1956 ZVAL_LONG(result, op1_lval >> op2_lval);
1957 return SUCCESS;
1958 }
1959 /* }}} */
1960
concat_function(zval * result,zval * op1,zval * op2)1961 ZEND_API zend_result ZEND_FASTCALL concat_function(zval *result, zval *op1, zval *op2) /* {{{ */
1962 {
1963 zval *orig_op1 = op1;
1964 zend_string *op1_string, *op2_string;
1965 bool free_op1_string = false;
1966 bool free_op2_string = false;
1967
1968 do {
1969 if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
1970 op1_string = Z_STR_P(op1);
1971 } else {
1972 if (Z_ISREF_P(op1)) {
1973 op1 = Z_REFVAL_P(op1);
1974 if (Z_TYPE_P(op1) == IS_STRING) {
1975 op1_string = Z_STR_P(op1);
1976 break;
1977 }
1978 }
1979 ZEND_TRY_BINARY_OBJECT_OPERATION(ZEND_CONCAT);
1980 op1_string = zval_get_string_func(op1);
1981 if (UNEXPECTED(EG(exception))) {
1982 zend_string_release(op1_string);
1983 if (orig_op1 != result) {
1984 ZVAL_UNDEF(result);
1985 }
1986 return FAILURE;
1987 }
1988 free_op1_string = true;
1989 if (result == op1) {
1990 if (UNEXPECTED(op1 == op2)) {
1991 op2_string = op1_string;
1992 goto has_op2_string;
1993 }
1994 }
1995 }
1996 } while (0);
1997 do {
1998 if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
1999 op2_string = Z_STR_P(op2);
2000 } else {
2001 if (Z_ISREF_P(op2)) {
2002 op2 = Z_REFVAL_P(op2);
2003 if (Z_TYPE_P(op2) == IS_STRING) {
2004 op2_string = Z_STR_P(op2);
2005 break;
2006 }
2007 }
2008 /* hold an additional reference because a userland function could free this */
2009 if (!free_op1_string) {
2010 op1_string = zend_string_copy(op1_string);
2011 free_op1_string = true;
2012 }
2013 ZEND_TRY_BINARY_OP2_OBJECT_OPERATION(ZEND_CONCAT);
2014 op2_string = zval_get_string_func(op2);
2015 if (UNEXPECTED(EG(exception))) {
2016 zend_string_release(op1_string);
2017 zend_string_release(op2_string);
2018 if (orig_op1 != result) {
2019 ZVAL_UNDEF(result);
2020 }
2021 return FAILURE;
2022 }
2023 free_op2_string = true;
2024 }
2025 } while (0);
2026
2027 has_op2_string:;
2028 if (UNEXPECTED(ZSTR_LEN(op1_string) == 0)) {
2029 if (EXPECTED(result != op2 || Z_TYPE_P(result) != IS_STRING)) {
2030 if (result == orig_op1) {
2031 i_zval_ptr_dtor(result);
2032 }
2033 if (free_op2_string) {
2034 /* transfer ownership of op2_string */
2035 ZVAL_STR(result, op2_string);
2036 free_op2_string = false;
2037 } else {
2038 ZVAL_STR_COPY(result, op2_string);
2039 }
2040 }
2041 } else if (UNEXPECTED(ZSTR_LEN(op2_string) == 0)) {
2042 if (EXPECTED(result != op1 || Z_TYPE_P(result) != IS_STRING)) {
2043 if (result == orig_op1) {
2044 i_zval_ptr_dtor(result);
2045 }
2046 if (free_op1_string) {
2047 /* transfer ownership of op1_string */
2048 ZVAL_STR(result, op1_string);
2049 free_op1_string = false;
2050 } else {
2051 ZVAL_STR_COPY(result, op1_string);
2052 }
2053 }
2054 } else {
2055 size_t op1_len = ZSTR_LEN(op1_string);
2056 size_t op2_len = ZSTR_LEN(op2_string);
2057 size_t result_len = op1_len + op2_len;
2058 zend_string *result_str;
2059 uint32_t flags = ZSTR_GET_COPYABLE_CONCAT_PROPERTIES_BOTH(op1_string, op2_string);
2060
2061 if (UNEXPECTED(op1_len > ZSTR_MAX_LEN - op2_len)) {
2062 if (free_op1_string) zend_string_release(op1_string);
2063 if (free_op2_string) zend_string_release(op2_string);
2064 zend_throw_error(NULL, "String size overflow");
2065 if (orig_op1 != result) {
2066 ZVAL_UNDEF(result);
2067 }
2068 return FAILURE;
2069 }
2070
2071 if (result == op1) {
2072 /* Destroy the old result first to drop the refcount, such that $x .= ...; may happen in-place. */
2073 if (free_op1_string) {
2074 /* op1_string will be used as the result, so we should not free it */
2075 i_zval_ptr_dtor(result);
2076 /* Set it to NULL in case that the extension will throw an out-of-memory error.
2077 * Otherwise the shutdown sequence will try to free this again. */
2078 ZVAL_NULL(result);
2079 free_op1_string = false;
2080 }
2081 /* special case, perform operations on result */
2082 result_str = zend_string_extend(op1_string, result_len, 0);
2083 /* account for the case where result_str == op1_string == op2_string and the realloc is done */
2084 if (op1_string == op2_string) {
2085 if (free_op2_string) {
2086 zend_string_release(op2_string);
2087 free_op2_string = false;
2088 }
2089 op2_string = result_str;
2090 }
2091 } else {
2092 result_str = zend_string_alloc(result_len, 0);
2093 memcpy(ZSTR_VAL(result_str), ZSTR_VAL(op1_string), op1_len);
2094 if (result == orig_op1) {
2095 i_zval_ptr_dtor(result);
2096 }
2097 }
2098 GC_ADD_FLAGS(result_str, flags);
2099
2100 ZVAL_NEW_STR(result, result_str);
2101 memcpy(ZSTR_VAL(result_str) + op1_len, ZSTR_VAL(op2_string), op2_len);
2102 ZSTR_VAL(result_str)[result_len] = '\0';
2103 }
2104
2105 if (free_op1_string) zend_string_release(op1_string);
2106 if (free_op2_string) zend_string_release(op2_string);
2107
2108 return SUCCESS;
2109 }
2110 /* }}} */
2111
string_compare_function_ex(zval * op1,zval * op2,bool case_insensitive)2112 ZEND_API int ZEND_FASTCALL string_compare_function_ex(zval *op1, zval *op2, bool case_insensitive) /* {{{ */
2113 {
2114 zend_string *tmp_str1, *tmp_str2;
2115 zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2116 zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2117 int ret;
2118
2119 if (case_insensitive) {
2120 ret = zend_binary_strcasecmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2121 } else {
2122 ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2123 }
2124
2125 zend_tmp_string_release(tmp_str1);
2126 zend_tmp_string_release(tmp_str2);
2127 return ret;
2128 }
2129 /* }}} */
2130
string_compare_function(zval * op1,zval * op2)2131 ZEND_API int ZEND_FASTCALL string_compare_function(zval *op1, zval *op2) /* {{{ */
2132 {
2133 if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
2134 EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
2135 if (Z_STR_P(op1) == Z_STR_P(op2)) {
2136 return 0;
2137 } else {
2138 return zend_binary_strcmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
2139 }
2140 } else {
2141 zend_string *tmp_str1, *tmp_str2;
2142 zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2143 zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2144 int ret = zend_binary_strcmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2145
2146 zend_tmp_string_release(tmp_str1);
2147 zend_tmp_string_release(tmp_str2);
2148 return ret;
2149 }
2150 }
2151 /* }}} */
2152
string_case_compare_function(zval * op1,zval * op2)2153 ZEND_API int ZEND_FASTCALL string_case_compare_function(zval *op1, zval *op2) /* {{{ */
2154 {
2155 if (EXPECTED(Z_TYPE_P(op1) == IS_STRING) &&
2156 EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
2157 if (Z_STR_P(op1) == Z_STR_P(op2)) {
2158 return 0;
2159 } else {
2160 return zend_binary_strcasecmp(Z_STRVAL_P(op1), Z_STRLEN_P(op1), Z_STRVAL_P(op2), Z_STRLEN_P(op2));
2161 }
2162 } else {
2163 zend_string *tmp_str1, *tmp_str2;
2164 zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2165 zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2166 int ret = zend_binary_strcasecmp(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2));
2167
2168 zend_tmp_string_release(tmp_str1);
2169 zend_tmp_string_release(tmp_str2);
2170 return ret;
2171 }
2172 }
2173 /* }}} */
2174
string_locale_compare_function(zval * op1,zval * op2)2175 ZEND_API int ZEND_FASTCALL string_locale_compare_function(zval *op1, zval *op2) /* {{{ */
2176 {
2177 zend_string *tmp_str1, *tmp_str2;
2178 zend_string *str1 = zval_get_tmp_string(op1, &tmp_str1);
2179 zend_string *str2 = zval_get_tmp_string(op2, &tmp_str2);
2180 int ret = strcoll(ZSTR_VAL(str1), ZSTR_VAL(str2));
2181
2182 zend_tmp_string_release(tmp_str1);
2183 zend_tmp_string_release(tmp_str2);
2184 return ret;
2185 }
2186 /* }}} */
2187
numeric_compare_function(zval * op1,zval * op2)2188 ZEND_API int ZEND_FASTCALL numeric_compare_function(zval *op1, zval *op2) /* {{{ */
2189 {
2190 double d1, d2;
2191
2192 d1 = zval_get_double(op1);
2193 d2 = zval_get_double(op2);
2194
2195 return ZEND_THREEWAY_COMPARE(d1, d2);
2196 }
2197 /* }}} */
2198
compare_function(zval * result,zval * op1,zval * op2)2199 ZEND_API zend_result ZEND_FASTCALL compare_function(zval *result, zval *op1, zval *op2) /* {{{ */
2200 {
2201 ZVAL_LONG(result, zend_compare(op1, op2));
2202 return SUCCESS;
2203 }
2204 /* }}} */
2205
compare_long_to_string(zend_long lval,zend_string * str)2206 static int compare_long_to_string(zend_long lval, zend_string *str) /* {{{ */
2207 {
2208 zend_long str_lval;
2209 double str_dval;
2210 uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
2211
2212 if (type == IS_LONG) {
2213 return lval > str_lval ? 1 : lval < str_lval ? -1 : 0;
2214 }
2215
2216 if (type == IS_DOUBLE) {
2217 return ZEND_THREEWAY_COMPARE((double) lval, str_dval);
2218 }
2219
2220 zend_string *lval_as_str = zend_long_to_str(lval);
2221 int cmp_result = zend_binary_strcmp(
2222 ZSTR_VAL(lval_as_str), ZSTR_LEN(lval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
2223 zend_string_release(lval_as_str);
2224 return ZEND_NORMALIZE_BOOL(cmp_result);
2225 }
2226 /* }}} */
2227
compare_double_to_string(double dval,zend_string * str)2228 static int compare_double_to_string(double dval, zend_string *str) /* {{{ */
2229 {
2230 zend_long str_lval;
2231 double str_dval;
2232 uint8_t type = is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), &str_lval, &str_dval, 0);
2233
2234 if (type == IS_LONG) {
2235 return ZEND_THREEWAY_COMPARE(dval, (double) str_lval);
2236 }
2237
2238 if (type == IS_DOUBLE) {
2239 return ZEND_THREEWAY_COMPARE(dval, str_dval);
2240 }
2241
2242 zend_string *dval_as_str = zend_double_to_str(dval);
2243 int cmp_result = zend_binary_strcmp(
2244 ZSTR_VAL(dval_as_str), ZSTR_LEN(dval_as_str), ZSTR_VAL(str), ZSTR_LEN(str));
2245 zend_string_release(dval_as_str);
2246 return ZEND_NORMALIZE_BOOL(cmp_result);
2247 }
2248 /* }}} */
2249
zend_compare(zval * op1,zval * op2)2250 ZEND_API int ZEND_FASTCALL zend_compare(zval *op1, zval *op2) /* {{{ */
2251 {
2252 int converted = 0;
2253 zval op1_copy, op2_copy;
2254
2255 while (1) {
2256 switch (TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
2257 case TYPE_PAIR(IS_LONG, IS_LONG):
2258 return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
2259
2260 case TYPE_PAIR(IS_DOUBLE, IS_LONG):
2261 return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), (double)Z_LVAL_P(op2));
2262
2263 case TYPE_PAIR(IS_LONG, IS_DOUBLE):
2264 return ZEND_THREEWAY_COMPARE((double)Z_LVAL_P(op1), Z_DVAL_P(op2));
2265
2266 case TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
2267 return ZEND_THREEWAY_COMPARE(Z_DVAL_P(op1), Z_DVAL_P(op2));
2268
2269 case TYPE_PAIR(IS_ARRAY, IS_ARRAY):
2270 return zend_compare_arrays(op1, op2);
2271
2272 case TYPE_PAIR(IS_NULL, IS_NULL):
2273 case TYPE_PAIR(IS_NULL, IS_FALSE):
2274 case TYPE_PAIR(IS_FALSE, IS_NULL):
2275 case TYPE_PAIR(IS_FALSE, IS_FALSE):
2276 case TYPE_PAIR(IS_TRUE, IS_TRUE):
2277 return 0;
2278
2279 case TYPE_PAIR(IS_NULL, IS_TRUE):
2280 return -1;
2281
2282 case TYPE_PAIR(IS_TRUE, IS_NULL):
2283 return 1;
2284
2285 case TYPE_PAIR(IS_STRING, IS_STRING):
2286 if (Z_STR_P(op1) == Z_STR_P(op2)) {
2287 return 0;
2288 }
2289 return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
2290
2291 case TYPE_PAIR(IS_NULL, IS_STRING):
2292 return Z_STRLEN_P(op2) == 0 ? 0 : -1;
2293
2294 case TYPE_PAIR(IS_STRING, IS_NULL):
2295 return Z_STRLEN_P(op1) == 0 ? 0 : 1;
2296
2297 case TYPE_PAIR(IS_LONG, IS_STRING):
2298 return compare_long_to_string(Z_LVAL_P(op1), Z_STR_P(op2));
2299
2300 case TYPE_PAIR(IS_STRING, IS_LONG):
2301 return -compare_long_to_string(Z_LVAL_P(op2), Z_STR_P(op1));
2302
2303 case TYPE_PAIR(IS_DOUBLE, IS_STRING):
2304 if (zend_isnan(Z_DVAL_P(op1))) {
2305 return 1;
2306 }
2307
2308 return compare_double_to_string(Z_DVAL_P(op1), Z_STR_P(op2));
2309
2310 case TYPE_PAIR(IS_STRING, IS_DOUBLE):
2311 if (zend_isnan(Z_DVAL_P(op2))) {
2312 return 1;
2313 }
2314
2315 return -compare_double_to_string(Z_DVAL_P(op2), Z_STR_P(op1));
2316
2317 case TYPE_PAIR(IS_OBJECT, IS_NULL):
2318 return 1;
2319
2320 case TYPE_PAIR(IS_NULL, IS_OBJECT):
2321 return -1;
2322
2323 default:
2324 if (Z_ISREF_P(op1)) {
2325 op1 = Z_REFVAL_P(op1);
2326 continue;
2327 } else if (Z_ISREF_P(op2)) {
2328 op2 = Z_REFVAL_P(op2);
2329 continue;
2330 }
2331
2332 if (Z_TYPE_P(op1) == IS_OBJECT
2333 && Z_TYPE_P(op2) == IS_OBJECT
2334 && Z_OBJ_P(op1) == Z_OBJ_P(op2)) {
2335 return 0;
2336 } else if (Z_TYPE_P(op1) == IS_OBJECT) {
2337 return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
2338 } else if (Z_TYPE_P(op2) == IS_OBJECT) {
2339 return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
2340 }
2341
2342 if (!converted) {
2343 if (Z_TYPE_P(op1) < IS_TRUE) {
2344 return zval_is_true(op2) ? -1 : 0;
2345 } else if (Z_TYPE_P(op1) == IS_TRUE) {
2346 return zval_is_true(op2) ? 0 : 1;
2347 } else if (Z_TYPE_P(op2) < IS_TRUE) {
2348 return zval_is_true(op1) ? 1 : 0;
2349 } else if (Z_TYPE_P(op2) == IS_TRUE) {
2350 return zval_is_true(op1) ? 0 : -1;
2351 } else {
2352 op1 = _zendi_convert_scalar_to_number_silent(op1, &op1_copy);
2353 op2 = _zendi_convert_scalar_to_number_silent(op2, &op2_copy);
2354 if (EG(exception)) {
2355 return 1; /* to stop comparison of arrays */
2356 }
2357 converted = 1;
2358 }
2359 } else if (Z_TYPE_P(op1)==IS_ARRAY) {
2360 return 1;
2361 } else if (Z_TYPE_P(op2)==IS_ARRAY) {
2362 return -1;
2363 } else {
2364 ZEND_UNREACHABLE();
2365 zend_throw_error(NULL, "Unsupported operand types");
2366 return 1;
2367 }
2368 }
2369 }
2370 }
2371 /* }}} */
2372
2373 /* return int to be compatible with compare_func_t */
hash_zval_identical_function(zval * z1,zval * z2)2374 static int hash_zval_identical_function(zval *z1, zval *z2) /* {{{ */
2375 {
2376 /* is_identical_function() returns 1 in case of identity and 0 in case
2377 * of a difference;
2378 * whereas this comparison function is expected to return 0 on identity,
2379 * and non zero otherwise.
2380 */
2381 ZVAL_DEREF(z1);
2382 ZVAL_DEREF(z2);
2383 return fast_is_not_identical_function(z1, z2);
2384 }
2385 /* }}} */
2386
zend_is_identical(const zval * op1,const zval * op2)2387 ZEND_API bool ZEND_FASTCALL zend_is_identical(const zval *op1, const zval *op2) /* {{{ */
2388 {
2389 if (Z_TYPE_P(op1) != Z_TYPE_P(op2)) {
2390 return 0;
2391 }
2392 switch (Z_TYPE_P(op1)) {
2393 case IS_NULL:
2394 case IS_FALSE:
2395 case IS_TRUE:
2396 return 1;
2397 case IS_LONG:
2398 return (Z_LVAL_P(op1) == Z_LVAL_P(op2));
2399 case IS_RESOURCE:
2400 return (Z_RES_P(op1) == Z_RES_P(op2));
2401 case IS_DOUBLE:
2402 return (Z_DVAL_P(op1) == Z_DVAL_P(op2));
2403 case IS_STRING:
2404 return zend_string_equals(Z_STR_P(op1), Z_STR_P(op2));
2405 case IS_ARRAY:
2406 return (Z_ARRVAL_P(op1) == Z_ARRVAL_P(op2) ||
2407 zend_hash_compare(Z_ARRVAL_P(op1), Z_ARRVAL_P(op2), (compare_func_t) hash_zval_identical_function, 1) == 0);
2408 case IS_OBJECT:
2409 return (Z_OBJ_P(op1) == Z_OBJ_P(op2));
2410 default:
2411 return 0;
2412 }
2413 }
2414 /* }}} */
2415
is_identical_function(zval * result,zval * op1,zval * op2)2416 ZEND_API zend_result ZEND_FASTCALL is_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2417 {
2418 ZVAL_BOOL(result, zend_is_identical(op1, op2));
2419 return SUCCESS;
2420 }
2421 /* }}} */
2422
is_not_identical_function(zval * result,zval * op1,zval * op2)2423 ZEND_API zend_result ZEND_FASTCALL is_not_identical_function(zval *result, zval *op1, zval *op2) /* {{{ */
2424 {
2425 ZVAL_BOOL(result, !zend_is_identical(op1, op2));
2426 return SUCCESS;
2427 }
2428 /* }}} */
2429
is_equal_function(zval * result,zval * op1,zval * op2)2430 ZEND_API zend_result ZEND_FASTCALL is_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2431 {
2432 ZVAL_BOOL(result, zend_compare(op1, op2) == 0);
2433 return SUCCESS;
2434 }
2435 /* }}} */
2436
is_not_equal_function(zval * result,zval * op1,zval * op2)2437 ZEND_API zend_result ZEND_FASTCALL is_not_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2438 {
2439 ZVAL_BOOL(result, (zend_compare(op1, op2) != 0));
2440 return SUCCESS;
2441 }
2442 /* }}} */
2443
is_smaller_function(zval * result,zval * op1,zval * op2)2444 ZEND_API zend_result ZEND_FASTCALL is_smaller_function(zval *result, zval *op1, zval *op2) /* {{{ */
2445 {
2446 ZVAL_BOOL(result, (zend_compare(op1, op2) < 0));
2447 return SUCCESS;
2448 }
2449 /* }}} */
2450
is_smaller_or_equal_function(zval * result,zval * op1,zval * op2)2451 ZEND_API zend_result ZEND_FASTCALL is_smaller_or_equal_function(zval *result, zval *op1, zval *op2) /* {{{ */
2452 {
2453 ZVAL_BOOL(result, (zend_compare(op1, op2) <= 0));
2454 return SUCCESS;
2455 }
2456 /* }}} */
2457
zend_class_implements_interface(const zend_class_entry * class_ce,const zend_class_entry * interface_ce)2458 ZEND_API bool ZEND_FASTCALL zend_class_implements_interface(const zend_class_entry *class_ce, const zend_class_entry *interface_ce) /* {{{ */
2459 {
2460 uint32_t i;
2461 ZEND_ASSERT(interface_ce->ce_flags & ZEND_ACC_INTERFACE);
2462
2463 if (class_ce->num_interfaces) {
2464 ZEND_ASSERT(class_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2465 for (i = 0; i < class_ce->num_interfaces; i++) {
2466 if (class_ce->interfaces[i] == interface_ce) {
2467 return 1;
2468 }
2469 }
2470 }
2471 return 0;
2472 }
2473 /* }}} */
2474
instanceof_function_slow(const zend_class_entry * instance_ce,const zend_class_entry * ce)2475 ZEND_API bool ZEND_FASTCALL instanceof_function_slow(const zend_class_entry *instance_ce, const zend_class_entry *ce) /* {{{ */
2476 {
2477 ZEND_ASSERT(instance_ce != ce && "Should have been checked already");
2478 if (ce->ce_flags & ZEND_ACC_INTERFACE) {
2479 uint32_t i;
2480
2481 if (instance_ce->num_interfaces) {
2482 ZEND_ASSERT(instance_ce->ce_flags & ZEND_ACC_RESOLVED_INTERFACES);
2483 for (i = 0; i < instance_ce->num_interfaces; i++) {
2484 if (instance_ce->interfaces[i] == ce) {
2485 return 1;
2486 }
2487 }
2488 }
2489 return 0;
2490 } else {
2491 while (1) {
2492 instance_ce = instance_ce->parent;
2493 if (instance_ce == ce) {
2494 return 1;
2495 }
2496 if (instance_ce == NULL) {
2497 return 0;
2498 }
2499 }
2500 }
2501 }
2502 /* }}} */
2503
2504 #define LOWER_CASE 1
2505 #define UPPER_CASE 2
2506 #define NUMERIC 3
2507
zend_string_only_has_ascii_alphanumeric(const zend_string * str)2508 ZEND_API bool zend_string_only_has_ascii_alphanumeric(const zend_string *str)
2509 {
2510 const char *p = ZSTR_VAL(str);
2511 const char *e = ZSTR_VAL(str) + ZSTR_LEN(str);
2512 while (p < e) {
2513 char c = *p++;
2514 if (UNEXPECTED( c < '0' || c > 'z' || (c < 'a' && c > 'Z') || (c < 'A' && c > '9') ) ) {
2515 return false;
2516 }
2517 }
2518 return true;
2519 }
2520
increment_string(zval * str)2521 static bool ZEND_FASTCALL increment_string(zval *str) /* {{{ */
2522 {
2523 int carry=0;
2524 size_t pos=Z_STRLEN_P(str)-1;
2525 char *s;
2526 zend_string *t;
2527 int last=0; /* Shut up the compiler warning */
2528 int ch;
2529
2530 if (UNEXPECTED(Z_STRLEN_P(str) == 0)) {
2531 zend_error(E_DEPRECATED, "Increment on non-alphanumeric string is deprecated");
2532 if (EG(exception)) {
2533 return false;
2534 }
2535 /* A userland error handler can change the type from string to something else */
2536 zval_ptr_dtor(str);
2537 ZVAL_CHAR(str, '1');
2538 return true;
2539 }
2540
2541 if (UNEXPECTED(!zend_string_only_has_ascii_alphanumeric(Z_STR_P(str)))) {
2542 zend_string *zstr = Z_STR_P(str);
2543 zend_string_addref(zstr);
2544 zend_error(E_DEPRECATED, "Increment on non-alphanumeric string is deprecated");
2545 if (EG(exception)) {
2546 zend_string_release(zstr);
2547 return false;
2548 }
2549 zval_ptr_dtor(str);
2550 ZVAL_STR(str, zstr);
2551 }
2552
2553 if (!Z_REFCOUNTED_P(str)) {
2554 Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2555 Z_TYPE_INFO_P(str) = IS_STRING_EX;
2556 } else if (Z_REFCOUNT_P(str) > 1) {
2557 /* Only release string after allocation succeeded. */
2558 zend_string *orig_str = Z_STR_P(str);
2559 Z_STR_P(str) = zend_string_init(Z_STRVAL_P(str), Z_STRLEN_P(str), 0);
2560 GC_DELREF(orig_str);
2561 } else {
2562 zend_string_forget_hash_val(Z_STR_P(str));
2563 }
2564 s = Z_STRVAL_P(str);
2565
2566 do {
2567 ch = s[pos];
2568 if (ch >= 'a' && ch <= 'z') {
2569 if (ch == 'z') {
2570 s[pos] = 'a';
2571 carry=1;
2572 } else {
2573 s[pos]++;
2574 carry=0;
2575 }
2576 last=LOWER_CASE;
2577 } else if (ch >= 'A' && ch <= 'Z') {
2578 if (ch == 'Z') {
2579 s[pos] = 'A';
2580 carry=1;
2581 } else {
2582 s[pos]++;
2583 carry=0;
2584 }
2585 last=UPPER_CASE;
2586 } else if (ch >= '0' && ch <= '9') {
2587 if (ch == '9') {
2588 s[pos] = '0';
2589 carry=1;
2590 } else {
2591 s[pos]++;
2592 carry=0;
2593 }
2594 last = NUMERIC;
2595 } else {
2596 carry=0;
2597 break;
2598 }
2599 if (carry == 0) {
2600 break;
2601 }
2602 } while (pos-- > 0);
2603
2604 if (carry) {
2605 t = zend_string_alloc(Z_STRLEN_P(str)+1, 0);
2606 memcpy(ZSTR_VAL(t) + 1, Z_STRVAL_P(str), Z_STRLEN_P(str));
2607 ZSTR_VAL(t)[Z_STRLEN_P(str) + 1] = '\0';
2608 switch (last) {
2609 case NUMERIC:
2610 ZSTR_VAL(t)[0] = '1';
2611 break;
2612 case UPPER_CASE:
2613 ZSTR_VAL(t)[0] = 'A';
2614 break;
2615 case LOWER_CASE:
2616 ZSTR_VAL(t)[0] = 'a';
2617 break;
2618 }
2619 zend_string_free(Z_STR_P(str));
2620 ZVAL_NEW_STR(str, t);
2621 }
2622 return true;
2623 }
2624 /* }}} */
2625
increment_function(zval * op1)2626 ZEND_API zend_result ZEND_FASTCALL increment_function(zval *op1) /* {{{ */
2627 {
2628 try_again:
2629 switch (Z_TYPE_P(op1)) {
2630 case IS_LONG:
2631 fast_long_increment_function(op1);
2632 break;
2633 case IS_DOUBLE:
2634 Z_DVAL_P(op1) = Z_DVAL_P(op1) + 1;
2635 break;
2636 case IS_NULL:
2637 ZVAL_LONG(op1, 1);
2638 break;
2639 case IS_STRING: {
2640 zend_long lval;
2641 double dval;
2642
2643 switch (is_numeric_str_function(Z_STR_P(op1), &lval, &dval)) {
2644 case IS_LONG:
2645 zval_ptr_dtor_str(op1);
2646 if (lval == ZEND_LONG_MAX) {
2647 /* switch to double */
2648 double d = (double)lval;
2649 ZVAL_DOUBLE(op1, d+1);
2650 } else {
2651 ZVAL_LONG(op1, lval+1);
2652 }
2653 break;
2654 case IS_DOUBLE:
2655 zval_ptr_dtor_str(op1);
2656 ZVAL_DOUBLE(op1, dval+1);
2657 break;
2658 default:
2659 /* Perl style string increment */
2660 increment_string(op1);
2661 if (EG(exception)) {
2662 return FAILURE;
2663 }
2664 break;
2665 }
2666 }
2667 break;
2668 case IS_FALSE:
2669 case IS_TRUE: {
2670 /* Error handler can undef/change type of op1, save it and reset it in case those cases */
2671 zval copy;
2672 ZVAL_COPY_VALUE(©, op1);
2673 zend_error(E_WARNING, "Increment on type bool has no effect, this will change in the next major version of PHP");
2674 zval_ptr_dtor(op1);
2675 ZVAL_COPY_VALUE(op1, ©);
2676 if (EG(exception)) {
2677 return FAILURE;
2678 }
2679 break;
2680 }
2681 case IS_REFERENCE:
2682 op1 = Z_REFVAL_P(op1);
2683 goto try_again;
2684 case IS_OBJECT: {
2685 if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2686 zval op2;
2687 ZVAL_LONG(&op2, 1);
2688 if (Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_ADD, op1, op1, &op2) == SUCCESS) {
2689 return SUCCESS;
2690 }
2691 }
2692 zval tmp;
2693 if (Z_OBJ_HT_P(op1)->cast_object(Z_OBJ_P(op1), &tmp, _IS_NUMBER) == SUCCESS) {
2694 ZEND_ASSERT(Z_TYPE(tmp) == IS_LONG || Z_TYPE(tmp) == IS_DOUBLE);
2695 zval_ptr_dtor(op1);
2696 ZVAL_COPY_VALUE(op1, &tmp);
2697 goto try_again;
2698 }
2699 ZEND_FALLTHROUGH;
2700 }
2701 case IS_RESOURCE:
2702 case IS_ARRAY:
2703 zend_type_error("Cannot increment %s", zend_zval_value_name(op1));
2704 return FAILURE;
2705 EMPTY_SWITCH_DEFAULT_CASE()
2706 }
2707 return SUCCESS;
2708 }
2709 /* }}} */
2710
decrement_function(zval * op1)2711 ZEND_API zend_result ZEND_FASTCALL decrement_function(zval *op1) /* {{{ */
2712 {
2713 zend_long lval;
2714 double dval;
2715
2716 try_again:
2717 switch (Z_TYPE_P(op1)) {
2718 case IS_LONG:
2719 fast_long_decrement_function(op1);
2720 break;
2721 case IS_DOUBLE:
2722 Z_DVAL_P(op1) = Z_DVAL_P(op1) - 1;
2723 break;
2724 case IS_STRING: /* Like perl we only support string increment */
2725 if (Z_STRLEN_P(op1) == 0) { /* consider as 0 */
2726 zend_error(E_DEPRECATED, "Decrement on empty string is deprecated as non-numeric");
2727 if (EG(exception)) {
2728 return FAILURE;
2729 }
2730 /* A userland error handler can change the type from string to something else */
2731 zval_ptr_dtor(op1);
2732 ZVAL_LONG(op1, -1);
2733 break;
2734 }
2735 switch (is_numeric_str_function(Z_STR_P(op1), &lval, &dval)) {
2736 case IS_LONG:
2737 zval_ptr_dtor_str(op1);
2738 if (lval == ZEND_LONG_MIN) {
2739 double d = (double)lval;
2740 ZVAL_DOUBLE(op1, d-1);
2741 } else {
2742 ZVAL_LONG(op1, lval-1);
2743 }
2744 break;
2745 case IS_DOUBLE:
2746 zval_ptr_dtor_str(op1);
2747 ZVAL_DOUBLE(op1, dval - 1);
2748 break;
2749 default: {
2750 /* Error handler can unset the variable */
2751 zend_string *zstr = Z_STR_P(op1);
2752 zend_string_addref(zstr);
2753 zend_error(E_DEPRECATED, "Decrement on non-numeric string has no effect and is deprecated");
2754 if (EG(exception)) {
2755 zend_string_release(zstr);
2756 return FAILURE;
2757 }
2758 zval_ptr_dtor(op1);
2759 ZVAL_STR(op1, zstr);
2760 }
2761 }
2762 break;
2763 case IS_NULL: {
2764 /* Error handler can undef/change type of op1, save it and reset it in case those cases */
2765 zval copy;
2766 ZVAL_COPY_VALUE(©, op1);
2767 zend_error(E_WARNING, "Decrement on type null has no effect, this will change in the next major version of PHP");
2768 zval_ptr_dtor(op1);
2769 ZVAL_COPY_VALUE(op1, ©);
2770 if (EG(exception)) {
2771 return FAILURE;
2772 }
2773 break;
2774 }
2775 case IS_FALSE:
2776 case IS_TRUE: {
2777 /* Error handler can undef/change type of op1, save it and reset it in case those cases */
2778 zval copy;
2779 ZVAL_COPY_VALUE(©, op1);
2780 zend_error(E_WARNING, "Decrement on type bool has no effect, this will change in the next major version of PHP");
2781 zval_ptr_dtor(op1);
2782 ZVAL_COPY_VALUE(op1, ©);
2783 if (EG(exception)) {
2784 return FAILURE;
2785 }
2786 break;
2787 }
2788 case IS_REFERENCE:
2789 op1 = Z_REFVAL_P(op1);
2790 goto try_again;
2791 case IS_OBJECT: {
2792 if (Z_OBJ_HANDLER_P(op1, do_operation)) {
2793 zval op2;
2794 ZVAL_LONG(&op2, 1);
2795 if (Z_OBJ_HANDLER_P(op1, do_operation)(ZEND_SUB, op1, op1, &op2) == SUCCESS) {
2796 return SUCCESS;
2797 }
2798 }
2799 zval tmp;
2800 if (Z_OBJ_HT_P(op1)->cast_object(Z_OBJ_P(op1), &tmp, _IS_NUMBER) == SUCCESS) {
2801 ZEND_ASSERT(Z_TYPE(tmp) == IS_LONG || Z_TYPE(tmp) == IS_DOUBLE);
2802 zval_ptr_dtor(op1);
2803 ZVAL_COPY_VALUE(op1, &tmp);
2804 goto try_again;
2805 }
2806 ZEND_FALLTHROUGH;
2807 }
2808 case IS_RESOURCE:
2809 case IS_ARRAY:
2810 zend_type_error("Cannot decrement %s", zend_zval_value_name(op1));
2811 return FAILURE;
2812 EMPTY_SWITCH_DEFAULT_CASE()
2813 }
2814
2815 return SUCCESS;
2816 }
2817 /* }}} */
2818
zend_is_true(const zval * op)2819 ZEND_API bool ZEND_FASTCALL zend_is_true(const zval *op) /* {{{ */
2820 {
2821 return i_zend_is_true(op);
2822 }
2823 /* }}} */
2824
zend_object_is_true(const zval * op)2825 ZEND_API bool ZEND_FASTCALL zend_object_is_true(const zval *op) /* {{{ */
2826 {
2827 zend_object *zobj = Z_OBJ_P(op);
2828 zval tmp;
2829 if (zobj->handlers->cast_object(zobj, &tmp, _IS_BOOL) == SUCCESS) {
2830 return Z_TYPE(tmp) == IS_TRUE;
2831 }
2832 zend_error(E_RECOVERABLE_ERROR, "Object of class %s could not be converted to bool", ZSTR_VAL(zobj->ce->name));
2833 return false;
2834 }
2835 /* }}} */
2836
zend_update_current_locale(void)2837 ZEND_API void zend_update_current_locale(void) /* {{{ */
2838 {
2839 #ifdef ZEND_USE_TOLOWER_L
2840 # if defined(ZEND_WIN32) && defined(_MSC_VER)
2841 current_locale = _get_current_locale();
2842 # else
2843 current_locale = uselocale(0);
2844 # endif
2845 #endif
2846 #if defined(ZEND_WIN32) && defined(_MSC_VER)
2847 if (MB_CUR_MAX > 1) {
2848 unsigned int cp = ___lc_codepage_func();
2849 CG(variable_width_locale) = 1;
2850 // TODO: EUC-* are also ASCII compatible ???
2851 CG(ascii_compatible_locale) =
2852 cp == 65001; /* UTF-8 */
2853 } else {
2854 CG(variable_width_locale) = 0;
2855 CG(ascii_compatible_locale) = 1;
2856 }
2857 #elif defined(MB_CUR_MAX)
2858 /* Check if current locale uses variable width encoding */
2859 if (MB_CUR_MAX > 1) {
2860 #ifdef HAVE_NL_LANGINFO
2861 const char *charmap = nl_langinfo(CODESET);
2862 #else
2863 char buf[16];
2864 const char *charmap = NULL;
2865 const char *locale = setlocale(LC_CTYPE, NULL);
2866
2867 if (locale) {
2868 const char *dot = strchr(locale, '.');
2869 const char *modifier;
2870
2871 if (dot) {
2872 dot++;
2873 modifier = strchr(dot, '@');
2874 if (!modifier) {
2875 charmap = dot;
2876 } else if (modifier - dot < sizeof(buf)) {
2877 memcpy(buf, dot, modifier - dot);
2878 buf[modifier - dot] = '\0';
2879 charmap = buf;
2880 }
2881 }
2882 }
2883 #endif
2884 CG(variable_width_locale) = 1;
2885 CG(ascii_compatible_locale) = 0;
2886
2887 if (charmap) {
2888 size_t len = strlen(charmap);
2889 static const char *ascii_compatible_charmaps[] = {
2890 "utf-8",
2891 "utf8",
2892 // TODO: EUC-* are also ASCII compatible ???
2893 NULL
2894 };
2895 const char **p;
2896 /* Check if current locale is ASCII compatible */
2897 for (p = ascii_compatible_charmaps; *p; p++) {
2898 if (zend_binary_strcasecmp(charmap, len, *p, strlen(*p)) == 0) {
2899 CG(ascii_compatible_locale) = 1;
2900 break;
2901 }
2902 }
2903 }
2904
2905 } else {
2906 CG(variable_width_locale) = 0;
2907 CG(ascii_compatible_locale) = 1;
2908 }
2909 #else
2910 /* We can't determine current charset. Assume the worst case */
2911 CG(variable_width_locale) = 1;
2912 CG(ascii_compatible_locale) = 0;
2913 #endif
2914 }
2915 /* }}} */
2916
zend_reset_lc_ctype_locale(void)2917 ZEND_API void zend_reset_lc_ctype_locale(void)
2918 {
2919 /* Use the C.UTF-8 locale so that readline can process UTF-8 input, while not interfering
2920 * with single-byte locale-dependent functions used by PHP. */
2921 if (!setlocale(LC_CTYPE, "C.UTF-8")) {
2922 setlocale(LC_CTYPE, "C");
2923 }
2924 }
2925
zend_str_tolower_impl(char * dest,const char * str,size_t length)2926 static zend_always_inline void zend_str_tolower_impl(char *dest, const char *str, size_t length) /* {{{ */ {
2927 unsigned char *p = (unsigned char*)str;
2928 unsigned char *q = (unsigned char*)dest;
2929 unsigned char *end = p + length;
2930 #ifdef HAVE_BLOCKCONV
2931 if (length >= BLOCKCONV_STRIDE) {
2932 BLOCKCONV_INIT_RANGE('A', 'Z');
2933 BLOCKCONV_INIT_DELTA('a' - 'A');
2934 do {
2935 BLOCKCONV_LOAD(p);
2936 BLOCKCONV_STORE(q);
2937 p += BLOCKCONV_STRIDE;
2938 q += BLOCKCONV_STRIDE;
2939 } while (p + BLOCKCONV_STRIDE <= end);
2940 }
2941 #endif
2942 while (p < end) {
2943 *q++ = zend_tolower_ascii(*p++);
2944 }
2945 }
2946 /* }}} */
2947
zend_str_toupper_impl(char * dest,const char * str,size_t length)2948 static zend_always_inline void zend_str_toupper_impl(char *dest, const char *str, size_t length) /* {{{ */ {
2949 unsigned char *p = (unsigned char*)str;
2950 unsigned char *q = (unsigned char*)dest;
2951 unsigned char *end = p + length;
2952 #ifdef HAVE_BLOCKCONV
2953 if (length >= BLOCKCONV_STRIDE) {
2954 BLOCKCONV_INIT_RANGE('a', 'z');
2955 BLOCKCONV_INIT_DELTA('A' - 'a');
2956 do {
2957 BLOCKCONV_LOAD(p);
2958 BLOCKCONV_STORE(q);
2959 p += BLOCKCONV_STRIDE;
2960 q += BLOCKCONV_STRIDE;
2961 } while (p + BLOCKCONV_STRIDE <= end);
2962 }
2963 #endif
2964 while (p < end) {
2965 *q++ = zend_toupper_ascii(*p++);
2966 }
2967 }
2968 /* }}} */
2969
zend_str_tolower_copy(char * dest,const char * source,size_t length)2970 ZEND_API char* ZEND_FASTCALL zend_str_tolower_copy(char *dest, const char *source, size_t length) /* {{{ */
2971 {
2972 zend_str_tolower_impl(dest, source, length);
2973 dest[length] = '\0';
2974 return dest;
2975 }
2976 /* }}} */
2977
zend_str_toupper_copy(char * dest,const char * source,size_t length)2978 ZEND_API char* ZEND_FASTCALL zend_str_toupper_copy(char *dest, const char *source, size_t length) /* {{{ */
2979 {
2980 zend_str_toupper_impl(dest, source, length);
2981 dest[length] = '\0';
2982 return dest;
2983 }
2984 /* }}} */
2985
zend_str_tolower_dup(const char * source,size_t length)2986 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup(const char *source, size_t length) /* {{{ */
2987 {
2988 return zend_str_tolower_copy((char *)emalloc(length+1), source, length);
2989 }
2990 /* }}} */
2991
zend_str_toupper_dup(const char * source,size_t length)2992 ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup(const char *source, size_t length) /* {{{ */
2993 {
2994 return zend_str_toupper_copy((char *)emalloc(length+1), source, length);
2995 }
2996 /* }}} */
2997
zend_str_tolower(char * str,size_t length)2998 ZEND_API void ZEND_FASTCALL zend_str_tolower(char *str, size_t length) /* {{{ */
2999 {
3000 zend_str_tolower_impl(str, (const char*)str, length);
3001 }
3002 /* }}} */
3003
zend_str_toupper(char * str,size_t length)3004 ZEND_API void ZEND_FASTCALL zend_str_toupper(char *str, size_t length) /* {{{ */
3005 {
3006 zend_str_toupper_impl(str, (const char*)str, length);
3007 }
3008 /* }}} */
3009
3010
zend_str_tolower_dup_ex(const char * source,size_t length)3011 ZEND_API char* ZEND_FASTCALL zend_str_tolower_dup_ex(const char *source, size_t length) /* {{{ */
3012 {
3013 const unsigned char *p = (const unsigned char*)source;
3014 const unsigned char *end = p + length;
3015
3016 while (p < end) {
3017 if (*p != zend_tolower_ascii(*p)) {
3018 char *res = (char*)emalloc(length + 1);
3019 unsigned char *r;
3020
3021 if (p != (const unsigned char*)source) {
3022 memcpy(res, source, p - (const unsigned char*)source);
3023 }
3024 r = (unsigned char*)p + (res - source);
3025 zend_str_tolower_impl((char *)r, (const char*)p, end - p);
3026 res[length] = '\0';
3027 return res;
3028 }
3029 p++;
3030 }
3031 return NULL;
3032 }
3033 /* }}} */
3034
zend_str_toupper_dup_ex(const char * source,size_t length)3035 ZEND_API char* ZEND_FASTCALL zend_str_toupper_dup_ex(const char *source, size_t length) /* {{{ */
3036 {
3037 const unsigned char *p = (const unsigned char*)source;
3038 const unsigned char *end = p + length;
3039
3040 while (p < end) {
3041 if (*p != zend_toupper_ascii(*p)) {
3042 char *res = (char*)emalloc(length + 1);
3043 unsigned char *r;
3044
3045 if (p != (const unsigned char*)source) {
3046 memcpy(res, source, p - (const unsigned char*)source);
3047 }
3048 r = (unsigned char*)p + (res - source);
3049 zend_str_toupper_impl((char *)r, (const char*)p, end - p);
3050 res[length] = '\0';
3051 return res;
3052 }
3053 p++;
3054 }
3055 return NULL;
3056 }
3057 /* }}} */
3058
zend_string_tolower_ex(zend_string * str,bool persistent)3059 ZEND_API zend_string* ZEND_FASTCALL zend_string_tolower_ex(zend_string *str, bool persistent) /* {{{ */
3060 {
3061 size_t length = ZSTR_LEN(str);
3062 unsigned char *p = (unsigned char *) ZSTR_VAL(str);
3063 unsigned char *end = p + length;
3064
3065 #ifdef HAVE_BLOCKCONV
3066 BLOCKCONV_INIT_RANGE('A', 'Z');
3067 while (p + BLOCKCONV_STRIDE <= end) {
3068 BLOCKCONV_LOAD(p);
3069 if (BLOCKCONV_FOUND()) {
3070 zend_string *res = zend_string_alloc(length, persistent);
3071 memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
3072 unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
3073
3074 /* Lowercase the chunk we already compared. */
3075 BLOCKCONV_INIT_DELTA('a' - 'A');
3076 BLOCKCONV_STORE(q);
3077
3078 /* Lowercase the rest of the string. */
3079 p += BLOCKCONV_STRIDE;
3080 q += BLOCKCONV_STRIDE;
3081 zend_str_tolower_impl((char *) q, (const char *) p, end - p);
3082 ZSTR_VAL(res)[length] = '\0';
3083 return res;
3084 }
3085 p += BLOCKCONV_STRIDE;
3086 }
3087 #endif
3088
3089 while (p < end) {
3090 if (*p != zend_tolower_ascii(*p)) {
3091 zend_string *res = zend_string_alloc(length, persistent);
3092 memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
3093
3094 unsigned char *q = (unsigned char*) ZSTR_VAL(res) + (p - (unsigned char*) ZSTR_VAL(str));
3095 while (p < end) {
3096 *q++ = zend_tolower_ascii(*p++);
3097 }
3098 ZSTR_VAL(res)[length] = '\0';
3099 return res;
3100 }
3101 p++;
3102 }
3103
3104 return zend_string_copy(str);
3105 }
3106 /* }}} */
3107
zend_string_toupper_ex(zend_string * str,bool persistent)3108 ZEND_API zend_string* ZEND_FASTCALL zend_string_toupper_ex(zend_string *str, bool persistent) /* {{{ */
3109 {
3110 size_t length = ZSTR_LEN(str);
3111 unsigned char *p = (unsigned char *) ZSTR_VAL(str);
3112 unsigned char *end = p + length;
3113
3114 #ifdef HAVE_BLOCKCONV
3115 BLOCKCONV_INIT_RANGE('a', 'z');
3116 while (p + BLOCKCONV_STRIDE <= end) {
3117 BLOCKCONV_LOAD(p);
3118 if (BLOCKCONV_FOUND()) {
3119 zend_string *res = zend_string_alloc(length, persistent);
3120 memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char *) ZSTR_VAL(str));
3121 unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str));
3122
3123 /* Uppercase the chunk we already compared. */
3124 BLOCKCONV_INIT_DELTA('A' - 'a');
3125 BLOCKCONV_STORE(q);
3126
3127 /* Uppercase the rest of the string. */
3128 p += BLOCKCONV_STRIDE;
3129 q += BLOCKCONV_STRIDE;
3130 zend_str_toupper_impl((char *) q, (const char *) p, end - p);
3131 ZSTR_VAL(res)[length] = '\0';
3132 return res;
3133 }
3134 p += BLOCKCONV_STRIDE;
3135 }
3136 #endif
3137
3138 while (p < end) {
3139 if (*p != zend_toupper_ascii(*p)) {
3140 zend_string *res = zend_string_alloc(length, persistent);
3141 memcpy(ZSTR_VAL(res), ZSTR_VAL(str), p - (unsigned char*) ZSTR_VAL(str));
3142
3143 unsigned char *q = (unsigned char *) ZSTR_VAL(res) + (p - (unsigned char *) ZSTR_VAL(str));
3144 while (p < end) {
3145 *q++ = zend_toupper_ascii(*p++);
3146 }
3147 ZSTR_VAL(res)[length] = '\0';
3148 return res;
3149 }
3150 p++;
3151 }
3152
3153 return zend_string_copy(str);
3154 }
3155 /* }}} */
3156
zend_binary_strcmp(const char * s1,size_t len1,const char * s2,size_t len2)3157 ZEND_API int ZEND_FASTCALL zend_binary_strcmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
3158 {
3159 int retval;
3160
3161 if (s1 == s2) {
3162 return 0;
3163 }
3164 retval = memcmp(s1, s2, MIN(len1, len2));
3165 if (!retval) {
3166 return ZEND_THREEWAY_COMPARE(len1, len2);
3167 } else {
3168 return retval;
3169 }
3170 }
3171 /* }}} */
3172
zend_binary_strncmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)3173 ZEND_API int ZEND_FASTCALL zend_binary_strncmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
3174 {
3175 int retval;
3176
3177 if (s1 == s2) {
3178 return 0;
3179 }
3180 retval = memcmp(s1, s2, MIN(length, MIN(len1, len2)));
3181 if (!retval) {
3182 return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
3183 } else {
3184 return retval;
3185 }
3186 }
3187 /* }}} */
3188
zend_binary_strcasecmp(const char * s1,size_t len1,const char * s2,size_t len2)3189 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
3190 {
3191 size_t len;
3192 int c1, c2;
3193
3194 if (s1 == s2) {
3195 return 0;
3196 }
3197
3198 len = MIN(len1, len2);
3199 while (len--) {
3200 c1 = zend_tolower_ascii(*(unsigned char *)s1++);
3201 c2 = zend_tolower_ascii(*(unsigned char *)s2++);
3202 if (c1 != c2) {
3203 return c1 - c2;
3204 }
3205 }
3206
3207 return ZEND_THREEWAY_COMPARE(len1, len2);
3208 }
3209 /* }}} */
3210
zend_binary_strncasecmp(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)3211 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
3212 {
3213 size_t len;
3214 int c1, c2;
3215
3216 if (s1 == s2) {
3217 return 0;
3218 }
3219 len = MIN(length, MIN(len1, len2));
3220 while (len--) {
3221 c1 = zend_tolower_ascii(*(unsigned char *)s1++);
3222 c2 = zend_tolower_ascii(*(unsigned char *)s2++);
3223 if (c1 != c2) {
3224 return c1 - c2;
3225 }
3226 }
3227
3228 return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
3229 }
3230 /* }}} */
3231
zend_binary_strcasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2)3232 ZEND_API int ZEND_FASTCALL zend_binary_strcasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2) /* {{{ */
3233 {
3234 size_t len;
3235 int c1, c2;
3236
3237 if (s1 == s2) {
3238 return 0;
3239 }
3240
3241 len = MIN(len1, len2);
3242 while (len--) {
3243 c1 = zend_tolower((int)*(unsigned char *)s1++);
3244 c2 = zend_tolower((int)*(unsigned char *)s2++);
3245 if (c1 != c2) {
3246 return c1 - c2;
3247 }
3248 }
3249
3250 return ZEND_THREEWAY_COMPARE(len1, len2);
3251 }
3252 /* }}} */
3253
zend_binary_strncasecmp_l(const char * s1,size_t len1,const char * s2,size_t len2,size_t length)3254 ZEND_API int ZEND_FASTCALL zend_binary_strncasecmp_l(const char *s1, size_t len1, const char *s2, size_t len2, size_t length) /* {{{ */
3255 {
3256 size_t len;
3257 int c1, c2;
3258
3259 if (s1 == s2) {
3260 return 0;
3261 }
3262 len = MIN(length, MIN(len1, len2));
3263 while (len--) {
3264 c1 = zend_tolower((int)*(unsigned char *)s1++);
3265 c2 = zend_tolower((int)*(unsigned char *)s2++);
3266 if (c1 != c2) {
3267 return c1 - c2;
3268 }
3269 }
3270
3271 return ZEND_THREEWAY_COMPARE(MIN(length, len1), MIN(length, len2));
3272 }
3273 /* }}} */
3274
zend_binary_zval_strcmp(zval * s1,zval * s2)3275 ZEND_API int ZEND_FASTCALL zend_binary_zval_strcmp(zval *s1, zval *s2) /* {{{ */
3276 {
3277 return zend_binary_strcmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2));
3278 }
3279 /* }}} */
3280
zend_binary_zval_strncmp(zval * s1,zval * s2,zval * s3)3281 ZEND_API int ZEND_FASTCALL zend_binary_zval_strncmp(zval *s1, zval *s2, zval *s3) /* {{{ */
3282 {
3283 return zend_binary_strncmp(Z_STRVAL_P(s1), Z_STRLEN_P(s1), Z_STRVAL_P(s2), Z_STRLEN_P(s2), Z_LVAL_P(s3));
3284 }
3285 /* }}} */
3286
zendi_smart_streq(zend_string * s1,zend_string * s2)3287 ZEND_API bool ZEND_FASTCALL zendi_smart_streq(zend_string *s1, zend_string *s2) /* {{{ */
3288 {
3289 uint8_t ret1, ret2;
3290 int oflow1, oflow2;
3291 zend_long lval1 = 0, lval2 = 0;
3292 double dval1 = 0.0, dval2 = 0.0;
3293
3294 if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
3295 (ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
3296 #if ZEND_ULONG_MAX == 0xFFFFFFFF
3297 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
3298 ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
3299 || (oflow1 == -1 && dval1 < -9007199254740991.))) {
3300 #else
3301 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
3302 #endif
3303 /* both values are integers overflown to the same side, and the
3304 * double comparison may have resulted in crucial accuracy lost */
3305 goto string_cmp;
3306 }
3307 if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
3308 if (ret1 != IS_DOUBLE) {
3309 if (oflow2) {
3310 /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
3311 return 0;
3312 }
3313 dval1 = (double) lval1;
3314 } else if (ret2 != IS_DOUBLE) {
3315 if (oflow1) {
3316 return 0;
3317 }
3318 dval2 = (double) lval2;
3319 } else if (dval1 == dval2 && !zend_finite(dval1)) {
3320 /* Both values overflowed and have the same sign,
3321 * so a numeric comparison would be inaccurate */
3322 goto string_cmp;
3323 }
3324 return dval1 == dval2;
3325 } else { /* they both have to be long's */
3326 return lval1 == lval2;
3327 }
3328 } else {
3329 string_cmp:
3330 return zend_string_equal_content(s1, s2);
3331 }
3332 }
3333 /* }}} */
3334
3335 ZEND_API int ZEND_FASTCALL zendi_smart_strcmp(zend_string *s1, zend_string *s2) /* {{{ */
3336 {
3337 uint8_t ret1, ret2;
3338 int oflow1, oflow2;
3339 zend_long lval1 = 0, lval2 = 0;
3340 double dval1 = 0.0, dval2 = 0.0;
3341
3342 if ((ret1 = is_numeric_string_ex(s1->val, s1->len, &lval1, &dval1, false, &oflow1, NULL)) &&
3343 (ret2 = is_numeric_string_ex(s2->val, s2->len, &lval2, &dval2, false, &oflow2, NULL))) {
3344 #if ZEND_ULONG_MAX == 0xFFFFFFFF
3345 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0. &&
3346 ((oflow1 == 1 && dval1 > 9007199254740991. /*0x1FFFFFFFFFFFFF*/)
3347 || (oflow1 == -1 && dval1 < -9007199254740991.))) {
3348 #else
3349 if (oflow1 != 0 && oflow1 == oflow2 && dval1 - dval2 == 0.) {
3350 #endif
3351 /* both values are integers overflowed to the same side, and the
3352 * double comparison may have resulted in crucial accuracy lost */
3353 goto string_cmp;
3354 }
3355 if ((ret1 == IS_DOUBLE) || (ret2 == IS_DOUBLE)) {
3356 if (ret1 != IS_DOUBLE) {
3357 if (oflow2) {
3358 /* 2nd operand is integer > LONG_MAX (oflow2==1) or < LONG_MIN (-1) */
3359 return -1 * oflow2;
3360 }
3361 dval1 = (double) lval1;
3362 } else if (ret2 != IS_DOUBLE) {
3363 if (oflow1) {
3364 return oflow1;
3365 }
3366 dval2 = (double) lval2;
3367 } else if (dval1 == dval2 && !zend_finite(dval1)) {
3368 /* Both values overflowed and have the same sign,
3369 * so a numeric comparison would be inaccurate */
3370 goto string_cmp;
3371 }
3372 dval1 = dval1 - dval2;
3373 return ZEND_NORMALIZE_BOOL(dval1);
3374 } else { /* they both have to be long's */
3375 return lval1 > lval2 ? 1 : (lval1 < lval2 ? -1 : 0);
3376 }
3377 } else {
3378 int strcmp_ret;
3379 string_cmp:
3380 strcmp_ret = zend_binary_strcmp(s1->val, s1->len, s2->val, s2->len);
3381 return ZEND_NORMALIZE_BOOL(strcmp_ret);
3382 }
3383 }
3384 /* }}} */
3385
3386 static int hash_zval_compare_function(zval *z1, zval *z2) /* {{{ */
3387 {
3388 return zend_compare(z1, z2);
3389 }
3390 /* }}} */
3391
3392 ZEND_API int ZEND_FASTCALL zend_compare_symbol_tables(HashTable *ht1, HashTable *ht2) /* {{{ */
3393 {
3394 return ht1 == ht2 ? 0 : zend_hash_compare(ht1, ht2, (compare_func_t) hash_zval_compare_function, 0);
3395 }
3396 /* }}} */
3397
3398 ZEND_API int ZEND_FASTCALL zend_compare_arrays(zval *a1, zval *a2) /* {{{ */
3399 {
3400 return zend_compare_symbol_tables(Z_ARRVAL_P(a1), Z_ARRVAL_P(a2));
3401 }
3402 /* }}} */
3403
3404 ZEND_API int ZEND_FASTCALL zend_compare_objects(zval *o1, zval *o2) /* {{{ */
3405 {
3406 if (Z_OBJ_P(o1) == Z_OBJ_P(o2)) {
3407 return 0;
3408 }
3409
3410 if (Z_OBJ_HT_P(o1)->compare == NULL) {
3411 return 1;
3412 } else {
3413 return Z_OBJ_HT_P(o1)->compare(o1, o2);
3414 }
3415 }
3416 /* }}} */
3417
3418 ZEND_API zend_string* ZEND_FASTCALL zend_long_to_str(zend_long num) /* {{{ */
3419 {
3420 if ((zend_ulong)num <= 9) {
3421 return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3422 } else {
3423 char buf[MAX_LENGTH_OF_LONG + 1];
3424 char *res = zend_print_long_to_buf(buf + sizeof(buf) - 1, num);
3425 zend_string *str = zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3426 GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3427 return str;
3428 }
3429 }
3430 /* }}} */
3431
3432 ZEND_API zend_string* ZEND_FASTCALL zend_ulong_to_str(zend_ulong num)
3433 {
3434 if (num <= 9) {
3435 return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3436 } else {
3437 char buf[MAX_LENGTH_OF_LONG + 1];
3438 char *res = zend_print_ulong_to_buf(buf + sizeof(buf) - 1, num);
3439 zend_string *str = zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3440 GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3441 return str;
3442 }
3443 }
3444
3445 /* buf points to the END of the buffer */
3446 static zend_always_inline char *zend_print_u64_to_buf(char *buf, uint64_t num64) {
3447 #if SIZEOF_ZEND_LONG == 8
3448 return zend_print_ulong_to_buf(buf, num64);
3449 #else
3450 *buf = '\0';
3451 while (num64 > ZEND_ULONG_MAX) {
3452 *--buf = (char) (num64 % 10) + '0';
3453 num64 /= 10;
3454 }
3455
3456 zend_ulong num = (zend_ulong) num64;
3457 do {
3458 *--buf = (char) (num % 10) + '0';
3459 num /= 10;
3460 } while (num > 0);
3461 return buf;
3462 #endif
3463 }
3464
3465 /* buf points to the END of the buffer */
3466 static zend_always_inline char *zend_print_i64_to_buf(char *buf, int64_t num) {
3467 if (num < 0) {
3468 char *result = zend_print_u64_to_buf(buf, ~((uint64_t) num) + 1);
3469 *--result = '-';
3470 return result;
3471 } else {
3472 return zend_print_u64_to_buf(buf, num);
3473 }
3474 }
3475
3476 ZEND_API zend_string* ZEND_FASTCALL zend_u64_to_str(uint64_t num)
3477 {
3478 if (num <= 9) {
3479 return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3480 } else {
3481 char buf[20 + 1];
3482 char *res = zend_print_u64_to_buf(buf + sizeof(buf) - 1, num);
3483 zend_string *str = zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3484 GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3485 return str;
3486 }
3487 }
3488
3489 ZEND_API zend_string* ZEND_FASTCALL zend_i64_to_str(int64_t num)
3490 {
3491 if ((uint64_t)num <= 9) {
3492 return ZSTR_CHAR((zend_uchar)'0' + (zend_uchar)num);
3493 } else {
3494 char buf[20 + 1];
3495 char *res = zend_print_i64_to_buf(buf + sizeof(buf) - 1, num);
3496 zend_string *str = zend_string_init(res, buf + sizeof(buf) - 1 - res, 0);
3497 GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3498 return str;
3499 }
3500 }
3501
3502 ZEND_API zend_string* ZEND_FASTCALL zend_double_to_str(double num)
3503 {
3504 char buf[ZEND_DOUBLE_MAX_LENGTH];
3505 /* Model snprintf precision behavior. */
3506 int precision = (int) EG(precision);
3507 zend_gcvt(num, precision ? precision : 1, '.', 'E', buf);
3508 zend_string *str = zend_string_init(buf, strlen(buf), 0);
3509 GC_ADD_FLAGS(str, IS_STR_VALID_UTF8);
3510 return str;
3511 }
3512
3513 ZEND_API uint8_t ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval) /* {{{ */
3514 {
3515 return is_numeric_string(ZSTR_VAL(str), ZSTR_LEN(str), lval, dval, false);
3516 }
3517 /* }}} */
3518
3519 ZEND_API uint8_t ZEND_FASTCALL _is_numeric_string_ex(const char *str, size_t length, zend_long *lval,
3520 double *dval, bool allow_errors, int *oflow_info, bool *trailing_data) /* {{{ */
3521 {
3522 const char *ptr;
3523 int digits = 0, dp_or_e = 0;
3524 double local_dval = 0.0;
3525 uint8_t type;
3526 zend_ulong tmp_lval = 0;
3527 int neg = 0;
3528
3529 if (!length) {
3530 return 0;
3531 }
3532
3533 if (oflow_info != NULL) {
3534 *oflow_info = 0;
3535 }
3536 if (trailing_data != NULL) {
3537 *trailing_data = false;
3538 }
3539
3540 /* Skip any whitespace
3541 * This is much faster than the isspace() function */
3542 while (*str == ' ' || *str == '\t' || *str == '\n' || *str == '\r' || *str == '\v' || *str == '\f') {
3543 str++;
3544 length--;
3545 }
3546 ptr = str;
3547
3548 if (*ptr == '-') {
3549 neg = 1;
3550 ptr++;
3551 } else if (*ptr == '+') {
3552 ptr++;
3553 }
3554
3555 if (ZEND_IS_DIGIT(*ptr)) {
3556 /* Skip any leading 0s */
3557 while (*ptr == '0') {
3558 ptr++;
3559 }
3560
3561 /* Count the number of digits. If a decimal point/exponent is found,
3562 * it's a double. Otherwise, if there's a dval or no need to check for
3563 * a full match, stop when there are too many digits for a long */
3564 for (type = IS_LONG; !(digits >= MAX_LENGTH_OF_LONG && (dval || allow_errors)); digits++, ptr++) {
3565 check_digits:
3566 if (ZEND_IS_DIGIT(*ptr)) {
3567 tmp_lval = tmp_lval * 10 + (*ptr) - '0';
3568 continue;
3569 } else if (*ptr == '.' && dp_or_e < 1) {
3570 goto process_double;
3571 } else if ((*ptr == 'e' || *ptr == 'E') && dp_or_e < 2) {
3572 const char *e = ptr + 1;
3573
3574 if (*e == '-' || *e == '+') {
3575 ptr = e++;
3576 }
3577 if (ZEND_IS_DIGIT(*e)) {
3578 goto process_double;
3579 }
3580 }
3581
3582 break;
3583 }
3584
3585 if (digits >= MAX_LENGTH_OF_LONG) {
3586 if (oflow_info != NULL) {
3587 *oflow_info = *str == '-' ? -1 : 1;
3588 }
3589 dp_or_e = -1;
3590 goto process_double;
3591 }
3592 } else if (*ptr == '.' && ZEND_IS_DIGIT(ptr[1])) {
3593 process_double:
3594 type = IS_DOUBLE;
3595
3596 /* If there's a dval, do the conversion; else continue checking
3597 * the digits if we need to check for a full match */
3598 if (dval) {
3599 local_dval = zend_strtod(str, &ptr);
3600 } else if (!allow_errors && dp_or_e != -1) {
3601 dp_or_e = (*ptr++ == '.') ? 1 : 2;
3602 goto check_digits;
3603 }
3604 } else {
3605 return 0;
3606 }
3607
3608 if (ptr != str + length) {
3609 const char *endptr = ptr;
3610 while (*endptr == ' ' || *endptr == '\t' || *endptr == '\n' || *endptr == '\r' || *endptr == '\v' || *endptr == '\f') {
3611 endptr++;
3612 length--;
3613 }
3614 if (ptr != str + length) {
3615 if (!allow_errors) {
3616 return 0;
3617 }
3618 if (trailing_data != NULL) {
3619 *trailing_data = true;
3620 }
3621 }
3622 }
3623
3624 if (type == IS_LONG) {
3625 if (digits == MAX_LENGTH_OF_LONG - 1) {
3626 int cmp = strcmp(&ptr[-digits], long_min_digits);
3627
3628 if (!(cmp < 0 || (cmp == 0 && *str == '-'))) {
3629 if (dval) {
3630 *dval = zend_strtod(str, NULL);
3631 }
3632 if (oflow_info != NULL) {
3633 *oflow_info = *str == '-' ? -1 : 1;
3634 }
3635
3636 return IS_DOUBLE;
3637 }
3638 }
3639
3640 if (lval) {
3641 if (neg) {
3642 tmp_lval = -tmp_lval;
3643 }
3644 *lval = (zend_long) tmp_lval;
3645 }
3646
3647 return IS_LONG;
3648 } else {
3649 if (dval) {
3650 *dval = local_dval;
3651 }
3652
3653 return IS_DOUBLE;
3654 }
3655 }
3656 /* }}} */
3657
3658 /*
3659 * String matching - Sunday algorithm
3660 * http://www.iti.fh-flensburg.de/lang/algorithmen/pattern/sundayen.htm
3661 */
3662 static zend_always_inline void zend_memnstr_ex_pre(unsigned int td[], const char *needle, size_t needle_len, int reverse) /* {{{ */ {
3663 int i;
3664
3665 for (i = 0; i < 256; i++) {
3666 td[i] = needle_len + 1;
3667 }
3668
3669 if (reverse) {
3670 for (i = needle_len - 1; i >= 0; i--) {
3671 td[(unsigned char)needle[i]] = i + 1;
3672 }
3673 } else {
3674 size_t i;
3675
3676 for (i = 0; i < needle_len; i++) {
3677 td[(unsigned char)needle[i]] = (int)needle_len - i;
3678 }
3679 }
3680 }
3681 /* }}} */
3682
3683 ZEND_API const char* ZEND_FASTCALL zend_memnstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3684 {
3685 unsigned int td[256];
3686 size_t i;
3687 const char *p;
3688
3689 if (needle_len == 0 || (end - haystack) < needle_len) {
3690 return NULL;
3691 }
3692
3693 zend_memnstr_ex_pre(td, needle, needle_len, 0);
3694
3695 p = haystack;
3696 end -= needle_len;
3697
3698 while (p <= end) {
3699 for (i = 0; i < needle_len; i++) {
3700 if (needle[i] != p[i]) {
3701 break;
3702 }
3703 }
3704 if (i == needle_len) {
3705 return p;
3706 }
3707 if (UNEXPECTED(p == end)) {
3708 return NULL;
3709 }
3710 p += td[(unsigned char)(p[needle_len])];
3711 }
3712
3713 return NULL;
3714 }
3715 /* }}} */
3716
3717 ZEND_API const char* ZEND_FASTCALL zend_memnrstr_ex(const char *haystack, const char *needle, size_t needle_len, const char *end) /* {{{ */
3718 {
3719 unsigned int td[256];
3720 size_t i;
3721 const char *p;
3722
3723 if (needle_len == 0 || (end - haystack) < needle_len) {
3724 return NULL;
3725 }
3726
3727 zend_memnstr_ex_pre(td, needle, needle_len, 1);
3728
3729 p = end;
3730 p -= needle_len;
3731
3732 while (p >= haystack) {
3733 for (i = 0; i < needle_len; i++) {
3734 if (needle[i] != p[i]) {
3735 break;
3736 }
3737 }
3738
3739 if (i == needle_len) {
3740 return (const char *)p;
3741 }
3742
3743 if (UNEXPECTED(p == haystack)) {
3744 return NULL;
3745 }
3746
3747 p -= td[(unsigned char)(p[-1])];
3748 }
3749
3750 return NULL;
3751 }
3752 /* }}} */
3753
3754 #if SIZEOF_ZEND_LONG == 4
3755 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d) /* {{{ */
3756 {
3757 double two_pow_32 = pow(2., 32.),
3758 dmod;
3759
3760 dmod = fmod(d, two_pow_32);
3761 if (dmod < 0) {
3762 /* we're going to make this number positive; call ceil()
3763 * to simulate rounding towards 0 of the negative number */
3764 dmod = ceil(dmod) + two_pow_32;
3765 }
3766 return (zend_long)(zend_ulong)dmod;
3767 }
3768 #else
3769 ZEND_API zend_long ZEND_FASTCALL zend_dval_to_lval_slow(double d)
3770 {
3771 double two_pow_64 = pow(2., 64.),
3772 dmod;
3773
3774 dmod = fmod(d, two_pow_64);
3775 if (dmod < 0) {
3776 /* no need to call ceil; original double must have had no
3777 * fractional part, hence dmod does not have one either */
3778 dmod += two_pow_64;
3779 }
3780 return (zend_long)(zend_ulong)dmod;
3781 }
3782 /* }}} */
3783 #endif
3784