Coverage Report

Created: 2026-09-14 06:25

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