Coverage Report

Created: 2026-10-28 06:20

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