Coverage Report

Created: 2025-12-14 06:10

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