Coverage Report

Created: 2026-04-01 06:49

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