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