LCOV - code coverage report
Current view: top level - /ext - colopl_bc_php74.c (source / functions) Coverage Total Hit
Test: Extension code coverage Lines: 67.5 % 1264 853
Test Date: 2026-06-22 04:49:10 Functions: 73.5 % 102 75

            Line data    Source code
       1              : /*
       2              :   +----------------------------------------------------------------------+
       3              :   | COLOPL PHP Backwards Compatibility Extension.                        |
       4              :   +----------------------------------------------------------------------+
       5              :   | Copyright (c) COLOPL, Inc.                                           |
       6              :   +----------------------------------------------------------------------+
       7              :   | This source file is subject to the BSD-3-Clause license that is      |
       8              :   | bundled with this package in the file LICENSE.                       |
       9              :   +----------------------------------------------------------------------+
      10              :   | Author: Go Kudo <g-kudo@colopl.co.jp>                                |
      11              :   +----------------------------------------------------------------------+
      12              : */
      13              : 
      14              : #ifdef HAVE_CONFIG_H
      15              : # include "config.h"
      16              : #endif
      17              : 
      18              : #include <string.h>
      19              : 
      20              : #include "php_colopl_bc.h"
      21              : 
      22              : #include "ext/standard/php_array.h"
      23              : #include "ext/standard/php_string.h"
      24              : #include "zend_exceptions.h"
      25              : #include "zend_operators.h"
      26              : 
      27              : #if PHP_VERSION_ID < 80000
      28              : 
      29              : static void php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAMETERS)
      30              : {
      31              :         zend_internal_function *fn;
      32              :         zend_string *function_name = execute_data->func->common.function_name;
      33              :         const char *native_name = ZSTR_VAL(function_name);
      34              :         const char *namespace_separator = strrchr(native_name, '\\');
      35              : 
      36              :         if (namespace_separator != NULL) {
      37              :                 native_name = namespace_separator + 1;
      38              :         }
      39              : 
      40              :         fn = zend_hash_str_find_ptr(EG(function_table), native_name, strlen(native_name));
      41              :         if (UNEXPECTED(fn == NULL)) {
      42              :                 zend_throw_error(NULL, "Internal function %s() is not available", native_name);
      43              :                 return;
      44              :         }
      45              : 
      46              :         fn->handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
      47              : }
      48              : 
      49              : static inline int php_colopl_bc_normalize_compare_result(int result)
      50              : {
      51              :         return result > 0 ? 1 : (result < 0 ? -1 : 0);
      52              : }
      53              : 
      54              : PHP_INI_MH(OnUpdateCompareMode)
      55              : {
      56              :         return OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
      57              : }
      58              : 
      59              : PHP_INI_MH(OnUpdateSortMode)
      60              : {
      61              :         return OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage);
      62              : }
      63              : 
      64              : int php_colopl_bc_compare(zval *op1, zval *op2)
      65              : {
      66              :         zval result;
      67              : 
      68              :         if (compare_function(&result, op1, op2) == FAILURE) {
      69              :                 return 0;
      70              :         }
      71              : 
      72              :         return php_colopl_bc_normalize_compare_result(Z_LVAL(result));
      73              : }
      74              : 
      75              : PHP_FUNCTION(Colopl_ColoplBc_Php74_ksort)
      76              : {
      77              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
      78              : }
      79              : 
      80              : PHP_FUNCTION(Colopl_ColoplBc_Php74_krsort)
      81              : {
      82              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
      83              : }
      84              : 
      85              : PHP_FUNCTION(Colopl_ColoplBc_Php74_asort)
      86              : {
      87              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
      88              : }
      89              : 
      90              : PHP_FUNCTION(Colopl_ColoplBc_Php74_arsort)
      91              : {
      92              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
      93              : }
      94              : 
      95              : PHP_FUNCTION(Colopl_ColoplBc_Php74_sort)
      96              : {
      97              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
      98              : }
      99              : 
     100              : PHP_FUNCTION(Colopl_ColoplBc_Php74_rsort)
     101              : {
     102              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
     103              : }
     104              : 
     105              : PHP_FUNCTION(Colopl_ColoplBc_Php74_usort)
     106              : {
     107              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
     108              : }
     109              : 
     110              : PHP_FUNCTION(Colopl_ColoplBc_Php74_uasort)
     111              : {
     112              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
     113              : }
     114              : 
     115              : PHP_FUNCTION(Colopl_ColoplBc_Php74_uksort)
     116              : {
     117              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
     118              : }
     119              : 
     120              : PHP_FUNCTION(Colopl_ColoplBc_Php74_in_array)
     121              : {
     122              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
     123              : }
     124              : 
     125              : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_search)
     126              : {
     127              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
     128              : }
     129              : 
     130              : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_keys)
     131              : {
     132              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
     133              : }
     134              : 
     135              : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_multisort)
     136              : {
     137              :         php_colopl_bc_call_native_function(INTERNAL_FUNCTION_PARAM_PASSTHRU);
     138              : }
     139              : 
     140              : PHP_FUNCTION(Colopl_ColoplBc_Php74_eq)
     141              : {
     142              :         zval *op1, *op2;
     143              : 
     144              :         ZEND_PARSE_PARAMETERS_START(2, 2)
     145              :                 Z_PARAM_ZVAL(op1)
     146              :                 Z_PARAM_ZVAL(op2)
     147              :         ZEND_PARSE_PARAMETERS_END();
     148              : 
     149              :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) == 0);
     150              : }
     151              : 
     152              : PHP_FUNCTION(Colopl_ColoplBc_Php74_neq)
     153              : {
     154              :         zval *op1, *op2;
     155              : 
     156              :         ZEND_PARSE_PARAMETERS_START(2, 2)
     157              :                 Z_PARAM_ZVAL(op1)
     158              :                 Z_PARAM_ZVAL(op2)
     159              :         ZEND_PARSE_PARAMETERS_END();
     160              : 
     161              :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) != 0);
     162              : }
     163              : 
     164              : PHP_FUNCTION(Colopl_ColoplBc_Php74_lt)
     165              : {
     166              :         zval *op1, *op2;
     167              : 
     168              :         ZEND_PARSE_PARAMETERS_START(2, 2)
     169              :                 Z_PARAM_ZVAL(op1)
     170              :                 Z_PARAM_ZVAL(op2)
     171              :         ZEND_PARSE_PARAMETERS_END();
     172              : 
     173              :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) < 0);
     174              : }
     175              : 
     176              : PHP_FUNCTION(Colopl_ColoplBc_Php74_lte)
     177              : {
     178              :         zval *op1, *op2;
     179              : 
     180              :         ZEND_PARSE_PARAMETERS_START(2, 2)
     181              :                 Z_PARAM_ZVAL(op1)
     182              :                 Z_PARAM_ZVAL(op2)
     183              :         ZEND_PARSE_PARAMETERS_END();
     184              : 
     185              :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) <= 0);
     186              : }
     187              : 
     188              : PHP_FUNCTION(Colopl_ColoplBc_Php74_gt)
     189              : {
     190              :         zval *op1, *op2;
     191              : 
     192              :         ZEND_PARSE_PARAMETERS_START(2, 2)
     193              :                 Z_PARAM_ZVAL(op1)
     194              :                 Z_PARAM_ZVAL(op2)
     195              :         ZEND_PARSE_PARAMETERS_END();
     196              : 
     197              :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) > 0);
     198              : }
     199              : 
     200              : PHP_FUNCTION(Colopl_ColoplBc_Php74_gte)
     201              : {
     202              :         zval *op1, *op2;
     203              : 
     204              :         ZEND_PARSE_PARAMETERS_START(2, 2)
     205              :                 Z_PARAM_ZVAL(op1)
     206              :                 Z_PARAM_ZVAL(op2)
     207              :         ZEND_PARSE_PARAMETERS_END();
     208              : 
     209              :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) >= 0);
     210              : }
     211              : 
     212              : PHP_FUNCTION(Colopl_ColoplBc_Php74_spaceship)
     213              : {
     214              :         zval *op1, *op2;
     215              : 
     216              :         ZEND_PARSE_PARAMETERS_START(2, 2)
     217              :                 Z_PARAM_ZVAL(op1)
     218              :                 Z_PARAM_ZVAL(op2)
     219              :         ZEND_PARSE_PARAMETERS_END();
     220              : 
     221              :         RETURN_LONG(php_colopl_bc_compare(op1, op2));
     222              : }
     223              : 
     224              : #else
     225              : 
     226              : /* zend_operators.c */
     227              : 
     228              : #define COLOPL_BC_TYPE_PAIR(t1,t2) (((t1) << 4) | (t2))
     229              : 
     230              : #define COLOPL_BC_MULTISORT_ORDER       0
     231              : #define COLOPL_BC_MULTISORT_TYPE        1
     232              : #define COLOPL_BC_MULTISORT_LAST        2
     233              : 
     234              : typedef struct _php_colopl_bc_snapshot_context {
     235              :         HashTable arrays;
     236              :         HashTable objects;
     237              : } php_colopl_bc_snapshot_context;
     238              : 
     239              : typedef struct _php_colopl_bc_diagnostic_error_state {
     240              :         int error_reporting;
     241              :         int user_error_handler_error_reporting;
     242              :         bool record_errors;
     243              : } php_colopl_bc_diagnostic_error_state;
     244              : 
     245              : typedef struct _php_colopl_bc_user_sort_zero_pair {
     246              :         uint32_t first;
     247              :         uint32_t second;
     248              : } php_colopl_bc_user_sort_zero_pair;
     249              : 
     250              : typedef struct _php_colopl_bc_user_sort_context {
     251              :         php_colopl_bc_user_sort_zero_pair *zero_pairs;
     252              :         uint32_t zero_pair_count;
     253              :         uint32_t zero_pair_capacity;
     254              : } php_colopl_bc_user_sort_context;
     255              : 
     256              : static int legacy_compare_fast(zval *op1, zval *op2);
     257              : 
     258        12104 : static inline void php_colopl_bc_snapshot_context_init(php_colopl_bc_snapshot_context *ctx)
     259              : {
     260        12104 :         zend_hash_init(&ctx->arrays, 8, NULL, NULL, 0);
     261        12104 :         zend_hash_init(&ctx->objects, 8, NULL, NULL, 0);
     262        12104 : }
     263              : 
     264        12104 : static inline void php_colopl_bc_snapshot_context_destroy(php_colopl_bc_snapshot_context *ctx)
     265              : {
     266        12104 :         zend_hash_destroy(&ctx->objects);
     267        12104 :         zend_hash_destroy(&ctx->arrays);
     268        12104 : }
     269              : 
     270        10308 : static inline void php_colopl_bc_diagnostic_error_state_suppress(php_colopl_bc_diagnostic_error_state *state)
     271              : {
     272        10308 :         state->error_reporting = EG(error_reporting);
     273        10308 :         state->user_error_handler_error_reporting = EG(user_error_handler_error_reporting);
     274        10308 :         state->record_errors = EG(record_errors);
     275              : 
     276        10308 :         EG(error_reporting) = 0;
     277        10308 :         EG(user_error_handler_error_reporting) = 0;
     278        10308 :         EG(record_errors) = false;
     279        10308 : }
     280              : 
     281        10308 : static inline void php_colopl_bc_diagnostic_error_state_restore(php_colopl_bc_diagnostic_error_state *state)
     282              : {
     283        10308 :         EG(record_errors) = state->record_errors;
     284        10308 :         EG(user_error_handler_error_reporting) = state->user_error_handler_error_reporting;
     285        10308 :         EG(error_reporting) = state->error_reporting;
     286        10308 : }
     287              : 
     288        10308 : static inline bool php_colopl_bc_clear_diagnostic_exception(void)
     289              : {
     290        10308 :         if (EG(exception)) {
     291            0 :                 zend_clear_exception();
     292              : 
     293            0 :                 return true;
     294              :         }
     295              : 
     296        10308 :         return false;
     297              : }
     298              : 
     299          908 : static inline void php_colopl_bc_log_incompatibility(const char *message)
     300              : {
     301          908 :         const char *filename = zend_get_executed_filename();
     302          908 :         uint32_t lineno = zend_get_executed_lineno();
     303              :         char *log_message;
     304              : 
     305          908 :         if (filename != NULL && filename[0] != '\0') {
     306          908 :                 spprintf(&log_message, 0, "%s in %s on line %u", message, filename, lineno);
     307          908 :                 php_log_err_with_severity(log_message, LOG_NOTICE);
     308          908 :                 efree(log_message);
     309              : 
     310          908 :                 return;
     311              :         }
     312              : 
     313            0 :         php_log_err_with_severity(message, LOG_NOTICE);
     314              : }
     315              : 
     316        24900 : static inline bool php_colopl_bc_zval_contains_object(zval *op, HashTable *seen_arrays)
     317              : {
     318              :         zend_array *array;
     319              :         zval *entry;
     320              : 
     321        24900 :         ZVAL_DEREF(op);
     322        24900 :         if (Z_TYPE_P(op) == IS_INDIRECT) {
     323            0 :                 op = Z_INDIRECT_P(op);
     324            0 :                 ZVAL_DEREF(op);
     325              :         }
     326              : 
     327        24900 :         switch (Z_TYPE_P(op)) {
     328            4 :                 case IS_OBJECT:
     329            4 :                         return true;
     330         1248 :                 case IS_ARRAY:
     331         1248 :                         array = Z_ARRVAL_P(op);
     332         1248 :                         if (zend_hash_index_exists(seen_arrays, (zend_ulong)(uintptr_t) array)) {
     333           44 :                                 return false;
     334              :                         }
     335         1204 :                         zend_hash_index_add_empty_element(seen_arrays, (zend_ulong)(uintptr_t) array);
     336              : 
     337         5932 :                         ZEND_HASH_FOREACH_VAL(array, entry) {
     338         4732 :                                 if (php_colopl_bc_zval_contains_object(entry, seen_arrays)) {
     339            4 :                                         return true;
     340              :                                 }
     341              :                         } ZEND_HASH_FOREACH_END();
     342              : 
     343         1200 :                         return false;
     344        23648 :                 default:
     345        23648 :                         return false;
     346              :         }
     347              : }
     348              : 
     349        10020 : static inline bool php_colopl_bc_zvals_contain_object(zval *op1, zval *op2)
     350              : {
     351              :         HashTable seen_arrays;
     352              :         bool contains_object;
     353              : 
     354        10020 :         zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
     355        10020 :         contains_object =
     356        20040 :                 php_colopl_bc_zval_contains_object(op1, &seen_arrays) ||
     357        10020 :                 php_colopl_bc_zval_contains_object(op2, &seen_arrays);
     358        10020 :         zend_hash_destroy(&seen_arrays);
     359              : 
     360        10020 :         return contains_object;
     361              : }
     362              : 
     363          108 : static inline bool php_colopl_bc_zval_contains_child_array(zval *op)
     364              : {
     365              :         zval *entry;
     366              : 
     367          108 :         ZVAL_DEREF(op);
     368          108 :         if (Z_TYPE_P(op) == IS_INDIRECT) {
     369            0 :                 op = Z_INDIRECT_P(op);
     370            0 :                 ZVAL_DEREF(op);
     371              :         }
     372              : 
     373          108 :         if (Z_TYPE_P(op) != IS_ARRAY) {
     374            0 :                 return false;
     375              :         }
     376              : 
     377         3192 :         ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(op), entry) {
     378         3092 :                 ZVAL_DEREF(entry);
     379         3092 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
     380            0 :                         entry = Z_INDIRECT_P(entry);
     381            0 :                         ZVAL_DEREF(entry);
     382              :                 }
     383         3092 :                 if (Z_TYPE_P(entry) == IS_ARRAY) {
     384            8 :                         return true;
     385              :                 }
     386              :         } ZEND_HASH_FOREACH_END();
     387              : 
     388          100 :         return false;
     389              : }
     390              : 
     391        25236 : static inline bool php_colopl_bc_zval_contains_recursive_array_ex(zval *op, HashTable *seen_arrays, HashTable *active_arrays)
     392              : {
     393              :         zend_array *array;
     394              :         zend_ulong key;
     395              :         zval *entry;
     396        25236 :         bool contains_recursive_array = false;
     397              : 
     398        25236 :         ZVAL_DEREF(op);
     399        25236 :         if (Z_TYPE_P(op) == IS_INDIRECT) {
     400            0 :                 op = Z_INDIRECT_P(op);
     401            0 :                 ZVAL_DEREF(op);
     402              :         }
     403              : 
     404        25236 :         if (Z_TYPE_P(op) != IS_ARRAY) {
     405        24016 :                 return false;
     406              :         }
     407              : 
     408         1220 :         array = Z_ARRVAL_P(op);
     409         1220 :         key = (zend_ulong)(uintptr_t) array;
     410         1220 :         if (zend_hash_index_exists(active_arrays, key)) {
     411            0 :                 return true;
     412              :         }
     413         1220 :         if (zend_hash_index_exists(seen_arrays, key)) {
     414           40 :                 return false;
     415              :         }
     416              : 
     417         1180 :         zend_hash_index_add_empty_element(active_arrays, key);
     418         5884 :         ZEND_HASH_FOREACH_VAL(array, entry) {
     419         4704 :                 if (php_colopl_bc_zval_contains_recursive_array_ex(entry, seen_arrays, active_arrays)) {
     420            0 :                         contains_recursive_array = true;
     421            0 :                         break;
     422              :                 }
     423              :         } ZEND_HASH_FOREACH_END();
     424         1180 :         zend_hash_index_del(active_arrays, key);
     425         1180 :         if (contains_recursive_array) {
     426            0 :                 return true;
     427              :         }
     428         1180 :         zend_hash_index_add_empty_element(seen_arrays, key);
     429              : 
     430         1180 :         return false;
     431              : }
     432              : 
     433          116 : static inline bool php_colopl_bc_zval_contains_recursive_array(zval *op)
     434              : {
     435              :         HashTable seen_arrays, active_arrays;
     436              :         bool contains_recursive_array;
     437              : 
     438          116 :         zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
     439          116 :         zend_hash_init(&active_arrays, 8, NULL, NULL, 0);
     440          116 :         contains_recursive_array = php_colopl_bc_zval_contains_recursive_array_ex(op, &seen_arrays, &active_arrays);
     441          116 :         zend_hash_destroy(&active_arrays);
     442          116 :         zend_hash_destroy(&seen_arrays);
     443              : 
     444          116 :         return contains_recursive_array;
     445              : }
     446              : 
     447        10208 : static inline bool php_colopl_bc_zvals_contain_recursive_array(zval *op1, zval *op2)
     448              : {
     449              :         HashTable seen_arrays, active_arrays;
     450              :         bool contains_recursive_array;
     451              : 
     452        10208 :         zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
     453        10208 :         zend_hash_init(&active_arrays, 8, NULL, NULL, 0);
     454        10208 :         contains_recursive_array =
     455        20416 :                 php_colopl_bc_zval_contains_recursive_array_ex(op1, &seen_arrays, &active_arrays) ||
     456        10208 :                 php_colopl_bc_zval_contains_recursive_array_ex(op2, &seen_arrays, &active_arrays);
     457        10208 :         zend_hash_destroy(&active_arrays);
     458        10208 :         zend_hash_destroy(&seen_arrays);
     459              : 
     460        10208 :         return contains_recursive_array;
     461              : }
     462              : 
     463           16 : static inline bool php_colopl_bc_zval_is_snapshot_safe_object_property(zval *op)
     464              : {
     465              :         HashTable seen_arrays;
     466              :         bool contains_object;
     467              : 
     468           16 :         if (php_colopl_bc_zval_contains_recursive_array(op)) {
     469            0 :                 return false;
     470              :         }
     471              : 
     472           16 :         zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
     473           16 :         contains_object = php_colopl_bc_zval_contains_object(op, &seen_arrays);
     474           16 :         zend_hash_destroy(&seen_arrays);
     475              : 
     476           16 :         return !contains_object;
     477              : }
     478              : 
     479          376 : static inline bool php_colopl_bc_object_is_snapshot_safe_for_native_compare(zend_object *object)
     480              : {
     481              :         zend_ulong num_key;
     482              :         zend_string *str_key;
     483              :         zval *entry, *prop;
     484              :         uint32_t i;
     485              :         ptrdiff_t offset;
     486              : 
     487          376 :         if (object->handlers != &std_object_handlers) {
     488            0 :                 return false;
     489              :         }
     490              : 
     491          392 :         for (i = 0; i < object->ce->default_properties_count; i++) {
     492           16 :                 prop = object->properties_table + i;
     493           16 :                 if (Z_TYPE_P(prop) == IS_UNDEF) {
     494            0 :                         continue;
     495              :                 }
     496           16 :                 if (!php_colopl_bc_zval_is_snapshot_safe_object_property(prop)) {
     497            0 :                         return false;
     498              :                 }
     499              :         }
     500              : 
     501          376 :         if (object->properties == NULL || zend_hash_num_elements(object->properties) == 0) {
     502          376 :                 return true;
     503              :         }
     504              : 
     505            0 :         ZEND_HASH_FOREACH_KEY_VAL(object->properties, num_key, str_key, entry) {
     506            0 :                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
     507            0 :                         offset = Z_INDIRECT_P(entry) - object->properties_table;
     508            0 :                         if (offset >= 0 && offset < object->ce->default_properties_count) {
     509            0 :                                 continue;
     510              :                         }
     511            0 :                         entry = Z_INDIRECT_P(entry);
     512              :                 }
     513              : 
     514            0 :                 if (!php_colopl_bc_zval_is_snapshot_safe_object_property(entry)) {
     515            0 :                         return false;
     516              :                 }
     517              :         } ZEND_HASH_FOREACH_END();
     518              : 
     519            0 :         return true;
     520              : }
     521              : 
     522        11924 : static inline bool php_colopl_bc_zvals_allow_native_compare_snapshot(zval *op1, zval *op2)
     523              : {
     524        11924 :         ZVAL_DEREF(op1);
     525        11924 :         ZVAL_DEREF(op2);
     526              : 
     527        11924 :         if (Z_TYPE_P(op1) == IS_INDIRECT) {
     528            0 :                 op1 = Z_INDIRECT_P(op1);
     529            0 :                 ZVAL_DEREF(op1);
     530              :         }
     531              : 
     532        11924 :         if (Z_TYPE_P(op2) == IS_INDIRECT) {
     533            0 :                 op2 = Z_INDIRECT_P(op2);
     534            0 :                 ZVAL_DEREF(op2);
     535              :         }
     536        11924 :         if (Z_TYPE_P(op1) == IS_OBJECT || Z_TYPE_P(op2) == IS_OBJECT) {
     537         2956 :                 return Z_TYPE_P(op1) == IS_OBJECT &&
     538         1240 :                         Z_TYPE_P(op2) == IS_OBJECT &&
     539         3144 :                         php_colopl_bc_object_is_snapshot_safe_for_native_compare(Z_OBJ_P(op1)) &&
     540          188 :                         php_colopl_bc_object_is_snapshot_safe_for_native_compare(Z_OBJ_P(op2))
     541              :                 ;
     542              :         }
     543              : 
     544        10020 :         return !php_colopl_bc_zvals_contain_object(op1, op2);
     545              : }
     546              : 
     547        25236 : static inline bool php_colopl_bc_snapshot_zval(zval *dst, zval *src, php_colopl_bc_snapshot_context *ctx)
     548              : {
     549              :         zend_object *src_object, *object, *cached_obj;
     550              :         zend_array *src_array, *array, *cached_arr;
     551              :         zend_ulong num_key;
     552              :         zend_string *str_key;
     553              :         zval *entry, new_entry, *src_prop, *dst_prop;
     554              :         uint32_t i;
     555              :         ptrdiff_t offset;
     556              : 
     557        25236 :         ZVAL_DEREF(src);
     558              : 
     559        25236 :         switch (Z_TYPE_P(src)) {
     560         1220 :                 case IS_ARRAY: {
     561         1220 :                         src_array = Z_ARRVAL_P(src);
     562         1220 :                         cached_arr = zend_hash_index_find_ptr(&ctx->arrays, (zend_ulong)(uintptr_t) src_array);
     563         1220 :                         if (cached_arr != NULL) {
     564           40 :                                 GC_ADDREF(cached_arr);
     565           40 :                                 ZVAL_ARR(dst, cached_arr);
     566              : 
     567           40 :                                 return true;
     568              :                         }
     569              : 
     570         1180 :                         array = zend_new_array(zend_hash_num_elements(src_array));
     571         1180 :                         ZVAL_ARR(dst, array);
     572         1180 :                         zend_hash_index_update_ptr(&ctx->arrays, (zend_ulong)(uintptr_t) src_array, array);
     573              : 
     574         5884 :                         ZEND_HASH_FOREACH_KEY_VAL(src_array, num_key, str_key, entry) {
     575         4704 :                                 if (Z_TYPE_P(entry) == IS_INDIRECT) {
     576            0 :                                         entry = Z_INDIRECT_P(entry);
     577              :                                 }
     578              : 
     579         4704 :                                 if (!php_colopl_bc_snapshot_zval(&new_entry, entry, ctx)) {
     580            0 :                                         zval_ptr_dtor(dst);
     581            0 :                                         ZVAL_UNDEF(dst);
     582              : 
     583            0 :                                         return false;
     584              :                                 }
     585              : 
     586         4704 :                                 if (str_key) {
     587         2296 :                                         zend_hash_update(array, str_key, &new_entry);
     588              :                                 } else {
     589         2408 :                                         zend_hash_index_update(array, num_key, &new_entry);
     590              :                                 }
     591              :                         } ZEND_HASH_FOREACH_END();
     592              : 
     593         1180 :                         return true;
     594              :                 }
     595          376 :                 case IS_OBJECT: {
     596          376 :                         src_object = Z_OBJ_P(src);
     597          376 :                         cached_obj = zend_hash_index_find_ptr(&ctx->objects, (zend_ulong)(uintptr_t) src_object);
     598          376 :                         if (cached_obj != NULL) {
     599           60 :                                 GC_ADDREF(cached_obj);
     600           60 :                                 ZVAL_OBJ(dst, cached_obj);
     601              : 
     602           60 :                                 return true;
     603              :                         }
     604              : 
     605          316 :                         if (src_object->handlers != &std_object_handlers) {
     606            0 :                                 return false;
     607              :                         }
     608              : 
     609          316 :                         object = zend_objects_new(src_object->ce);
     610              : 
     611          316 :                         zend_object_store_ctor_failed(object);
     612          316 :                         ZVAL_OBJ(dst, object);
     613          316 :                         zend_hash_index_update_ptr(&ctx->objects, (zend_ulong)(uintptr_t) src_object, object);
     614              : 
     615          332 :                         for (i = 0; i < src_object->ce->default_properties_count; i++) {
     616           16 :                                 src_prop = src_object->properties_table + i;
     617           16 :                                 dst_prop = object->properties_table + i;
     618              : 
     619           16 :                                 ZVAL_UNDEF(dst_prop);
     620           16 :                                 Z_PROP_FLAG_P(dst_prop) = Z_PROP_FLAG_P(src_prop);
     621              : 
     622           16 :                                 if (Z_TYPE_P(src_prop) == IS_UNDEF) {
     623            0 :                                         continue;
     624              :                                 }
     625              : 
     626           16 :                                 if (!php_colopl_bc_snapshot_zval(dst_prop, src_prop, ctx)) {
     627            0 :                                         zval_ptr_dtor(dst);
     628            0 :                                         ZVAL_UNDEF(dst);
     629              : 
     630            0 :                                         return false;
     631              :                                 }
     632              : 
     633           16 :                                 Z_PROP_FLAG_P(dst_prop) = Z_PROP_FLAG_P(src_prop);
     634              :                         }
     635              : 
     636          316 :                         if (src_object->properties != NULL && zend_hash_num_elements(src_object->properties) > 0) {
     637            0 :                                 object->properties = zend_new_array(zend_hash_num_elements(src_object->properties));
     638            0 :                                 zend_hash_real_init_mixed(object->properties);
     639              : 
     640            0 :                                 ZEND_HASH_FOREACH_KEY_VAL(src_object->properties, num_key, str_key, entry) {
     641            0 :                                         if (Z_TYPE_P(entry) == IS_INDIRECT) {
     642            0 :                                                 offset = Z_INDIRECT_P(entry) - src_object->properties_table;
     643            0 :                                                 if (offset >= 0 && offset < src_object->ce->default_properties_count) {
     644            0 :                                                         ZVAL_INDIRECT(&new_entry, object->properties_table + offset);
     645              :                                                 } else {
     646            0 :                                                         entry = Z_INDIRECT_P(entry);
     647            0 :                                                         if (!php_colopl_bc_snapshot_zval(&new_entry, entry, ctx)) {
     648            0 :                                                                 zval_ptr_dtor(dst);
     649            0 :                                                                 ZVAL_UNDEF(dst);
     650              : 
     651            0 :                                                                 return false;
     652              :                                                         }
     653              :                                                 }
     654              :                                         } else {
     655            0 :                                                 if (!php_colopl_bc_snapshot_zval(&new_entry, entry, ctx)) {
     656            0 :                                                         zval_ptr_dtor(dst);
     657            0 :                                                         ZVAL_UNDEF(dst);
     658              : 
     659            0 :                                                         return false;
     660              :                                                 }
     661            0 :                                                 Z_PROP_FLAG_P(&new_entry) = Z_PROP_FLAG_P(entry);
     662              :                                         }
     663              : 
     664            0 :                                         if (str_key) {
     665            0 :                                                 zend_hash_update(object->properties, str_key, &new_entry);
     666              :                                         } else {
     667            0 :                                                 zend_hash_index_update(object->properties, num_key, &new_entry);
     668              :                                         }
     669              :                                 } ZEND_HASH_FOREACH_END();
     670              :                         }
     671              : 
     672          316 :                         return true;
     673              :                 }
     674        23640 :                 default:
     675        23640 :                         ZVAL_DUP(dst, src);
     676        23640 :                         return true;
     677              :         }
     678              : }
     679              : 
     680        80800 : static inline zval *php_colopl_bc_hash_get_ordered_value(HashTable *ht, uint32_t *pos, zend_ulong *num_key, zend_string **str_key)
     681              : {
     682              :         zval *value;
     683              :         Bucket *bucket;
     684              : 
     685        80800 :         if (HT_IS_PACKED(ht)) {
     686        55800 :                 while (*pos < ht->nNumUsed) {
     687              : #if PHP_VERSION_ID >= 80200
     688        55752 :                         value = ht->arPacked + *pos;
     689        55752 :                         *num_key = *pos;
     690              : #else
     691              :                         bucket = ht->arData + *pos;
     692              :                         value = &bucket->val;
     693              :                         *num_key = bucket->h;
     694              : #endif
     695        55752 :                         *str_key = NULL;
     696        55752 :                         (*pos)++;
     697        55752 :                         if (Z_TYPE_P(value) != IS_UNDEF) {
     698        55752 :                                 return value;
     699              :                         }
     700              :                 }
     701              :         } else {
     702        25000 :                 while (*pos < ht->nNumUsed) {
     703        24992 :                         bucket = ht->arData + *pos;
     704        24992 :                         (*pos)++;
     705        24992 :                         if (Z_TYPE(bucket->val) != IS_UNDEF) {
     706        24992 :                                 *num_key = bucket->h;
     707        24992 :                                 *str_key = bucket->key;
     708        24992 :                                 return &bucket->val;
     709              :                         }
     710              :                 }
     711              :         }
     712              : 
     713           56 :         return NULL;
     714              : }
     715              : 
     716           68 : static inline void php_colopl_bc_user_sort_context_init(php_colopl_bc_user_sort_context *ctx)
     717              : {
     718           68 :         ctx->zero_pairs = NULL;
     719           68 :         ctx->zero_pair_count = 0;
     720           68 :         ctx->zero_pair_capacity = 0;
     721           68 : }
     722              : 
     723           68 : static inline void php_colopl_bc_user_sort_context_destroy(php_colopl_bc_user_sort_context *ctx)
     724              : {
     725           68 :         if (ctx->zero_pairs != NULL) {
     726           64 :                 efree(ctx->zero_pairs);
     727              :         }
     728           68 : }
     729              : 
     730         7468 : static inline void php_colopl_bc_user_sort_context_record_zero_pair(Bucket *first, Bucket *second)
     731              : {
     732         7468 :         php_colopl_bc_user_sort_context *ctx = COLOPL_BC_G(php74_user_sort_context);
     733              :         uint32_t first_pos, second_pos, new_capacity;
     734              : 
     735         7468 :         if (ctx == NULL) {
     736          600 :                 return;
     737              :         }
     738              : 
     739         6868 :         first_pos = Z_EXTRA(first->val);
     740         6868 :         second_pos = Z_EXTRA(second->val);
     741         6868 :         if (first_pos == second_pos) {
     742            0 :                 return;
     743              :         }
     744              : 
     745         6868 :         if (ctx->zero_pair_count == ctx->zero_pair_capacity) {
     746          248 :                 new_capacity = ctx->zero_pair_capacity == 0 ? 16 : ctx->zero_pair_capacity * 2;
     747          248 :                 ctx->zero_pairs = erealloc(ctx->zero_pairs, sizeof(php_colopl_bc_user_sort_zero_pair) * new_capacity);
     748          248 :                 ctx->zero_pair_capacity = new_capacity;
     749              :         }
     750              : 
     751         6868 :         ctx->zero_pairs[ctx->zero_pair_count].first = first_pos;
     752         6868 :         ctx->zero_pairs[ctx->zero_pair_count].second = second_pos;
     753         6868 :         ctx->zero_pair_count++;
     754              : }
     755              : 
     756         2984 : static inline bool php_colopl_bc_hash_get_ordered_entry_at(HashTable *ht, uint32_t target_pos, zval **value, zend_ulong *num_key, zend_string **str_key)
     757              : {
     758         2984 :         uint32_t pos = 0, ordered_pos = 0;
     759              : 
     760        71464 :         while ((*value = php_colopl_bc_hash_get_ordered_value(ht, &pos, num_key, str_key)) != NULL) {
     761        71464 :                 if (ordered_pos == target_pos) {
     762         2984 :                         return true;
     763              :                 }
     764        68480 :                 ordered_pos++;
     765              :         }
     766              : 
     767            0 :         return false;
     768              : }
     769              : 
     770         1348 : static inline bool php_colopl_bc_user_sort_pair_values_identical(zval *original, uint32_t first_pos, uint32_t second_pos)
     771              : {
     772              :         zend_ulong first_num_key, second_num_key;
     773              :         zend_string *first_str_key, *second_str_key;
     774              :         zval *first, *second;
     775              : 
     776         1348 :         if (Z_ISUNDEF_P(original)) {
     777            0 :                 return false;
     778              :         }
     779              : 
     780         1348 :         if (!php_colopl_bc_hash_get_ordered_entry_at(Z_ARRVAL_P(original), first_pos, &first, &first_num_key, &first_str_key) ||
     781         1348 :                 !php_colopl_bc_hash_get_ordered_entry_at(Z_ARRVAL_P(original), second_pos, &second, &second_num_key, &second_str_key)) {
     782            0 :                 return false;
     783              :         }
     784              : 
     785         1348 :         return zend_is_identical(first, second);
     786              : }
     787              : 
     788          240 : static inline bool php_colopl_bc_user_sort_find_final_position_by_key(zval *legacy, zend_ulong original_num_key, zend_string *original_str_key, uint32_t *final_pos)
     789              : {
     790              :         zend_ulong num_key;
     791              :         zend_string *str_key;
     792              :         zval *value;
     793          240 :         uint32_t pos = 0;
     794              : 
     795          240 :         *final_pos = 0;
     796         5440 :         while ((value = php_colopl_bc_hash_get_ordered_value(Z_ARRVAL_P(legacy), &pos, &num_key, &str_key)) != NULL) {
     797              :                 (void) value;
     798              : 
     799         5440 :                 if (original_str_key != NULL) {
     800         2304 :                         if (str_key != NULL && zend_string_equals(str_key, original_str_key)) {
     801          144 :                                 return true;
     802              :                         }
     803         3136 :                 } else if (str_key == NULL && num_key == original_num_key) {
     804           96 :                         return true;
     805              :                 }
     806              : 
     807         5200 :                 (*final_pos)++;
     808              :         }
     809              : 
     810            0 :         return false;
     811              : }
     812              : 
     813           48 : static inline bool php_colopl_bc_user_sort_find_final_position_by_value(zval *legacy, zval *original_value, uint32_t *final_pos)
     814              : {
     815              :         zend_ulong num_key;
     816              :         zend_string *str_key;
     817              :         zval *value;
     818           48 :         uint32_t pos = 0;
     819              : 
     820           48 :         *final_pos = 0;
     821         1568 :         while ((value = php_colopl_bc_hash_get_ordered_value(Z_ARRVAL_P(legacy), &pos, &num_key, &str_key)) != NULL) {
     822              :                 (void) num_key;
     823              :                 (void) str_key;
     824              : 
     825         1568 :                 if (zend_is_identical(value, original_value)) {
     826           48 :                         return true;
     827              :                 }
     828              : 
     829         1520 :                 (*final_pos)++;
     830              :         }
     831              : 
     832            0 :         return false;
     833              : }
     834              : 
     835          288 : static inline bool php_colopl_bc_user_sort_find_final_position(zval *legacy, zval *original, uint32_t original_pos, bool renumber, uint32_t *final_pos)
     836              : {
     837              :         zend_ulong num_key;
     838              :         zend_string *str_key;
     839              :         zval *value;
     840              : 
     841          288 :         if (Z_ISUNDEF_P(original) ||
     842          288 :                 !php_colopl_bc_hash_get_ordered_entry_at(Z_ARRVAL_P(original), original_pos, &value, &num_key, &str_key)) {
     843            0 :                 return false;
     844              :         }
     845              : 
     846          288 :         if (renumber) {
     847           48 :                 return php_colopl_bc_user_sort_find_final_position_by_value(legacy, value, final_pos);
     848              :         }
     849              : 
     850          240 :         return php_colopl_bc_user_sort_find_final_position_by_key(legacy, num_key, str_key, final_pos);
     851              : }
     852              : 
     853           68 : static inline bool php_colopl_bc_user_sort_context_detect_incompatible_order(php_colopl_bc_user_sort_context *ctx, zval *legacy, zval *original, bool renumber)
     854              : {
     855              :         uint32_t num_elements, i, first_pos, second_pos, first_final_pos, second_final_pos;
     856              : 
     857           68 :         if (ctx->zero_pair_count == 0) {
     858            4 :                 return false;
     859              :         }
     860              : 
     861           64 :         num_elements = zend_hash_num_elements(Z_ARRVAL_P(legacy));
     862           64 :         if (num_elements == 0) {
     863            0 :                 return false;
     864              :         }
     865              : 
     866         1484 :         for (i = 0; i < ctx->zero_pair_count; i++) {
     867         1468 :                 first_pos = ctx->zero_pairs[i].first;
     868         1468 :                 second_pos = ctx->zero_pairs[i].second;
     869         1468 :                 if (first_pos >= num_elements || second_pos >= num_elements) {
     870            0 :                         continue;
     871              :                 }
     872              : 
     873         1468 :                 if (renumber && php_colopl_bc_user_sort_pair_values_identical(original, first_pos, second_pos)) {
     874         1324 :                         continue;
     875              :                 }
     876              : 
     877          144 :                 if (!php_colopl_bc_user_sort_find_final_position(legacy, original, first_pos, renumber, &first_final_pos) ||
     878          144 :                         !php_colopl_bc_user_sort_find_final_position(legacy, original, second_pos, renumber, &second_final_pos)) {
     879            0 :                         continue;
     880              :                 }
     881              : 
     882          144 :                 if ((first_pos < second_pos && first_final_pos > second_final_pos) ||
     883           48 :                         (first_pos > second_pos && first_final_pos < second_final_pos)) {
     884           48 :                         return true;
     885              :                 }
     886              :         }
     887              : 
     888           16 :         return false;
     889              : }
     890              : 
     891          100 : static inline bool php_colopl_bc_same_snapshot_array_pair_seen(HashTable *seen_arrays, zend_array *legacy_array, zend_array *native_array)
     892              : {
     893              :         uintptr_t pair[2];
     894              : 
     895          100 :         pair[0] = (uintptr_t) legacy_array;
     896          100 :         pair[1] = (uintptr_t) native_array;
     897              : 
     898          100 :         if (zend_hash_str_exists(seen_arrays, (char *) pair, sizeof(pair))) {
     899            0 :                 return true;
     900              :         }
     901          100 :         zend_hash_str_add_empty_element(seen_arrays, (char *) pair, sizeof(pair));
     902              : 
     903          100 :         return false;
     904              : }
     905              : 
     906         1172 : static inline bool php_colopl_bc_same_snapshot_value_ex(zval *legacy, zval *native, php_colopl_bc_snapshot_context *ctx, HashTable *seen_arrays)
     907              : {
     908              :         zend_object *snapshot;
     909              :         zend_array *legacy_array, *native_array;
     910              :         zend_ulong legacy_num_key, native_num_key;
     911              :         zend_string *legacy_str_key, *native_str_key;
     912              :         zval *legacy_value, *native_value;
     913              :         uint32_t legacy_pos, native_pos;
     914              : 
     915         1172 :         ZVAL_DEREF(legacy);
     916         1172 :         ZVAL_DEREF(native);
     917              : 
     918         1172 :         if (Z_TYPE_P(legacy) == IS_OBJECT && Z_TYPE_P(native) == IS_OBJECT) {
     919            0 :                 snapshot = zend_hash_index_find_ptr(&ctx->objects, (zend_ulong)(uintptr_t) Z_OBJ_P(legacy));
     920            0 :                 if (snapshot != NULL && snapshot == Z_OBJ_P(native)) {
     921            0 :                         return true;
     922              :                 }
     923              :         }
     924              : 
     925         1172 :         if (Z_TYPE_P(legacy) != IS_ARRAY || Z_TYPE_P(native) != IS_ARRAY) {
     926         1072 :                 return zend_is_identical(legacy, native);
     927              :         }
     928              : 
     929          100 :         legacy_array = Z_ARRVAL_P(legacy);
     930          100 :         native_array = Z_ARRVAL_P(native);
     931          100 :         if (php_colopl_bc_same_snapshot_array_pair_seen(seen_arrays, legacy_array, native_array)) {
     932            0 :                 return true;
     933              :         }
     934              : 
     935          100 :         if (zend_hash_num_elements(legacy_array) != zend_hash_num_elements(native_array)) {
     936            0 :                 return false;
     937              :         }
     938              : 
     939          100 :         legacy_pos = native_pos = 0;
     940         1164 :         while ((legacy_value = php_colopl_bc_hash_get_ordered_value(legacy_array, &legacy_pos, &legacy_num_key, &legacy_str_key)) != NULL) {
     941         1136 :                 native_value = php_colopl_bc_hash_get_ordered_value(native_array, &native_pos, &native_num_key, &native_str_key);
     942              : 
     943         1136 :                 if (native_value == NULL) {
     944            0 :                         return false;
     945              :                 }
     946              : 
     947         1136 :                 if (legacy_str_key != NULL || native_str_key != NULL) {
     948          436 :                         if (legacy_str_key == NULL || native_str_key == NULL) {
     949           64 :                                 return false;
     950              :                         }
     951          372 :                         if (!zend_string_equals(legacy_str_key, native_str_key)) {
     952            0 :                                 return false;
     953              :                         }
     954          700 :                 } else if (legacy_num_key != native_num_key) {
     955            0 :                         return false;
     956              :                 }
     957              : 
     958         1072 :                 if (!php_colopl_bc_same_snapshot_value_ex(legacy_value, native_value, ctx, seen_arrays)) {
     959            8 :                         return false;
     960              :                 }
     961              :         }
     962              : 
     963           28 :         return php_colopl_bc_hash_get_ordered_value(native_array, &native_pos, &native_num_key, &native_str_key) == NULL;
     964              : }
     965              : 
     966          100 : static inline bool php_colopl_bc_same_snapshot_value(zval *legacy, zval *native, php_colopl_bc_snapshot_context *ctx)
     967              : {
     968              :         HashTable seen_arrays;
     969              :         bool same;
     970              : 
     971          100 :         zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
     972          100 :         same = php_colopl_bc_same_snapshot_value_ex(legacy, native, ctx, &seen_arrays);
     973          100 :         zend_hash_destroy(&seen_arrays);
     974              : 
     975          100 :         return same;
     976              : }
     977              : 
     978            0 : static inline void php_colopl_bc_convert_object_to_type(zval *op, zval *dst, uint32_t ctype)
     979              : {
     980            0 :         ZVAL_UNDEF(dst);
     981            0 :         if (Z_OBJ_HT_P(op)->cast_object(Z_OBJ_P(op), dst, ctype) == FAILURE) {
     982            0 :                 zend_error(
     983              :                         E_WARNING,
     984              :                         "Object of class %s could not be converted to %s",
     985            0 :                         ZSTR_VAL(Z_OBJCE_P(op)->name),
     986              :                         zend_get_type_by_const(ctype)
     987              :                 );
     988              :         }
     989            0 : }
     990              : 
     991          128 : static int php_colopl_bc_legacy_compare_std_objects(zval *op1, zval *op2, bool *handled)
     992              : {
     993              :         zend_object *zobj1, *zobj2;
     994              :         zend_property_info *info;
     995              :         zval *p1, *p2;
     996              :         int i, ret;
     997              : 
     998          128 :         *handled = false;
     999              : 
    1000          128 :         if (Z_TYPE_P(op1) != IS_OBJECT || Z_TYPE_P(op2) != IS_OBJECT) {
    1001            0 :                 return 1;
    1002              :         }
    1003              : 
    1004          128 :         zobj1 = Z_OBJ_P(op1);
    1005          128 :         zobj2 = Z_OBJ_P(op2);
    1006              : 
    1007          128 :         if (zobj1 == zobj2) {
    1008            0 :                 *handled = true;
    1009            0 :                 return 0;
    1010              :         }
    1011              : 
    1012          128 :         if (zobj1->handlers != &std_object_handlers ||
    1013          128 :                 zobj2->handlers != &std_object_handlers ||
    1014          128 :                 zobj1->ce != zobj2->ce ||
    1015           48 :                 zobj1->properties != NULL ||
    1016            8 :                 zobj2->properties != NULL) {
    1017          120 :                 return 1;
    1018              :         }
    1019              : 
    1020            8 :         *handled = true;
    1021              : 
    1022            8 :         if (!zobj1->ce->default_properties_count) {
    1023            0 :                 return 0;
    1024              :         }
    1025              : 
    1026            8 :         if (UNEXPECTED(Z_IS_RECURSIVE_P(op1))) {
    1027            0 :                 zend_throw_error(NULL, "Nesting level too deep - recursive dependency?");
    1028            0 :                 return ZEND_UNCOMPARABLE;
    1029              :         }
    1030              : 
    1031            8 :         Z_PROTECT_RECURSION_P(op1);
    1032            8 :         GC_ADDREF(zobj1);
    1033            8 :         GC_ADDREF(zobj2);
    1034              : 
    1035           16 :         for (i = 0; i < zobj1->ce->default_properties_count; i++) {
    1036            8 :                 info = zobj1->ce->properties_info_table[i];
    1037            8 :                 if (!info) {
    1038            0 :                         continue;
    1039              :                 }
    1040              : 
    1041            8 :                 p1 = OBJ_PROP(zobj1, info->offset);
    1042            8 :                 p2 = OBJ_PROP(zobj2, info->offset);
    1043              : 
    1044            8 :                 if (Z_TYPE_P(p1) != IS_UNDEF) {
    1045            8 :                         if (Z_TYPE_P(p2) != IS_UNDEF) {
    1046            8 :                                 ret = legacy_compare_fast(p1, p2);
    1047            8 :                                 if (ret != 0) {
    1048            0 :                                         Z_UNPROTECT_RECURSION_P(op1);
    1049            0 :                                         goto done;
    1050              :                                 }
    1051              :                         } else {
    1052            0 :                                 Z_UNPROTECT_RECURSION_P(op1);
    1053            0 :                                 ret = 1;
    1054            0 :                                 goto done;
    1055              :                         }
    1056            0 :                 } else if (Z_TYPE_P(p2) != IS_UNDEF) {
    1057            0 :                         Z_UNPROTECT_RECURSION_P(op1);
    1058            0 :                         ret = 1;
    1059            0 :                         goto done;
    1060              :                 }
    1061              :         }
    1062              : 
    1063            8 :         Z_UNPROTECT_RECURSION_P(op1);
    1064            8 :         ret = 0;
    1065              : 
    1066            8 : done:
    1067            8 :         OBJ_RELEASE(zobj1);
    1068            8 :         OBJ_RELEASE(zobj2);
    1069              : 
    1070            8 :         return ret;
    1071              : }
    1072              : 
    1073         7720 : static zend_never_inline zval* ZEND_FASTCALL _php_colopl_bc_zendi_convert_scalar_to_number_silent(zval *op, zval *holder)
    1074              : {
    1075         7720 :         switch (Z_TYPE_P(op)) {
    1076            0 :                 case IS_NULL:
    1077              :                 case IS_FALSE:
    1078            0 :                         ZVAL_LONG(holder, 0);
    1079            0 :                         return holder;
    1080            0 :                 case IS_TRUE:
    1081            0 :                         ZVAL_LONG(holder, 1);
    1082            0 :                         return holder;
    1083         3540 :                 case IS_STRING:
    1084         3540 :                         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) {
    1085         1104 :                                 ZVAL_LONG(holder, 0);
    1086              :                         }
    1087         3540 :                         return holder;
    1088            0 :                 case IS_RESOURCE:
    1089            0 :                         ZVAL_LONG(holder, Z_RES_HANDLE_P(op));
    1090            0 :                         return holder;
    1091            0 :                 case IS_OBJECT:
    1092            0 :                         php_colopl_bc_convert_object_to_type(op, holder, _IS_NUMBER);
    1093            0 :                         if (UNEXPECTED(EG(exception)) ||
    1094            0 :                                 UNEXPECTED(Z_TYPE_P(holder) != IS_LONG && Z_TYPE_P(holder) != IS_DOUBLE)) {
    1095            0 :                                 ZVAL_LONG(holder, 1);
    1096              :                         }
    1097            0 :                         return holder;
    1098         4180 :                 case IS_LONG:
    1099              :                 case IS_DOUBLE:
    1100              :                 default:
    1101         4180 :                         return op;
    1102              :         }
    1103              : }
    1104              : 
    1105        15136 : static int legacy_compare_fast(zval *op1, zval *op2)
    1106              : {
    1107              :         zval op1_copy, op2_copy;
    1108              :         bool handled;
    1109        15136 :         int converted = 0, ret;
    1110              : 
    1111              :         while (1) {
    1112        18996 :                 switch (COLOPL_BC_TYPE_PAIR(Z_TYPE_P(op1), Z_TYPE_P(op2))) {
    1113         8888 :                         case COLOPL_BC_TYPE_PAIR(IS_LONG, IS_LONG):
    1114         8888 :                                 return Z_LVAL_P(op1)>Z_LVAL_P(op2)?1:(Z_LVAL_P(op1)<Z_LVAL_P(op2)?-1:0);
    1115              : 
    1116          200 :                         case COLOPL_BC_TYPE_PAIR(IS_DOUBLE, IS_LONG):
    1117          200 :                                 return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - (double)Z_LVAL_P(op2));
    1118              : 
    1119          200 :                         case COLOPL_BC_TYPE_PAIR(IS_LONG, IS_DOUBLE):
    1120          200 :                                 return ZEND_NORMALIZE_BOOL((double)Z_LVAL_P(op1) - Z_DVAL_P(op2));
    1121              : 
    1122           60 :                         case COLOPL_BC_TYPE_PAIR(IS_DOUBLE, IS_DOUBLE):
    1123           60 :                                 if (Z_DVAL_P(op1) == Z_DVAL_P(op2)) {
    1124           60 :                                         return 0;
    1125              :                                 } else {
    1126            0 :                                         return ZEND_NORMALIZE_BOOL(Z_DVAL_P(op1) - Z_DVAL_P(op2));
    1127              :                                 }
    1128              : 
    1129           80 :                         case COLOPL_BC_TYPE_PAIR(IS_ARRAY, IS_ARRAY):
    1130           80 :                                 return zend_compare_arrays(op1, op2);
    1131              : 
    1132          100 :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_NULL):
    1133              :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_FALSE):
    1134              :                         case COLOPL_BC_TYPE_PAIR(IS_FALSE, IS_NULL):
    1135              :                         case COLOPL_BC_TYPE_PAIR(IS_FALSE, IS_FALSE):
    1136              :                         case COLOPL_BC_TYPE_PAIR(IS_TRUE, IS_TRUE):
    1137          100 :                                 return 0;
    1138              : 
    1139           20 :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_TRUE):
    1140           20 :                                 return -1;
    1141              : 
    1142           20 :                         case COLOPL_BC_TYPE_PAIR(IS_TRUE, IS_NULL):
    1143           20 :                                 return 1;
    1144              : 
    1145           60 :                         case COLOPL_BC_TYPE_PAIR(IS_TRUE, IS_OBJECT):
    1146           60 :                                 return zval_is_true(op2) ? 0 : 1;
    1147              : 
    1148           60 :                         case COLOPL_BC_TYPE_PAIR(IS_FALSE, IS_OBJECT):
    1149           60 :                                 return zval_is_true(op2) ? -1 : 0;
    1150              : 
    1151           60 :                         case COLOPL_BC_TYPE_PAIR(IS_OBJECT, IS_TRUE):
    1152           60 :                                 return zval_is_true(op1) ? 0 : -1;
    1153              : 
    1154           60 :                         case COLOPL_BC_TYPE_PAIR(IS_OBJECT, IS_FALSE):
    1155           60 :                                 return zval_is_true(op1) ? 1 : 0;
    1156              : 
    1157         1584 :                         case COLOPL_BC_TYPE_PAIR(IS_STRING, IS_STRING):
    1158         1584 :                                 if (Z_STR_P(op1) == Z_STR_P(op2)) {
    1159          772 :                                         return 0;
    1160              :                                 }
    1161              : 
    1162          812 :                                 return zendi_smart_strcmp(Z_STR_P(op1), Z_STR_P(op2));
    1163              : 
    1164          100 :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_STRING):
    1165          100 :                                 return Z_STRLEN_P(op2) == 0 ? 0 : -1;
    1166              : 
    1167          100 :                         case COLOPL_BC_TYPE_PAIR(IS_STRING, IS_NULL):
    1168          100 :                                 return Z_STRLEN_P(op1) == 0 ? 0 : 1;
    1169              : 
    1170           60 :                         case COLOPL_BC_TYPE_PAIR(IS_OBJECT, IS_NULL):
    1171           60 :                                 return 1;
    1172              : 
    1173           60 :                         case COLOPL_BC_TYPE_PAIR(IS_NULL, IS_OBJECT):
    1174           60 :                                 return -1;
    1175              : 
    1176         7284 :                         default:
    1177         7284 :                                 if (Z_ISREF_P(op1)) {
    1178            0 :                                         op1 = Z_REFVAL_P(op1);
    1179              : 
    1180            0 :                                         continue;
    1181         7284 :                                 } else if (Z_ISREF_P(op2)) {
    1182            0 :                                         op2 = Z_REFVAL_P(op2);
    1183              : 
    1184            0 :                                         continue;
    1185              :                                 }
    1186              : 
    1187         8156 :                                 if (Z_TYPE_P(op1) == IS_OBJECT &&
    1188          872 :                                         Z_TYPE_P(op2) == IS_OBJECT &&
    1189          188 :                                         Z_OBJ_P(op1) == Z_OBJ_P(op2)
    1190              :                                 ) {
    1191           60 :                                         return 0;
    1192         7224 :                                 } else if (Z_TYPE_P(op1) == IS_OBJECT && Z_TYPE_P(op2) == IS_OBJECT) {
    1193          128 :                                         ret = php_colopl_bc_legacy_compare_std_objects(op1, op2, &handled);
    1194              : 
    1195          128 :                                         if (handled) {
    1196            8 :                                                 return ret;
    1197              :                                         }
    1198              : 
    1199          120 :                                         return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
    1200         7096 :                                 } else if (Z_TYPE_P(op1) == IS_OBJECT) {
    1201          684 :                                         return Z_OBJ_HANDLER_P(op1, compare)(op1, op2);
    1202         6412 :                                 } else if (Z_TYPE_P(op2) == IS_OBJECT) {
    1203          672 :                                         return Z_OBJ_HANDLER_P(op2, compare)(op1, op2);
    1204              :                                 }
    1205              : 
    1206         5740 :                                 if (!converted) {
    1207         5020 :                                         if (Z_TYPE_P(op1) < IS_TRUE) {
    1208          360 :                                                 return zval_is_true(op2) ? -1 : 0;
    1209         4660 :                                         } else if (Z_TYPE_P(op1) == IS_TRUE) {
    1210          240 :                                                 return zval_is_true(op2) ? 0 : 1;
    1211         4420 :                                         } else if (Z_TYPE_P(op2) < IS_TRUE) {
    1212          340 :                                                 return zval_is_true(op1) ? 1 : 0;
    1213         4080 :                                         } else if (Z_TYPE_P(op2) == IS_TRUE) {
    1214          220 :                                                 return zval_is_true(op1) ? 0 : -1;
    1215              :                                         } else {
    1216         3860 :                                                 op1 = _php_colopl_bc_zendi_convert_scalar_to_number_silent(op1, &op1_copy);
    1217         3860 :                                                 op2 = _php_colopl_bc_zendi_convert_scalar_to_number_silent(op2, &op2_copy);
    1218              : 
    1219         3860 :                                                 if (EG(exception)) {
    1220            0 :                                                         return 1; /* to stop comparison of arrays */
    1221              :                                                 }
    1222              : 
    1223         3860 :                                                 converted = 1;
    1224              :                                         }
    1225          720 :                                 } else if (Z_TYPE_P(op1)==IS_ARRAY) {
    1226          360 :                                         return 1;
    1227          360 :                                 } else if (Z_TYPE_P(op2)==IS_ARRAY) {
    1228          360 :                                         return -1;
    1229              :                                 } else {
    1230            0 :                                         ZEND_UNREACHABLE();
    1231              :                                         zend_throw_error(NULL, "Unsupported operand types");
    1232              : 
    1233              :                                         return 1;
    1234              :                                 }
    1235              :                 }
    1236              :         }
    1237              : }
    1238              : 
    1239        11924 : static int legacy_compare_slow(zval *op1, zval *op2)
    1240              : {
    1241              :         php_colopl_bc_snapshot_context snapshot_context;
    1242              :         php_colopl_bc_diagnostic_error_state error_state;
    1243              :         zval native_op1, native_op2;
    1244              :         bool have_native_snapshot, native_failed;
    1245              :         int bc, native;
    1246              : 
    1247        11924 :         if (COLOPL_BC_G(php74_compare_mode) <= COLOPL_BC_PHP74_COMPARE_MODE_SILENT) {
    1248            0 :                 return legacy_compare_fast(op1, op2);
    1249              :         }
    1250              : 
    1251        11924 :         ZVAL_UNDEF(&native_op1);
    1252        11924 :         ZVAL_UNDEF(&native_op2);
    1253        11924 :         php_colopl_bc_snapshot_context_init(&snapshot_context);
    1254        11924 :         have_native_snapshot = php_colopl_bc_zvals_allow_native_compare_snapshot(op1, op2) &&
    1255        20416 :                 !php_colopl_bc_zvals_contain_recursive_array(op1, op2) &&
    1256        32340 :                 php_colopl_bc_snapshot_zval(&native_op1, op1, &snapshot_context) &&
    1257        10208 :                 php_colopl_bc_snapshot_zval(&native_op2, op2, &snapshot_context)
    1258              :         ;
    1259              : 
    1260        11924 :         bc = legacy_compare_fast(op1, op2);
    1261              : 
    1262        11924 :         if (have_native_snapshot && !EG(exception)) {
    1263        10208 :                 php_colopl_bc_diagnostic_error_state_suppress(&error_state);
    1264        10208 :                 native = zend_compare(&native_op1, &native_op2);
    1265        10208 :                 native_failed = php_colopl_bc_clear_diagnostic_exception();
    1266        10208 :                 php_colopl_bc_diagnostic_error_state_restore(&error_state);
    1267              :         } else {
    1268         1716 :                 native = bc;
    1269         1716 :                 native_failed = false;
    1270              :         }
    1271              : 
    1272        11924 :         if (have_native_snapshot && !native_failed && native != bc) {
    1273          820 :                 if (COLOPL_BC_G(php74_compare_mode) & COLOPL_BC_PHP74_COMPARE_MODE_LOG) {
    1274          812 :                         php_colopl_bc_log_incompatibility("Incompatible compare detected");
    1275              :                 }
    1276              : 
    1277          820 :                 if (COLOPL_BC_G(php74_compare_mode) & COLOPL_BC_PHP74_COMPARE_MODE_DEPRECATED) {
    1278          812 :                         php_error_docref(NULL, E_DEPRECATED, "Incompatible compare detected");
    1279              :                 }
    1280              :         }
    1281              : 
    1282        11924 :         if (!Z_ISUNDEF(native_op2)) {
    1283        10208 :                 zval_ptr_dtor(&native_op2);
    1284              :         }
    1285              : 
    1286        11924 :         if (!Z_ISUNDEF(native_op1)) {
    1287        10208 :                 zval_ptr_dtor(&native_op1);
    1288              :         }
    1289              : 
    1290        11924 :         php_colopl_bc_snapshot_context_destroy(&snapshot_context);
    1291              : 
    1292        11924 :         return bc;
    1293              : }
    1294              : 
    1295          282 : PHP_INI_MH(OnUpdateCompareMode)
    1296              : {
    1297          282 :         if (OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage) == FAILURE) {
    1298            0 :                 return FAILURE;
    1299              :         }
    1300              : 
    1301          282 :         if (COLOPL_BC_G(php74_compare_mode) <= COLOPL_BC_PHP74_COMPARE_MODE_SILENT) {
    1302          178 :                 COLOPL_BC_G(php74_compare_func) = legacy_compare_fast;
    1303              :         } else {
    1304          104 :                 COLOPL_BC_G(php74_compare_func) = legacy_compare_slow;
    1305              :         }
    1306              : 
    1307          282 :         return SUCCESS;
    1308              : }
    1309              : 
    1310        15128 : int php_colopl_bc_compare(zval *op1, zval *op2)
    1311              : {
    1312        15128 :         return COLOPL_BC_G(php74_compare_func)(op1, op2);
    1313              : }
    1314              : 
    1315            0 : static zend_always_inline bool php_colopl_bc_fast_equal_check_long(zval *op1, zval *op2)
    1316              : {
    1317            0 :         if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
    1318            0 :                 return Z_LVAL_P(op1) == Z_LVAL_P(op2);
    1319              :         }
    1320            0 :         return php_colopl_bc_compare(op1, op2) == 0;
    1321              : }
    1322              : 
    1323            8 : static zend_always_inline bool php_colopl_bc_fast_equal_check_string(zval *op1, zval *op2)
    1324              : {
    1325            8 :         if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
    1326            0 :                 return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2));
    1327              :         }
    1328              : 
    1329            8 :         return php_colopl_bc_compare(op1, op2) == 0;
    1330              : }
    1331              : 
    1332            8 : static zend_always_inline bool php_colopl_bc_fast_equal_check_function(zval *op1, zval *op2)
    1333              : {
    1334            8 :         if (EXPECTED(Z_TYPE_P(op1) == IS_LONG)) {
    1335            0 :                 if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
    1336            0 :                         return Z_LVAL_P(op1) == Z_LVAL_P(op2);
    1337            0 :                 } else if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
    1338            0 :                         return ((double)Z_LVAL_P(op1)) == Z_DVAL_P(op2);
    1339              :                 }
    1340            8 :         } else if (EXPECTED(Z_TYPE_P(op1) == IS_DOUBLE)) {
    1341            0 :                 if (EXPECTED(Z_TYPE_P(op2) == IS_DOUBLE)) {
    1342            0 :                         return Z_DVAL_P(op1) == Z_DVAL_P(op2);
    1343            0 :                 } else if (EXPECTED(Z_TYPE_P(op2) == IS_LONG)) {
    1344            0 :                         return Z_DVAL_P(op1) == ((double)Z_LVAL_P(op2));
    1345              :                 }
    1346            8 :         } else if (EXPECTED(Z_TYPE_P(op1) == IS_STRING)) {
    1347            8 :                 if (EXPECTED(Z_TYPE_P(op2) == IS_STRING)) {
    1348            4 :                         return zend_fast_equal_strings(Z_STR_P(op1), Z_STR_P(op2));
    1349              :                 }
    1350              :         }
    1351              : 
    1352            4 :         return php_colopl_bc_compare(op1, op2) == 0;
    1353              : }
    1354              : 
    1355              : /* array.c */
    1356              : 
    1357         2792 : static int php_colopl_bc_array_key_compare(Bucket *f, Bucket *s)
    1358              : {
    1359              :         zend_uchar t;
    1360              :         zend_long l1, l2;
    1361              :         double d;
    1362              : 
    1363         2792 :         if (f->key == NULL) {
    1364           40 :                 if (s->key == NULL) {
    1365            0 :                         return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
    1366              :                 } else {
    1367           40 :                         l1 = (zend_long)f->h;
    1368           40 :                         t = is_numeric_string(s->key->val, s->key->len, &l2, &d, 1);
    1369           40 :                         if (t == IS_LONG) {
    1370              :                                 /* pass */
    1371           40 :                         } else if (t == IS_DOUBLE) {
    1372            0 :                                 return ZEND_NORMALIZE_BOOL((double)l1 - d);
    1373              :                         } else {
    1374           40 :                                 l2 = 0;
    1375              :                         }
    1376              :                 }
    1377              :         } else {
    1378         2752 :                 if (s->key) {
    1379         2704 :                         return zendi_smart_strcmp(f->key, s->key);
    1380              :                 } else {
    1381           48 :                         l2 = (zend_long)s->h;
    1382           48 :                         t = is_numeric_string(f->key->val, f->key->len, &l1, &d, 1);
    1383           48 :                         if (t == IS_LONG) {
    1384              :                                 /* pass */
    1385           48 :                         } else if (t == IS_DOUBLE) {
    1386            0 :                                 return ZEND_NORMALIZE_BOOL(d - (double)l2);
    1387              :                         } else {
    1388           48 :                                 l1 = 0;
    1389              :                         }
    1390              :                 }
    1391              :         }
    1392           88 :         return ZEND_NORMALIZE_BOOL(l1 - l2);
    1393              : }
    1394              : 
    1395         1412 : static int php_colopl_bc_array_reverse_key_compare(Bucket *a, Bucket *b)
    1396              : {
    1397         1412 :         return php_colopl_bc_array_key_compare(b, a);
    1398              : }
    1399              : 
    1400            0 : static int php_colopl_bc_array_key_compare_numeric(Bucket *f, Bucket *s)
    1401              : {
    1402              :         double d1, d2;
    1403              : 
    1404            0 :         if (f->key == NULL && s->key == NULL) {
    1405            0 :                 return (zend_long)f->h > (zend_long)s->h ? 1 : -1;
    1406              :         } else {
    1407            0 :                 if (f->key) {
    1408            0 :                         d1 = zend_strtod(f->key->val, NULL);
    1409              :                 } else {
    1410            0 :                         d1 = (double)(zend_long)f->h;
    1411              :                 }
    1412            0 :                 if (s->key) {
    1413            0 :                         d2 = zend_strtod(s->key->val, NULL);
    1414              :                 } else {
    1415            0 :                         d2 = (double)(zend_long)s->h;
    1416              :                 }
    1417              : 
    1418            0 :                 return ZEND_NORMALIZE_BOOL(d1 - d2);
    1419              :         }
    1420              : }
    1421              : 
    1422            0 : static int php_colopl_bc_array_reverse_key_compare_numeric(Bucket *a, Bucket *b)
    1423              : {
    1424            0 :         return php_colopl_bc_array_key_compare_numeric(b, a);
    1425              : }
    1426              : 
    1427            0 : static int php_colopl_bc_array_key_compare_string_case(Bucket *f, Bucket *s)
    1428              : {
    1429              :         const char *s1, *s2;
    1430              :         size_t l1, l2;
    1431              :         char buf1[MAX_LENGTH_OF_LONG + 1], buf2[MAX_LENGTH_OF_LONG + 1];
    1432              : 
    1433            0 :         if (f->key) {
    1434            0 :                 s1 = f->key->val;
    1435            0 :                 l1 = f->key->len;
    1436              :         } else {
    1437            0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
    1438            0 :                 l1 = buf1 + sizeof(buf1) - 1 - s1;
    1439              :         }
    1440              : 
    1441            0 :         if (s->key) {
    1442            0 :                 s2 = s->key->val;
    1443            0 :                 l2 = s->key->len;
    1444              :         } else {
    1445            0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
    1446            0 :                 l2 = buf2 + sizeof(buf2) - 1 - s2;
    1447              :         }
    1448              : 
    1449            0 :         return zend_binary_strcasecmp_l(s1, l1, s2, l2);
    1450              : }
    1451              : 
    1452            0 : static int php_colopl_bc_array_reverse_key_compare_string_case(Bucket *a, Bucket *b)
    1453              : {
    1454            0 :         return php_colopl_bc_array_key_compare_string_case(b, a);
    1455              : }
    1456              : 
    1457            0 : static int php_colopl_bc_array_key_compare_string(Bucket *f, Bucket *s)
    1458              : {
    1459              :         const char *s1, *s2;
    1460              :         size_t l1, l2;
    1461              :         char buf1[MAX_LENGTH_OF_LONG + 1], buf2[MAX_LENGTH_OF_LONG + 1];
    1462              : 
    1463            0 :         if (f->key) {
    1464            0 :                 s1 = f->key->val;
    1465            0 :                 l1 = f->key->len;
    1466              :         } else {
    1467            0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
    1468            0 :                 l1 = buf1 + sizeof(buf1) - 1 - s1;
    1469              :         }
    1470              : 
    1471            0 :         if (s->key) {
    1472            0 :                 s2 = s->key->val;
    1473            0 :                 l2 = s->key->len;
    1474              :         } else {
    1475            0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
    1476            0 :                 l2 = buf2 + sizeof(buf2) - 1 - s2;
    1477              :         }
    1478              : 
    1479            0 :         return zend_binary_strcmp(s1, l1, s2, l2);
    1480              : }
    1481              : 
    1482            0 : static int php_colopl_bc_array_reverse_key_compare_string(Bucket *a, Bucket *b)
    1483              : {
    1484            0 :         return php_colopl_bc_array_key_compare_string(b, a);
    1485              : }
    1486              : 
    1487            0 : static int php_colopl_bc_array_key_compare_string_natural_general(Bucket *f, Bucket *s, int fold_case)
    1488              : {
    1489              :         const char *s1, *s2;
    1490              :         size_t l1, l2;
    1491              :         char buf1[MAX_LENGTH_OF_LONG + 1], buf2[MAX_LENGTH_OF_LONG + 1];
    1492              : 
    1493            0 :         if (f->key) {
    1494            0 :                 s1 = f->key->val;
    1495            0 :                 l1 = f->key->len;
    1496              :         } else {
    1497            0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
    1498            0 :                 l1 = buf1 + sizeof(buf1) - 1 - s1;
    1499              :         }
    1500              : 
    1501            0 :         if (s->key) {
    1502            0 :                 s2 = s->key->val;
    1503            0 :                 l2 = s->key->len;
    1504              :         } else {
    1505            0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
    1506            0 :                 l2 = buf2 + sizeof(buf2) - 1 - s2;
    1507              :         }
    1508              : 
    1509            0 :         return strnatcmp_ex(s1, l1, s2, l2, fold_case);
    1510              : }
    1511              : 
    1512            0 : static int php_colopl_bc_array_key_compare_string_natural_case(Bucket *a, Bucket *b)
    1513              : {
    1514            0 :         return php_colopl_bc_array_key_compare_string_natural_general(a, b, 1);
    1515              : }
    1516              : 
    1517            0 : static int php_colopl_bc_array_reverse_key_compare_string_natural_case(Bucket *a, Bucket *b)
    1518              : {
    1519            0 :         return php_colopl_bc_array_key_compare_string_natural_general(b, a, 1);
    1520              : }
    1521              : 
    1522            0 : static int php_colopl_bc_array_key_compare_string_natural(Bucket *a, Bucket *b)
    1523              : {
    1524            0 :         return php_colopl_bc_array_key_compare_string_natural_general(a, b, 0);
    1525              : }
    1526              : 
    1527            0 : static int php_colopl_bc_array_reverse_key_compare_string_natural(Bucket *a, Bucket *b)
    1528              : {
    1529            0 :         return php_colopl_bc_array_key_compare_string_natural_general(b, a, 0);
    1530              : }
    1531              : 
    1532            0 : static int php_colopl_bc_array_key_compare_string_locale(Bucket *f, Bucket *s)
    1533              : {
    1534              :         const char *s1, *s2;
    1535              :         char buf1[MAX_LENGTH_OF_LONG + 1], buf2[MAX_LENGTH_OF_LONG + 1];
    1536              : 
    1537            0 :         if (f->key) {
    1538            0 :                 s1 = f->key->val;
    1539              :         } else {
    1540            0 :                 s1 = zend_print_long_to_buf(buf1 + sizeof(buf1) - 1, f->h);
    1541              :         }
    1542              : 
    1543            0 :         if (s->key) {
    1544            0 :                 s2 = s->key->val;
    1545              :         } else {
    1546            0 :                 s2 = zend_print_long_to_buf(buf2 + sizeof(buf2) - 1, s->h);
    1547              :         }
    1548              : 
    1549            0 :         return strcoll(s1, s2);
    1550              : }
    1551              : 
    1552            0 : static int php_colopl_bc_array_reverse_key_compare_string_locale(Bucket *a, Bucket *b)
    1553              : {
    1554            0 :         return php_colopl_bc_array_key_compare_string_locale(b, a);
    1555              : }
    1556              : 
    1557         9276 : static int php_colopl_bc_array_data_compare(Bucket *f, Bucket *s)
    1558              : {
    1559         9276 :         zval *first = &f->val, *second = &s->val;
    1560              : 
    1561         9276 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1562            0 :                 first = Z_INDIRECT_P(first);
    1563              :         }
    1564              : 
    1565         9276 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1566            0 :                 second = Z_INDIRECT_P(second);
    1567              :         }
    1568              : 
    1569         9276 :         return php_colopl_bc_compare(first, second);
    1570              : }
    1571              : 
    1572         3120 : static int php_colopl_bc_array_reverse_data_compare(Bucket *a, Bucket *b)
    1573              : {
    1574         3120 :         return php_colopl_bc_array_data_compare(a, b) * -1;
    1575              : }
    1576              : 
    1577            0 : static int php_colopl_bc_array_data_compare_numeric(Bucket *f, Bucket *s)
    1578              : {
    1579            0 :         zval *first = &f->val, *second = &s->val;
    1580              : 
    1581            0 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1582            0 :                 first = Z_INDIRECT_P(first);
    1583              :         }
    1584              : 
    1585            0 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1586            0 :                 second = Z_INDIRECT_P(second);
    1587              :         }
    1588              : 
    1589            0 :         return numeric_compare_function(first, second);
    1590              : }
    1591              : 
    1592            0 : static int php_colopl_bc_array_reverse_data_compare_numeric(Bucket *a, Bucket *b)
    1593              : {
    1594            0 :         return php_colopl_bc_array_data_compare_numeric(b, a);
    1595              : }
    1596              : 
    1597            0 : static int php_colopl_bc_array_data_compare_string_case(Bucket *f, Bucket *s)
    1598              : {
    1599            0 :         zval *first = &f->val, *second = &s->val;
    1600              : 
    1601            0 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1602            0 :                 first = Z_INDIRECT_P(first);
    1603              :         }
    1604              : 
    1605            0 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1606            0 :                 second = Z_INDIRECT_P(second);
    1607              :         }
    1608              : 
    1609            0 :         return string_case_compare_function(first, second);
    1610              : }
    1611              : 
    1612            0 : static int php_colopl_bc_array_reverse_data_compare_string_case(Bucket *a, Bucket *b)
    1613              : {
    1614            0 :         return php_colopl_bc_array_data_compare_string_case(b, a);
    1615              : }
    1616              : 
    1617            8 : static int php_colopl_bc_array_data_compare_string(Bucket *f, Bucket *s)
    1618              : {
    1619            8 :         zval *first = &f->val, *second = &s->val;
    1620              : 
    1621            8 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1622            0 :                 first = Z_INDIRECT_P(first);
    1623              :         }
    1624              : 
    1625            8 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1626            0 :                 second = Z_INDIRECT_P(second);
    1627              :         }
    1628              : 
    1629            8 :         return string_compare_function(first, second);
    1630              : }
    1631              : 
    1632            0 : static int php_colopl_bc_array_reverse_data_compare_string(Bucket *a, Bucket *b)
    1633              : {
    1634            0 :         return php_colopl_bc_array_data_compare_string(b, a);
    1635              : }
    1636              : 
    1637            0 : static int php_colopl_bc_array_natural_general_compare(Bucket *f, Bucket *s, int fold_case)
    1638              : {
    1639            0 :         zend_string *tmp_str1, *tmp_str2, *str1 = zval_get_tmp_string(&f->val, &tmp_str1), *str2 = zval_get_tmp_string(&s->val, &tmp_str2);
    1640            0 :         int result = strnatcmp_ex(ZSTR_VAL(str1), ZSTR_LEN(str1), ZSTR_VAL(str2), ZSTR_LEN(str2), fold_case);
    1641              : 
    1642            0 :         zend_tmp_string_release(tmp_str1);
    1643            0 :         zend_tmp_string_release(tmp_str2);
    1644              : 
    1645            0 :         return result;
    1646              : }
    1647              : 
    1648            0 : static int php_colopl_bc_array_natural_compare(Bucket *a, Bucket *b)
    1649              : {
    1650            0 :         return php_colopl_bc_array_natural_general_compare(a, b, 0);
    1651              : }
    1652              : 
    1653            0 : static int php_colopl_bc_array_reverse_natural_compare(Bucket *a, Bucket *b)
    1654              : {
    1655            0 :         return php_colopl_bc_array_natural_general_compare(b, a, 0);
    1656              : }
    1657              : 
    1658            0 : static int php_colopl_bc_array_natural_case_compare(Bucket *a, Bucket *b)
    1659              : {
    1660            0 :         return php_colopl_bc_array_natural_general_compare(a, b, 1);
    1661              : }
    1662              : 
    1663            0 : static int php_colopl_bc_array_reverse_natural_case_compare(Bucket *a, Bucket *b)
    1664              : {
    1665            0 :         return php_colopl_bc_array_natural_general_compare(b, a, 1);
    1666              : }
    1667              : 
    1668            0 : static int php_colopl_bc_array_data_compare_string_locale(Bucket *f, Bucket *s)
    1669              : {
    1670            0 :         zval *first = &f->val, *second = &s->val;
    1671              : 
    1672            0 :         if (UNEXPECTED(Z_TYPE_P(first) == IS_INDIRECT)) {
    1673            0 :                 first = Z_INDIRECT_P(first);
    1674              :         }
    1675              : 
    1676            0 :         if (UNEXPECTED(Z_TYPE_P(second) == IS_INDIRECT)) {
    1677            0 :                 second = Z_INDIRECT_P(second);
    1678              :         }
    1679              : 
    1680            0 :         return string_locale_compare_function(first, second);
    1681              : }
    1682              : 
    1683            0 : static int php_colopl_bc_array_reverse_data_compare_string_locale(Bucket *a, Bucket *b)
    1684              : {
    1685            0 :         return php_colopl_bc_array_data_compare_string_locale(b, a);
    1686              : }
    1687              : 
    1688         5224 : static int php_colopl_bc_array_user_compare(Bucket *f, Bucket *s)
    1689              : {
    1690              :         zend_long ret;
    1691              :         zval args[2], retval;
    1692              :         int result;
    1693              : 
    1694         5224 :         ZVAL_COPY(&args[0], &f->val);
    1695         5224 :         ZVAL_COPY(&args[1], &s->val);
    1696              : 
    1697         5224 :         COLOPL_BC_G(user_compare_fci).param_count = 2;
    1698         5224 :         COLOPL_BC_G(user_compare_fci).params = args;
    1699         5224 :         COLOPL_BC_G(user_compare_fci).retval = &retval;
    1700         5224 :         if (zend_call_function(&COLOPL_BC_G(user_compare_fci), &COLOPL_BC_G(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
    1701         5224 :                 ret = zval_get_long(&retval);
    1702         5224 :                 result = ZEND_NORMALIZE_BOOL(ret);
    1703              : 
    1704         5224 :                 zval_ptr_dtor(&retval);
    1705         5224 :                 zval_ptr_dtor(&args[1]);
    1706         5224 :                 zval_ptr_dtor(&args[0]);
    1707              : 
    1708         5224 :                 if (result == 0) {
    1709         5220 :                         php_colopl_bc_user_sort_context_record_zero_pair(f, s);
    1710              :                 }
    1711              : 
    1712         5224 :                 return result;
    1713              :         } else {
    1714            0 :                 zval_ptr_dtor(&args[1]);
    1715            0 :                 zval_ptr_dtor(&args[0]);
    1716              : 
    1717            0 :                 php_colopl_bc_user_sort_context_record_zero_pair(f, s);
    1718              : 
    1719            0 :                 result = 0;
    1720              :         }
    1721              : 
    1722            0 :         return result;
    1723              : }
    1724              : 
    1725         2248 : static int php_colopl_bc_array_user_key_compare(Bucket *f, Bucket *s)
    1726              : {
    1727              :         zend_long result;
    1728              :         zval args[2], retval;
    1729              : 
    1730         2248 :         if (f->key == NULL) {
    1731         1464 :                 ZVAL_LONG(&args[0], f->h);
    1732              :         } else {
    1733          784 :                 ZVAL_STR_COPY(&args[0], f->key);
    1734              :         }
    1735              : 
    1736         2248 :         if (s->key == NULL) {
    1737         1464 :                 ZVAL_LONG(&args[1], s->h);
    1738              :         } else {
    1739          784 :                 ZVAL_STR_COPY(&args[1], s->key);
    1740              :         }
    1741              : 
    1742         2248 :         COLOPL_BC_G(user_compare_fci).param_count = 2;
    1743         2248 :         COLOPL_BC_G(user_compare_fci).params = args;
    1744         2248 :         COLOPL_BC_G(user_compare_fci).retval = &retval;
    1745              : 
    1746         2248 :         if (zend_call_function(&COLOPL_BC_G(user_compare_fci), &COLOPL_BC_G(user_compare_fci_cache)) == SUCCESS && Z_TYPE(retval) != IS_UNDEF) {
    1747         2248 :                 result = zval_get_long(&retval);
    1748              : 
    1749         2248 :                 zval_ptr_dtor(&retval);
    1750              :         } else {
    1751            0 :                 result = 0;
    1752              :         }
    1753              : 
    1754         2248 :         zval_ptr_dtor(&args[0]);
    1755         2248 :         zval_ptr_dtor(&args[1]);
    1756              : 
    1757         2248 :         result = ZEND_NORMALIZE_BOOL(result);
    1758         2248 :         if (result == 0) {
    1759         2248 :                 php_colopl_bc_user_sort_context_record_zero_pair(f, s);
    1760              :         }
    1761              : 
    1762         2248 :         return result;
    1763              : }
    1764              : 
    1765           44 : static bucket_compare_func_t php_colopl_bc_get_key_compare_func(zend_long sort_type, int reverse)
    1766              : {
    1767           44 :         switch (sort_type & ~PHP_SORT_FLAG_CASE) {
    1768            0 :                 case PHP_SORT_NUMERIC:
    1769            0 :                         if (reverse) {
    1770            0 :                                 return php_colopl_bc_array_reverse_key_compare_numeric;
    1771              :                         } else {
    1772            0 :                                 return php_colopl_bc_array_key_compare_numeric;
    1773              :                         }
    1774              : 
    1775              :                         break;
    1776            0 :                 case PHP_SORT_STRING:
    1777            0 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
    1778            0 :                                 if (reverse) {
    1779            0 :                                         return php_colopl_bc_array_reverse_key_compare_string_case;
    1780              :                                 } else {
    1781            0 :                                         return php_colopl_bc_array_key_compare_string_case;
    1782              :                                 }
    1783              :                         } else {
    1784            0 :                                 if (reverse) {
    1785            0 :                                         return php_colopl_bc_array_reverse_key_compare_string;
    1786              :                                 } else {
    1787            0 :                                         return php_colopl_bc_array_key_compare_string;
    1788              :                                 }
    1789              :                         }
    1790              : 
    1791              :                         break;
    1792            0 :                 case PHP_SORT_NATURAL:
    1793            0 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
    1794            0 :                                 if (reverse) {
    1795            0 :                                         return php_colopl_bc_array_reverse_key_compare_string_natural_case;
    1796              :                                 } else {
    1797            0 :                                         return php_colopl_bc_array_key_compare_string_natural_case;
    1798              :                                 }
    1799              :                         } else {
    1800            0 :                                 if (reverse) {
    1801            0 :                                         return php_colopl_bc_array_reverse_key_compare_string_natural;
    1802              :                                 } else {
    1803            0 :                                         return php_colopl_bc_array_key_compare_string_natural;
    1804              :                                 }
    1805              :                         }
    1806              : 
    1807              :                         break;
    1808            0 :                 case PHP_SORT_LOCALE_STRING:
    1809            0 :                         if (reverse) {
    1810            0 :                                 return php_colopl_bc_array_reverse_key_compare_string_locale;
    1811              :                         } else {
    1812            0 :                                 return php_colopl_bc_array_key_compare_string_locale;
    1813              :                         }
    1814              : 
    1815              :                         break;
    1816           44 :                 case PHP_SORT_REGULAR:
    1817              :                 default:
    1818           44 :                         if (reverse) {
    1819           24 :                                 return php_colopl_bc_array_reverse_key_compare;
    1820              :                         } else {
    1821           20 :                                 return php_colopl_bc_array_key_compare;
    1822              :                         }
    1823              : 
    1824              :                         break;
    1825              :         }
    1826              : 
    1827              :         return NULL;
    1828              : }
    1829              : 
    1830          100 : static bucket_compare_func_t php_colopl_bc_get_data_compare_func(zend_long sort_type, int reverse)
    1831              : {
    1832          100 :         switch (sort_type & ~PHP_SORT_FLAG_CASE) {
    1833            0 :                 case PHP_SORT_NUMERIC:
    1834            0 :                         if (reverse) {
    1835            0 :                                 return php_colopl_bc_array_reverse_data_compare_numeric;
    1836              :                         } else {
    1837            0 :                                 return php_colopl_bc_array_data_compare_numeric;
    1838              :                         }
    1839              : 
    1840              :                         break;
    1841            8 :                 case PHP_SORT_STRING:
    1842            8 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
    1843            0 :                                 if (reverse) {
    1844            0 :                                         return php_colopl_bc_array_reverse_data_compare_string_case;
    1845              :                                 } else {
    1846            0 :                                         return php_colopl_bc_array_data_compare_string_case;
    1847              :                                 }
    1848              :                         } else {
    1849            8 :                                 if (reverse) {
    1850            0 :                                         return php_colopl_bc_array_reverse_data_compare_string;
    1851              :                                 } else {
    1852            8 :                                         return php_colopl_bc_array_data_compare_string;
    1853              :                                 }
    1854              :                         }
    1855              : 
    1856              :                         break;
    1857            0 :                 case PHP_SORT_NATURAL:
    1858            0 :                         if (sort_type & PHP_SORT_FLAG_CASE) {
    1859            0 :                                 if (reverse) {
    1860            0 :                                         return php_colopl_bc_array_reverse_natural_case_compare;
    1861              :                                 } else {
    1862            0 :                                         return php_colopl_bc_array_natural_case_compare;
    1863              :                                 }
    1864              :                         } else {
    1865            0 :                                 if (reverse) {
    1866            0 :                                         return php_colopl_bc_array_reverse_natural_compare;
    1867              :                                 } else {
    1868            0 :                                         return php_colopl_bc_array_natural_compare;
    1869              :                                 }
    1870              :                         }
    1871              : 
    1872              :                         break;
    1873            0 :                 case PHP_SORT_LOCALE_STRING:
    1874            0 :                         if (reverse) {
    1875            0 :                                 return php_colopl_bc_array_reverse_data_compare_string_locale;
    1876              :                         } else {
    1877            0 :                                 return php_colopl_bc_array_data_compare_string_locale;
    1878              :                         }
    1879              : 
    1880              :                         break;
    1881           92 :                 case PHP_SORT_REGULAR:
    1882              :                 default:
    1883           92 :                         if (reverse) {
    1884           40 :                                 return php_colopl_bc_array_reverse_data_compare;
    1885              :                         } else {
    1886           52 :                                 return php_colopl_bc_array_data_compare;
    1887              :                         }
    1888              : 
    1889              :                         break;
    1890              :         }
    1891              : 
    1892              :         return NULL;
    1893              : }
    1894              : 
    1895         1496 : int php_colopl_bc_multisort_compare(const void *a, const void *b)
    1896              : {
    1897         1496 :         Bucket *ab = *(Bucket **)a;
    1898         1496 :         Bucket *bb = *(Bucket **)b;
    1899              :         int r;
    1900              :         zend_long result;
    1901              : 
    1902         1496 :         r = 0;
    1903              :         do {
    1904         2992 :                 result = COLOPL_BC_G(multisort_func)[r](&ab[r], &bb[r]);
    1905         2992 :                 if (result != 0) {
    1906            0 :                         return result > 0 ? 1 : -1;
    1907              :                 }
    1908         2992 :                 r++;
    1909         2992 :         } while (Z_TYPE(ab[r].val) != IS_UNDEF);
    1910              : 
    1911         1496 :         return 0;
    1912              : }
    1913              : 
    1914              : #define COLOPL_BC_MULTISORT_ABORT       \
    1915              :         efree(func);    \
    1916              :         efree(arrays);  \
    1917              :         return;
    1918              : 
    1919          596 : static void colopl_bc_array_bucket_p_swap(void *p, void *q)
    1920              : {
    1921              :         Bucket *t;
    1922          596 :         Bucket **f = (Bucket **)p;
    1923          596 :         Bucket **g = (Bucket **)q;
    1924              : 
    1925          596 :         t = *f;
    1926          596 :         *f = *g;
    1927          596 :         *g = t;
    1928          596 : }
    1929              : 
    1930            8 : static inline void php_colopl_bc_search_array(INTERNAL_FUNCTION_PARAMETERS, int behavior)
    1931              : {
    1932              :         zval *value,                            /* value to check for */
    1933              :                  *array,                                /* array to check in */
    1934              :                  *entry;                                /* pointer to array entry */
    1935              :         zend_ulong num_idx;
    1936              :         zend_string *str_idx;
    1937            8 :         bool strict = 0;                        /* strict comparison or not */
    1938              : 
    1939            8 :         ZEND_PARSE_PARAMETERS_START(2, 3)
    1940            8 :                 Z_PARAM_ZVAL(value)
    1941            8 :                 Z_PARAM_ARRAY(array)
    1942            8 :                 Z_PARAM_OPTIONAL
    1943            8 :                 Z_PARAM_BOOL(strict)
    1944            8 :         ZEND_PARSE_PARAMETERS_END();
    1945              : 
    1946            8 :         if (strict) {
    1947            0 :                 if (Z_TYPE_P(value) == IS_LONG) {
    1948            0 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1949            0 :                                 ZVAL_DEREF(entry);
    1950            0 :                                 if (Z_TYPE_P(entry) == IS_LONG && Z_LVAL_P(entry) == Z_LVAL_P(value)) {
    1951            0 :                                         if (behavior == 0) {
    1952            0 :                                                 RETURN_TRUE;
    1953              :                                         } else {
    1954            0 :                                                 if (str_idx) {
    1955            0 :                                                         RETURN_STR_COPY(str_idx);
    1956              :                                                 } else {
    1957            0 :                                                         RETURN_LONG(num_idx);
    1958              :                                                 }
    1959              :                                         }
    1960              :                                 }
    1961              :                         } ZEND_HASH_FOREACH_END();
    1962              :                 } else {
    1963            0 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1964            0 :                                 ZVAL_DEREF(entry);
    1965            0 :                                 if (fast_is_identical_function(value, entry)) {
    1966            0 :                                         if (behavior == 0) {
    1967            0 :                                                 RETURN_TRUE;
    1968              :                                         } else {
    1969            0 :                                                 if (str_idx) {
    1970            0 :                                                         RETURN_STR_COPY(str_idx);
    1971              :                                                 } else {
    1972            0 :                                                         RETURN_LONG(num_idx);
    1973              :                                                 }
    1974              :                                         }
    1975              :                                 }
    1976              :                         } ZEND_HASH_FOREACH_END();
    1977              :                 }
    1978              :         } else {
    1979            8 :                 if (Z_TYPE_P(value) == IS_LONG) {
    1980            0 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1981            0 :                                 if (php_colopl_bc_fast_equal_check_long(value, entry)) {
    1982            0 :                                         if (behavior == 0) {
    1983            0 :                                                 RETURN_TRUE;
    1984              :                                         } else {
    1985            0 :                                                 if (str_idx) {
    1986            0 :                                                         RETURN_STR_COPY(str_idx);
    1987              :                                                 } else {
    1988            0 :                                                         RETURN_LONG(num_idx);
    1989              :                                                 }
    1990              :                                         }
    1991              :                                 }
    1992              :                         } ZEND_HASH_FOREACH_END();
    1993            8 :                 } else if (Z_TYPE_P(value) == IS_STRING) {
    1994            8 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    1995            8 :                                 if (php_colopl_bc_fast_equal_check_string(value, entry)) {
    1996            8 :                                         if (behavior == 0) {
    1997            4 :                                                 RETURN_TRUE;
    1998              :                                         } else {
    1999            4 :                                                 if (str_idx) {
    2000            4 :                                                         RETURN_STR_COPY(str_idx);
    2001              :                                                 } else {
    2002            0 :                                                         RETURN_LONG(num_idx);
    2003              :                                                 }
    2004              :                                         }
    2005              :                                 }
    2006              :                         } ZEND_HASH_FOREACH_END();
    2007              :                 } else {
    2008            0 :                         ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(array), num_idx, str_idx, entry) {
    2009            0 :                                 if (php_colopl_bc_fast_equal_check_function(value, entry)) {
    2010            0 :                                         if (behavior == 0) {
    2011            0 :                                                 RETURN_TRUE;
    2012              :                                         } else {
    2013            0 :                                                 if (str_idx) {
    2014            0 :                                                         RETURN_STR_COPY(str_idx);
    2015              :                                                 } else {
    2016            0 :                                                         RETURN_LONG(num_idx);
    2017              :                                                 }
    2018              :                                         }
    2019              :                                 }
    2020              :                         } ZEND_HASH_FOREACH_END();
    2021              :                 }
    2022              :         }
    2023              : 
    2024            0 :         RETURN_FALSE;
    2025              : }
    2026              : 
    2027              : #define PHP_COLOPL_BC_ARRAY_CMP_FUNC_VARS \
    2028              :         zend_fcall_info old_user_compare_fci; \
    2029              :         zend_fcall_info_cache old_user_compare_fci_cache \
    2030              : 
    2031              : #define PHP_COLOPL_BC_ARRAY_CMP_FUNC_BACKUP() \
    2032              :         old_user_compare_fci = COLOPL_BC_G(user_compare_fci); \
    2033              :         old_user_compare_fci_cache = COLOPL_BC_G(user_compare_fci_cache); \
    2034              :         COLOPL_BC_G(user_compare_fci_cache) = empty_fcall_info_cache; \
    2035              : 
    2036              : #define PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE() \
    2037              :         zend_release_fcall_info_cache(&COLOPL_BC_G(user_compare_fci_cache)); \
    2038              :         COLOPL_BC_G(user_compare_fci) = old_user_compare_fci; \
    2039              :         COLOPL_BC_G(user_compare_fci_cache) = old_user_compare_fci_cache; \
    2040              : 
    2041          120 : static inline void php_colopl_bc_report_incompatible_sort(void)
    2042              : {
    2043          120 :         if (COLOPL_BC_G(php74_sort_mode) & COLOPL_BC_PHP74_SORT_MODE_LOG) {
    2044           96 :                 php_colopl_bc_log_incompatibility("Incompatible sort detected");
    2045              :         }
    2046              : 
    2047          120 :         if (COLOPL_BC_G(php74_sort_mode) & COLOPL_BC_PHP74_SORT_MODE_DEPRECATED) {
    2048           96 :                 php_error_docref(NULL, E_DEPRECATED, "Incompatible sort detected");
    2049              :         }
    2050          120 : }
    2051              : 
    2052          216 : static inline void php_colopl_bc_hash_sort(HashTable *ht, bucket_compare_func_t compare_func, bool renumber, bool compare_func_may_call_user_code)
    2053              : {
    2054              :         (void) compare_func_may_call_user_code;
    2055              : 
    2056          216 :         zend_hash_sort_ex(ht, zend_sort, compare_func, renumber);
    2057          216 : }
    2058              : 
    2059          216 : static void legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAMETERS, zval *array, bucket_compare_func_t compare_func, bool renumber, bool compare_func_may_call_user_code)
    2060              : {
    2061          216 :         php_colopl_bc_hash_sort(Z_ARRVAL_P(array), compare_func, renumber, compare_func_may_call_user_code);
    2062          216 : }
    2063              : 
    2064          180 : static void legacy_hash_sort_slow(INTERNAL_FUNCTION_PARAMETERS, zval *array, bucket_compare_func_t compare_func, bool renumber, bool compare_func_may_call_user_code)
    2065              : {
    2066              :         php_colopl_bc_snapshot_context snapshot_context;
    2067              :         php_colopl_bc_diagnostic_error_state error_state;
    2068              :         php_colopl_bc_user_sort_context user_sort_context, *old_user_sort_context;
    2069              :         zend_internal_function *fn;
    2070              :         zval legacy, native, original, user_sort_original;
    2071              :         HashTable seen_arrays;
    2072          180 :         bool have_native_snapshot, native_failed = false,
    2073          180 :                 may_call_user_code = compare_func_may_call_user_code, track_user_sort = compare_func_may_call_user_code,
    2074          180 :                 user_sort_incompatible = false;
    2075              :         char *fnname_ptr;
    2076              : 
    2077          180 :         if (COLOPL_BC_G(php74_sort_mode) <= COLOPL_BC_PHP74_SORT_MODE_SILENT) {
    2078            0 :                 legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, compare_func, renumber, compare_func_may_call_user_code);
    2079            0 :                 return;
    2080              :         }
    2081              : 
    2082          180 :         ZVAL_UNDEF(&native);
    2083          180 :         ZVAL_UNDEF(&user_sort_original);
    2084          180 :         ZVAL_DUP(&legacy, array);
    2085          180 :         php_colopl_bc_snapshot_context_init(&snapshot_context);
    2086              : 
    2087          180 :         if (!may_call_user_code) {
    2088          112 :                 zend_hash_init(&seen_arrays, 8, NULL, NULL, 0);
    2089          112 :                 may_call_user_code = php_colopl_bc_zval_contains_object(array, &seen_arrays);
    2090          112 :                 zend_hash_destroy(&seen_arrays);
    2091              :         }
    2092              : 
    2093          180 :         if (!may_call_user_code) {
    2094          108 :                 may_call_user_code = php_colopl_bc_zval_contains_child_array(array);
    2095              :         }
    2096              : 
    2097          180 :         if (!may_call_user_code) {
    2098          100 :                 may_call_user_code = php_colopl_bc_zval_contains_recursive_array(array);
    2099              :         }
    2100              : 
    2101          180 :         have_native_snapshot = !may_call_user_code && php_colopl_bc_snapshot_zval(&native, array, &snapshot_context);
    2102              : 
    2103          180 :         if (track_user_sort) {
    2104           68 :                 ZVAL_DUP(&user_sort_original, array);
    2105           68 :                 SEPARATE_ARRAY(&user_sort_original);
    2106           68 :                 php_colopl_bc_user_sort_context_init(&user_sort_context);
    2107           68 :                 old_user_sort_context = COLOPL_BC_G(php74_user_sort_context);
    2108           68 :                 COLOPL_BC_G(php74_user_sort_context) = &user_sort_context;
    2109              :         }
    2110              : 
    2111          180 :         legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAM_PASSTHRU, &legacy, compare_func, renumber, compare_func_may_call_user_code);
    2112              : 
    2113          180 :         if (track_user_sort) {
    2114           68 :                 COLOPL_BC_G(php74_user_sort_context) = old_user_sort_context;
    2115           68 :                 if (!EG(exception)) {
    2116           68 :                         user_sort_incompatible = php_colopl_bc_user_sort_context_detect_incompatible_order(&user_sort_context, &legacy, &user_sort_original, renumber);
    2117              :                 }
    2118           68 :                 php_colopl_bc_user_sort_context_destroy(&user_sort_context);
    2119           68 :                 if (!Z_ISUNDEF(user_sort_original)) {
    2120           68 :                         zval_ptr_dtor(&user_sort_original);
    2121              :                 }
    2122              :         }
    2123              : 
    2124              :         /* Get native PHP bundled (internal) function ptr */
    2125          180 :         fnname_ptr = execute_data->func->internal_function.function_name->val;
    2126              :         /*
    2127              :          * Extracting last piece of namespaces, they're always identical a native function name
    2128              :          *
    2129              :          * e.g.)
    2130              :          * Colopl\ColoplBc\Php74\*****
    2131              :          *                       ^^^^^
    2132              :          */
    2133         4140 :         while (strchr(fnname_ptr, '\\')) {
    2134         3960 :                 ++fnname_ptr;
    2135              :         }
    2136          180 :         fn = zend_hash_str_find_ptr(EG(function_table), fnname_ptr, strlen(fnname_ptr));
    2137          180 :         if (EXPECTED(fn != NULL) && have_native_snapshot && !EG(exception)) {
    2138          100 :                 ZVAL_COPY_VALUE(&original, array);
    2139          100 :                 ZVAL_COPY_VALUE(array, &native);
    2140              : 
    2141          100 :                 php_colopl_bc_diagnostic_error_state_suppress(&error_state);
    2142          100 :                 fn->handler(INTERNAL_FUNCTION_PARAM_PASSTHRU);
    2143          100 :                 native_failed = php_colopl_bc_clear_diagnostic_exception();
    2144          100 :                 php_colopl_bc_diagnostic_error_state_restore(&error_state);
    2145          100 :                 ZVAL_COPY_VALUE(&native, array);
    2146          100 :                 ZVAL_COPY_VALUE(array, &original);
    2147              : 
    2148          100 :                 if (!native_failed && !php_colopl_bc_same_snapshot_value(&legacy, &native, &snapshot_context)) {
    2149           72 :                         php_colopl_bc_report_incompatible_sort();
    2150              :                 }
    2151              :         }
    2152              : 
    2153          180 :         if (user_sort_incompatible && !EG(exception)) {
    2154           48 :                 php_colopl_bc_report_incompatible_sort();
    2155              :         }
    2156              : 
    2157          180 :         if (!Z_ISUNDEF(native)) {
    2158          100 :                 zval_ptr_dtor(&native);
    2159              :         }
    2160              : 
    2161          180 :         php_colopl_bc_snapshot_context_destroy(&snapshot_context);
    2162              : 
    2163          180 :         zval_ptr_dtor(array);
    2164          180 :         ZVAL_ARR(array, Z_ARRVAL(legacy));
    2165              : }
    2166              : 
    2167          282 : PHP_INI_MH(OnUpdateSortMode)
    2168              : {
    2169          282 :         if (OnUpdateLong(entry, new_value, mh_arg1, mh_arg2, mh_arg3, stage) == FAILURE) {
    2170            0 :                 return FAILURE;
    2171              :         }
    2172              : 
    2173          282 :         if (COLOPL_BC_G(php74_sort_mode) <= 0) {
    2174          166 :                 COLOPL_BC_G(php74_hash_sort_func) = legacy_hash_sort_fast;
    2175              :         } else {
    2176          116 :                 COLOPL_BC_G(php74_hash_sort_func) = legacy_hash_sort_slow;
    2177              :         }
    2178              : 
    2179          282 :         return SUCCESS;
    2180              : }
    2181              : 
    2182           80 : static void php_colopl_bc_usort(INTERNAL_FUNCTION_PARAMETERS, bucket_compare_func_t compare_func, zend_bool renumber)
    2183              : {
    2184              :         zval *array, arr;
    2185              :         PHP_COLOPL_BC_ARRAY_CMP_FUNC_VARS;
    2186              : 
    2187           80 :         PHP_COLOPL_BC_ARRAY_CMP_FUNC_BACKUP();
    2188              : 
    2189           80 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2190           80 :                 Z_PARAM_ARRAY_EX2(array, 0, 1, 0)
    2191           80 :                 Z_PARAM_FUNC(COLOPL_BC_G(user_compare_fci), COLOPL_BC_G(user_compare_fci_cache))
    2192           80 :         ZEND_PARSE_PARAMETERS_END_EX( PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE(); return );
    2193              : 
    2194           80 :         if (zend_hash_num_elements(Z_ARRVAL_P(array)) == 0) {
    2195            0 :                 PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE();
    2196            0 :                 RETURN_TRUE;
    2197              :         }
    2198              : 
    2199           80 :         if (COLOPL_BC_G(php74_sort_mode) <= COLOPL_BC_PHP74_SORT_MODE_SILENT) {
    2200           12 :                 SEPARATE_ARRAY(array);
    2201           12 :                 legacy_hash_sort_fast(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, compare_func, renumber, true);
    2202           12 :                 PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE();
    2203           12 :                 RETURN_TRUE;
    2204              :         }
    2205              : 
    2206              :         /* Copy array, so the diagnostic path can compare the legacy result. */
    2207           68 :         ZVAL_DUP(&arr, array);
    2208              : 
    2209           68 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, &arr, compare_func, renumber, true);
    2210              : 
    2211           68 :         zval_ptr_dtor(array);
    2212           68 :         ZVAL_ARR(array, Z_ARRVAL(arr));
    2213              : 
    2214           68 :         PHP_COLOPL_BC_ARRAY_CMP_FUNC_RESTORE();
    2215           68 :         RETURN_TRUE;
    2216              : }
    2217              : 
    2218           20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_ksort)
    2219              : {
    2220              :         zval *array;
    2221           20 :         zend_long sort_type = PHP_SORT_REGULAR;
    2222              :         bucket_compare_func_t cmp;
    2223              : 
    2224           20 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    2225           20 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    2226           20 :                 Z_PARAM_OPTIONAL
    2227           20 :                 Z_PARAM_LONG(sort_type)
    2228           20 :         ZEND_PARSE_PARAMETERS_END();
    2229              : 
    2230           20 :         cmp = php_colopl_bc_get_key_compare_func(sort_type, 0);
    2231              : 
    2232           20 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0, false);
    2233              : 
    2234           20 :         RETURN_TRUE;
    2235              : }
    2236              : 
    2237           24 : PHP_FUNCTION(Colopl_ColoplBc_Php74_krsort)
    2238              : {
    2239              :         zval *array;
    2240           24 :         zend_long sort_type = PHP_SORT_REGULAR;
    2241              :         bucket_compare_func_t cmp;
    2242              : 
    2243           24 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    2244           24 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    2245           24 :                 Z_PARAM_OPTIONAL
    2246           24 :                 Z_PARAM_LONG(sort_type)
    2247           24 :         ZEND_PARSE_PARAMETERS_END();
    2248              : 
    2249           24 :         cmp = php_colopl_bc_get_key_compare_func(sort_type, 1);
    2250              : 
    2251           24 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0, false);
    2252              : 
    2253           24 :         RETURN_TRUE;
    2254              : }
    2255              : 
    2256           20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_asort)
    2257              : {
    2258              :         zval *array;
    2259           20 :         zend_long sort_type = PHP_SORT_REGULAR;
    2260              :         bucket_compare_func_t cmp;
    2261              : 
    2262           20 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    2263           20 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    2264           20 :                 Z_PARAM_OPTIONAL
    2265           20 :                 Z_PARAM_LONG(sort_type)
    2266           20 :         ZEND_PARSE_PARAMETERS_END();
    2267              : 
    2268           20 :         cmp = php_colopl_bc_get_data_compare_func(sort_type, 0);
    2269              : 
    2270           20 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0, false);
    2271              : 
    2272           20 :         RETURN_TRUE;
    2273              : }
    2274              : 
    2275           20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_arsort)
    2276              : {
    2277              :         zval *array;
    2278           20 :         zend_long sort_type = PHP_SORT_REGULAR;
    2279              :         bucket_compare_func_t cmp;
    2280              : 
    2281           20 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    2282           20 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    2283           20 :                 Z_PARAM_OPTIONAL
    2284           20 :                 Z_PARAM_LONG(sort_type)
    2285           20 :         ZEND_PARSE_PARAMETERS_END();
    2286              : 
    2287           20 :         cmp = php_colopl_bc_get_data_compare_func(sort_type, 1);
    2288              : 
    2289           20 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 0, false);
    2290              : 
    2291           20 :         RETURN_TRUE;
    2292              : }
    2293              : 
    2294           32 : PHP_FUNCTION(Colopl_ColoplBc_Php74_sort)
    2295              : {
    2296              :         zval *array;
    2297           32 :         zend_long sort_type = PHP_SORT_REGULAR;
    2298              :         bucket_compare_func_t cmp;
    2299              : 
    2300           32 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    2301           32 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    2302           32 :                 Z_PARAM_OPTIONAL
    2303           32 :                 Z_PARAM_LONG(sort_type)
    2304           32 :         ZEND_PARSE_PARAMETERS_END();
    2305              : 
    2306           32 :         cmp = php_colopl_bc_get_data_compare_func(sort_type, 0);
    2307              : 
    2308           32 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 1, false);
    2309              : 
    2310           32 :         RETURN_TRUE;
    2311              : }
    2312              : 
    2313           20 : PHP_FUNCTION(Colopl_ColoplBc_Php74_rsort)
    2314              : {
    2315              :         zval *array;
    2316           20 :         zend_long sort_type = PHP_SORT_REGULAR;
    2317              :         bucket_compare_func_t cmp;
    2318              : 
    2319           20 :         ZEND_PARSE_PARAMETERS_START(1, 2)
    2320           20 :                 Z_PARAM_ARRAY_EX(array, 0, 1)
    2321           20 :                 Z_PARAM_OPTIONAL
    2322           20 :                 Z_PARAM_LONG(sort_type)
    2323           20 :         ZEND_PARSE_PARAMETERS_END();
    2324              : 
    2325           20 :         cmp = php_colopl_bc_get_data_compare_func(sort_type, 1);
    2326              : 
    2327           20 :         COLOPL_BC_G(php74_hash_sort_func)(INTERNAL_FUNCTION_PARAM_PASSTHRU, array, cmp, 1, false);
    2328              : 
    2329           20 :         RETURN_TRUE;
    2330              : }
    2331              : 
    2332           32 : PHP_FUNCTION(Colopl_ColoplBc_Php74_usort)
    2333              : {
    2334           32 :         php_colopl_bc_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_colopl_bc_array_user_compare, 1);
    2335           32 : }
    2336              : 
    2337           24 : PHP_FUNCTION(Colopl_ColoplBc_Php74_uasort)
    2338              : {
    2339           24 :         php_colopl_bc_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_colopl_bc_array_user_compare, 0);
    2340           24 : }
    2341              : 
    2342           24 : PHP_FUNCTION(Colopl_ColoplBc_Php74_uksort)
    2343              : {
    2344           24 :         php_colopl_bc_usort(INTERNAL_FUNCTION_PARAM_PASSTHRU, php_colopl_bc_array_user_key_compare, 0);
    2345           24 : }
    2346              : 
    2347            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_in_array)
    2348              : {
    2349            4 :         php_colopl_bc_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
    2350            4 : }
    2351              : 
    2352            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_search)
    2353              : {
    2354            4 :         php_colopl_bc_search_array(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
    2355            4 : }
    2356              : 
    2357            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_keys)
    2358              : {
    2359              :         zval *input,                            /* Input array */
    2360            4 :                  *search_value = NULL,  /* Value to search for */
    2361              :                  *entry,                                /* An entry in the input array */
    2362              :                  new_val;                               /* New value */
    2363            4 :         bool strict = 0;                        /* do strict comparison */
    2364              :         zend_ulong num_idx;
    2365              :         zend_string *str_idx;
    2366              :         zend_array *arrval;
    2367              :         zend_ulong elem_count;
    2368              : 
    2369            4 :         ZEND_PARSE_PARAMETERS_START(1, 3)
    2370            4 :                 Z_PARAM_ARRAY(input)
    2371            4 :                 Z_PARAM_OPTIONAL
    2372            4 :                 Z_PARAM_ZVAL(search_value)
    2373            4 :                 Z_PARAM_BOOL(strict)
    2374            4 :         ZEND_PARSE_PARAMETERS_END();
    2375            4 :         arrval = Z_ARRVAL_P(input);
    2376            4 :         elem_count = zend_hash_num_elements(arrval);
    2377              : 
    2378              :         /* Base case: empty input */
    2379            4 :         if (!elem_count) {
    2380            0 :                 RETURN_COPY(input);
    2381              :         }
    2382              : 
    2383              :         /* Initialize return array */
    2384            4 :         if (search_value != NULL) {
    2385            4 :                 array_init(return_value);
    2386              : 
    2387            4 :                 if (strict) {
    2388            0 :                         ZEND_HASH_FOREACH_KEY_VAL(arrval, num_idx, str_idx, entry) {
    2389            0 :                                 ZVAL_DEREF(entry);
    2390            0 :                                 if (fast_is_identical_function(search_value, entry)) {
    2391            0 :                                         if (str_idx) {
    2392            0 :                                                 ZVAL_STR_COPY(&new_val, str_idx);
    2393              :                                         } else {
    2394            0 :                                                 ZVAL_LONG(&new_val, num_idx);
    2395              :                                         }
    2396            0 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
    2397              :                                 }
    2398              :                         } ZEND_HASH_FOREACH_END();
    2399              :                 } else {
    2400           12 :                         ZEND_HASH_FOREACH_KEY_VAL(arrval, num_idx, str_idx, entry) {
    2401            8 :                                 if (php_colopl_bc_fast_equal_check_function(search_value, entry)) {
    2402            8 :                                         if (str_idx) {
    2403            8 :                                                 ZVAL_STR_COPY(&new_val, str_idx);
    2404              :                                         } else {
    2405            0 :                                                 ZVAL_LONG(&new_val, num_idx);
    2406              :                                         }
    2407            8 :                                         zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &new_val);
    2408              :                                 }
    2409              :                         } ZEND_HASH_FOREACH_END();
    2410              :                 }
    2411              :         } else {
    2412            0 :                 array_init_size(return_value, elem_count);
    2413            0 :                 zend_hash_real_init_packed(Z_ARRVAL_P(return_value));
    2414            0 :                 ZEND_HASH_FILL_PACKED(Z_ARRVAL_P(return_value)) {
    2415            0 :                         if (HT_IS_PACKED(arrval) && HT_IS_WITHOUT_HOLES(arrval)) {
    2416              :                                 /* Optimistic case: range(0..n-1) for vector-like packed array */
    2417            0 :                                 zend_ulong lval = 0;
    2418              : 
    2419            0 :                                 for (; lval < elem_count; ++lval) {
    2420            0 :                                         ZEND_HASH_FILL_SET_LONG(lval);
    2421            0 :                                         ZEND_HASH_FILL_NEXT();
    2422              :                                 }
    2423              :                         } else {
    2424              :                                 /* Go through input array and add keys to the return array */
    2425            0 :                                 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input), num_idx, str_idx, entry) {
    2426            0 :                                         if (str_idx) {
    2427            0 :                                                 ZEND_HASH_FILL_SET_STR_COPY(str_idx);
    2428              :                                         } else {
    2429            0 :                                                 ZEND_HASH_FILL_SET_LONG(num_idx);
    2430              :                                         }
    2431            0 :                                         ZEND_HASH_FILL_NEXT();
    2432              :                                 } ZEND_HASH_FOREACH_END();
    2433              :                         }
    2434            0 :                 } ZEND_HASH_FILL_END();
    2435              :         }
    2436              : }
    2437              : 
    2438              : #if PHP_VERSION_ID < 80200
    2439              : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_multisort)
    2440              : {
    2441              :         zval*                   args;
    2442              :         zval**                  arrays;
    2443              :         Bucket**                indirect;
    2444              :         uint32_t                idx;
    2445              :         Bucket*                 p;
    2446              :         HashTable*              hash;
    2447              :         int                             argc;
    2448              :         int                             array_size;
    2449              :         int                             num_arrays = 0;
    2450              :         int                             parse_state[COLOPL_BC_MULTISORT_LAST]; /* 0 - flag not allowed 1 - flag allowed */
    2451              :         int                             sort_order = PHP_SORT_ASC;
    2452              :         int                             sort_type = PHP_SORT_REGULAR;
    2453              :         int                             i, k, n;
    2454              :         bucket_compare_func_t *func;
    2455              : 
    2456              :         ZEND_PARSE_PARAMETERS_START(1, -1)
    2457              :                 Z_PARAM_VARIADIC('+', args, argc)
    2458              :         ZEND_PARSE_PARAMETERS_END();
    2459              : 
    2460              :         /* Allocate space for storing pointers to input arrays and sort flags. */
    2461              :         arrays = (zval **)ecalloc(argc, sizeof(zval *));
    2462              :         for (i = 0; i < COLOPL_BC_MULTISORT_LAST; i++) {
    2463              :                 parse_state[i] = 0;
    2464              :         }
    2465              :         func = COLOPL_BC_G(multisort_func) = ecalloc(argc, sizeof(bucket_compare_func_t));
    2466              : 
    2467              :         /* Here we go through the input arguments and parse them. Each one can
    2468              :          * be either an array or a sort flag which follows an array. If not
    2469              :          * specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
    2470              :          * accordingly. There can't be two sort flags of the same type after an
    2471              :          * array, and the very first argument has to be an array. */
    2472              :         for (i = 0; i < argc; i++) {
    2473              :                 zval *arg = &args[i];
    2474              : 
    2475              :                 ZVAL_DEREF(arg);
    2476              :                 if (Z_TYPE_P(arg) == IS_ARRAY) {
    2477              :                         SEPARATE_ARRAY(arg);
    2478              :                         /* We see the next array, so we update the sort flags of
    2479              :                          * the previous array and reset the sort flags. */
    2480              :                         if (i > 0) {
    2481              :                                 COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    2482              :                                 sort_order = PHP_SORT_ASC;
    2483              :                                 sort_type = PHP_SORT_REGULAR;
    2484              :                         }
    2485              :                         arrays[num_arrays++] = arg;
    2486              : 
    2487              :                         /* Next one may be an array or a list of sort flags. */
    2488              :                         for (k = 0; k < COLOPL_BC_MULTISORT_LAST; k++) {
    2489              :                                 parse_state[k] = 1;
    2490              :                         }
    2491              :                 } else if (Z_TYPE_P(arg) == IS_LONG) {
    2492              :                         switch (Z_LVAL_P(arg) & ~PHP_SORT_FLAG_CASE) {
    2493              :                                 case PHP_SORT_ASC:
    2494              :                                 case PHP_SORT_DESC:
    2495              :                                         /* flag allowed here */
    2496              :                                         if (parse_state[COLOPL_BC_MULTISORT_ORDER] == 1) {
    2497              :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    2498              :                                                 sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? PHP_SORT_DESC : PHP_SORT_ASC;
    2499              :                                                 parse_state[COLOPL_BC_MULTISORT_ORDER] = 0;
    2500              :                                         } else {
    2501              :                                                 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
    2502              :                                                 COLOPL_BC_MULTISORT_ABORT;
    2503              :                                         }
    2504              :                                         break;
    2505              : 
    2506              :                                 case PHP_SORT_REGULAR:
    2507              :                                 case PHP_SORT_NUMERIC:
    2508              :                                 case PHP_SORT_STRING:
    2509              :                                 case PHP_SORT_NATURAL:
    2510              :                                 case PHP_SORT_LOCALE_STRING:
    2511              :                                         /* flag allowed here */
    2512              :                                         if (parse_state[COLOPL_BC_MULTISORT_TYPE] == 1) {
    2513              :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    2514              :                                                 sort_type = (int)Z_LVAL_P(arg);
    2515              :                                                 parse_state[COLOPL_BC_MULTISORT_TYPE] = 0;
    2516              :                                         } else {
    2517              :                                                 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
    2518              :                                                 COLOPL_BC_MULTISORT_ABORT;
    2519              :                                         }
    2520              :                                         break;
    2521              : 
    2522              :                                 default:
    2523              :                                         zend_argument_value_error(i + 1, "must be a valid sort flag");
    2524              :                                         COLOPL_BC_MULTISORT_ABORT;
    2525              :                                         break;
    2526              : 
    2527              :                         }
    2528              :                 } else {
    2529              :                         zend_argument_type_error(i + 1, "must be an array or a sort flag");
    2530              :                         COLOPL_BC_MULTISORT_ABORT;
    2531              :                 }
    2532              :         }
    2533              :         /* Take care of the last array sort flags. */
    2534              :         COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    2535              : 
    2536              :         /* Make sure the arrays are of the same size. */
    2537              :         array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
    2538              :         for (i = 0; i < num_arrays; i++) {
    2539              :                 if (zend_hash_num_elements(Z_ARRVAL_P(arrays[i])) != (uint32_t)array_size) {
    2540              :                         zend_value_error("Array sizes are inconsistent");
    2541              :                         COLOPL_BC_MULTISORT_ABORT;
    2542              :                 }
    2543              :         }
    2544              : 
    2545              :         /* If all arrays are empty we don't need to do anything. */
    2546              :         if (array_size < 1) {
    2547              :                 efree(func);
    2548              :                 efree(arrays);
    2549              :                 RETURN_TRUE;
    2550              :         }
    2551              : 
    2552              :         /* Create the indirection array. This array is of size MxN, where
    2553              :          * M is the number of entries in each input array and N is the number
    2554              :          * of the input arrays + 1. The last column is NULL to indicate the end
    2555              :          * of the row. */
    2556              :         indirect = (Bucket **)safe_emalloc(array_size, sizeof(Bucket *), 0);
    2557              :         for (i = 0; i < array_size; i++) {
    2558              :                 indirect[i] = (Bucket *)safe_emalloc((num_arrays + 1), sizeof(Bucket), 0);
    2559              :         }
    2560              :         for (i = 0; i < num_arrays; i++) {
    2561              :                 k = 0;
    2562              :                 for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++) {
    2563              :                         p = Z_ARRVAL_P(arrays[i])->arData + idx;
    2564              :                         if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2565              :                         indirect[k][i] = *p;
    2566              :                         k++;
    2567              :                 }
    2568              :         }
    2569              :         for (k = 0; k < array_size; k++) {
    2570              :                 ZVAL_UNDEF(&indirect[k][num_arrays].val);
    2571              :         }
    2572              : 
    2573              :         /* Do the actual sort magic - bada-bim, bada-boom. */
    2574              :         zend_sort(indirect, array_size, sizeof(Bucket *), php_colopl_bc_multisort_compare, (swap_func_t)colopl_bc_array_bucket_p_swap);
    2575              : 
    2576              :         /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
    2577              :         for (i = 0; i < num_arrays; i++) {
    2578              :                 int repack;
    2579              : 
    2580              :                 hash = Z_ARRVAL_P(arrays[i]);
    2581              :                 hash->nNumUsed = array_size;
    2582              :                 hash->nInternalPointer = 0;
    2583              :                 repack = !(HT_FLAGS(hash) & HASH_FLAG_PACKED);
    2584              : 
    2585              :                 for (n = 0, k = 0; k < array_size; k++) {
    2586              :                         hash->arData[k] = indirect[k][i];
    2587              :                         if (hash->arData[k].key == NULL) {
    2588              :                                 hash->arData[k].h = n++;
    2589              :                         } else {
    2590              :                                 repack = 0;
    2591              :                         }
    2592              :                 }
    2593              :                 hash->nNextFreeElement = array_size;
    2594              :                 if (repack) {
    2595              :                         zend_hash_to_packed(hash);
    2596              :                 } else if (!(HT_FLAGS(hash) & HASH_FLAG_PACKED)) {
    2597              :                         zend_hash_rehash(hash);
    2598              :                 }
    2599              :         }
    2600              : 
    2601              :         /* Clean up. */
    2602              :         for (i = 0; i < array_size; i++) {
    2603              :                 efree(indirect[i]);
    2604              :         }
    2605              :         efree(indirect);
    2606              :         efree(func);
    2607              :         efree(arrays);
    2608              :         RETURN_TRUE;
    2609              : }
    2610              : #else
    2611            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_array_multisort)
    2612              : {
    2613              :         zval*                   args;
    2614              :         zval**                  arrays;
    2615              :         Bucket**                indirect;
    2616              :         uint32_t                idx;
    2617              :         HashTable*              hash;
    2618              :         int                             argc;
    2619              :         int                             array_size;
    2620            4 :         int                             num_arrays = 0;
    2621              :         int                             parse_state[COLOPL_BC_MULTISORT_LAST];   /* 0 - flag not allowed 1 - flag allowed */
    2622            4 :         int                             sort_order = PHP_SORT_ASC;
    2623            4 :         int                             sort_type  = PHP_SORT_REGULAR;
    2624              :         int                             i, k, n;
    2625              :         bucket_compare_func_t *func;
    2626              : 
    2627            4 :         ZEND_PARSE_PARAMETERS_START(1, -1)
    2628            4 :                 Z_PARAM_VARIADIC('+', args, argc)
    2629            4 :         ZEND_PARSE_PARAMETERS_END();
    2630              : 
    2631              :         /* Allocate space for storing pointers to input arrays and sort flags. */
    2632            4 :         arrays = (zval **)ecalloc(argc, sizeof(zval *));
    2633           12 :         for (i = 0; i < COLOPL_BC_MULTISORT_LAST; i++) {
    2634            8 :                 parse_state[i] = 0;
    2635              :         }
    2636            4 :         func = COLOPL_BC_G(multisort_func) = ecalloc(argc, sizeof(bucket_compare_func_t));
    2637              : 
    2638              :         /* Here we go through the input arguments and parse them. Each one can
    2639              :          * be either an array or a sort flag which follows an array. If not
    2640              :          * specified, the sort flags defaults to PHP_SORT_ASC and PHP_SORT_REGULAR
    2641              :          * accordingly. There can't be two sort flags of the same type after an
    2642              :          * array, and the very first argument has to be an array. */
    2643           12 :         for (i = 0; i < argc; i++) {
    2644            8 :                 zval *arg = &args[i];
    2645              : 
    2646            8 :                 ZVAL_DEREF(arg);
    2647            8 :                 if (Z_TYPE_P(arg) == IS_ARRAY) {
    2648            8 :                         SEPARATE_ARRAY(arg);
    2649              :                         /* We see the next array, so we update the sort flags of
    2650              :                          * the previous array and reset the sort flags. */
    2651            8 :                         if (i > 0) {
    2652            4 :                                 COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    2653            4 :                                 sort_order = PHP_SORT_ASC;
    2654            4 :                                 sort_type = PHP_SORT_REGULAR;
    2655              :                         }
    2656            8 :                         arrays[num_arrays++] = arg;
    2657              : 
    2658              :                         /* Next one may be an array or a list of sort flags. */
    2659           24 :                         for (k = 0; k < COLOPL_BC_MULTISORT_LAST; k++) {
    2660           16 :                                 parse_state[k] = 1;
    2661              :                         }
    2662            0 :                 } else if (Z_TYPE_P(arg) == IS_LONG) {
    2663            0 :                         switch (Z_LVAL_P(arg) & ~PHP_SORT_FLAG_CASE) {
    2664            0 :                                 case PHP_SORT_ASC:
    2665              :                                 case PHP_SORT_DESC:
    2666              :                                         /* flag allowed here */
    2667            0 :                                         if (parse_state[COLOPL_BC_MULTISORT_ORDER] == 1) {
    2668              :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    2669            0 :                                                 sort_order = Z_LVAL_P(arg) == PHP_SORT_DESC ? PHP_SORT_DESC : PHP_SORT_ASC;
    2670            0 :                                                 parse_state[COLOPL_BC_MULTISORT_ORDER] = 0;
    2671              :                                         } else {
    2672            0 :                                                 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
    2673            0 :                                                 COLOPL_BC_MULTISORT_ABORT;
    2674              :                                         }
    2675            0 :                                         break;
    2676              : 
    2677            0 :                                 case PHP_SORT_REGULAR:
    2678              :                                 case PHP_SORT_NUMERIC:
    2679              :                                 case PHP_SORT_STRING:
    2680              :                                 case PHP_SORT_NATURAL:
    2681              :                                 case PHP_SORT_LOCALE_STRING:
    2682              :                                         /* flag allowed here */
    2683            0 :                                         if (parse_state[COLOPL_BC_MULTISORT_TYPE] == 1) {
    2684              :                                                 /* Save the flag and make sure then next arg is not the current flag. */
    2685            0 :                                                 sort_type = (int)Z_LVAL_P(arg);
    2686            0 :                                                 parse_state[COLOPL_BC_MULTISORT_TYPE] = 0;
    2687              :                                         } else {
    2688            0 :                                                 zend_argument_type_error(i + 1, "must be an array or a sort flag that has not already been specified");
    2689            0 :                                                 COLOPL_BC_MULTISORT_ABORT;
    2690              :                                         }
    2691            0 :                                         break;
    2692              : 
    2693            0 :                                 default:
    2694            0 :                                         zend_argument_value_error(i + 1, "must be a valid sort flag");
    2695            0 :                                         COLOPL_BC_MULTISORT_ABORT;
    2696              :                                         break;
    2697              : 
    2698              :                         }
    2699              :                 } else {
    2700            0 :                         zend_argument_type_error(i + 1, "must be an array or a sort flag");
    2701            0 :                         COLOPL_BC_MULTISORT_ABORT;
    2702              :                 }
    2703              :         }
    2704              :         /* Take care of the last array sort flags. */
    2705            4 :         COLOPL_BC_G(multisort_func)[num_arrays - 1] = php_colopl_bc_get_data_compare_func(sort_type, sort_order != PHP_SORT_ASC);
    2706              : 
    2707              :         /* Make sure the arrays are of the same size. */
    2708            4 :         array_size = zend_hash_num_elements(Z_ARRVAL_P(arrays[0]));
    2709           12 :         for (i = 0; i < num_arrays; i++) {
    2710            8 :                 if (zend_hash_num_elements(Z_ARRVAL_P(arrays[i])) != (uint32_t)array_size) {
    2711            0 :                         zend_value_error("Array sizes are inconsistent");
    2712            0 :                         COLOPL_BC_MULTISORT_ABORT;
    2713              :                 }
    2714              :         }
    2715              : 
    2716              :         /* If all arrays are empty we don't need to do anything. */
    2717            4 :         if (array_size < 1) {
    2718            0 :                 efree(func);
    2719            0 :                 efree(arrays);
    2720            0 :                 RETURN_TRUE;
    2721              :         }
    2722              : 
    2723              :         /* Create the indirection array. This array is of size MxN, where
    2724              :          * M is the number of entries in each input array and N is the number
    2725              :          * of the input arrays + 1. The last column is UNDEF to indicate the end
    2726              :          * of the row. It also stores the original position for stable sorting. */
    2727            4 :         indirect = (Bucket **)safe_emalloc(array_size, sizeof(Bucket *), 0);
    2728          404 :         for (i = 0; i < array_size; i++) {
    2729          400 :                 indirect[i] = (Bucket *)safe_emalloc((num_arrays + 1), sizeof(Bucket), 0);
    2730              :         }
    2731           12 :         for (i = 0; i < num_arrays; i++) {
    2732            8 :                 k = 0;
    2733            8 :                 if (HT_IS_PACKED(Z_ARRVAL_P(arrays[i]))) {
    2734            8 :                         zval *zv = Z_ARRVAL_P(arrays[i])->arPacked;
    2735          808 :                         for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++, zv++) {
    2736          800 :                                 if (Z_TYPE_P(zv) == IS_UNDEF) continue;
    2737          800 :                                 ZVAL_COPY_VALUE(&indirect[k][i].val, zv);
    2738          800 :                                 indirect[k][i].h = idx;
    2739          800 :                                 indirect[k][i].key = NULL;
    2740          800 :                                 k++;
    2741              :                         }
    2742              :                 } else {
    2743            0 :                         Bucket *p = Z_ARRVAL_P(arrays[i])->arData;
    2744            0 :                         for (idx = 0; idx < Z_ARRVAL_P(arrays[i])->nNumUsed; idx++, p++) {
    2745            0 :                                 if (Z_TYPE(p->val) == IS_UNDEF) continue;
    2746            0 :                                 indirect[k][i] = *p;
    2747            0 :                                 k++;
    2748              :                         }
    2749              :                 }
    2750              :         }
    2751          404 :         for (k = 0; k < array_size; k++) {
    2752          400 :                 ZVAL_UNDEF(&indirect[k][num_arrays].val);
    2753          400 :                 Z_EXTRA_P(&indirect[k][num_arrays].val) = k;
    2754              :         }
    2755              : 
    2756              :         /* Do the actual sort magic - bada-bim, bada-boom. */
    2757            4 :         zend_sort(indirect, array_size, sizeof(Bucket *), php_colopl_bc_multisort_compare, (swap_func_t)colopl_bc_array_bucket_p_swap);
    2758              : 
    2759              :         /* Restructure the arrays based on sorted indirect - this is mostly taken from zend_hash_sort() function. */
    2760           12 :         for (i = 0; i < num_arrays; i++) {
    2761            8 :                 hash = Z_ARRVAL_P(arrays[i]);
    2762            8 :                 hash->nNumUsed = array_size;
    2763            8 :                 hash->nNextFreeElement = array_size;
    2764            8 :                 hash->nInternalPointer = 0;
    2765            8 :                 if (HT_IS_PACKED(hash)) {
    2766          808 :                         for (k = 0; k < array_size; k++) {
    2767          800 :                                 ZVAL_COPY_VALUE(&hash->arPacked[k], &indirect[k][i].val);
    2768              :                         }
    2769              :                 } else {
    2770            0 :                         int repack = 1;
    2771              : 
    2772            0 :                         for (n = 0, k = 0; k < array_size; k++) {
    2773            0 :                                 hash->arData[k] = indirect[k][i];
    2774            0 :                                 if (hash->arData[k].key == NULL) {
    2775            0 :                                         hash->arData[k].h = n++;
    2776              :                                 } else {
    2777            0 :                                         repack = 0;
    2778              :                                 }
    2779              :                         }
    2780            0 :                         if (repack) {
    2781            0 :                                 zend_hash_to_packed(hash);
    2782              :                         }
    2783              :                 }
    2784              :         }
    2785              : 
    2786              :         /* Clean up. */
    2787          404 :         for (i = 0; i < array_size; i++) {
    2788          400 :                 efree(indirect[i]);
    2789              :         }
    2790            4 :         efree(indirect);
    2791            4 :         efree(func);
    2792            4 :         efree(arrays);
    2793            4 :         RETURN_TRUE;
    2794              : }
    2795              : #endif
    2796              : 
    2797              : /* BinaryOps */
    2798              : 
    2799         1192 : PHP_FUNCTION(Colopl_ColoplBc_Php74_eq)
    2800              : {
    2801              :         zval *op1, *op2;
    2802              : 
    2803         1192 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2804         1192 :                 Z_PARAM_ZVAL(op1)
    2805         1192 :                 Z_PARAM_ZVAL(op2)
    2806         1192 :         ZEND_PARSE_PARAMETERS_END();
    2807              : 
    2808         1192 :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) == 0);
    2809              : }
    2810              : 
    2811            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_neq)
    2812              : {
    2813              :         zval *op1, *op2;
    2814              : 
    2815            4 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2816            4 :                 Z_PARAM_ZVAL(op1)
    2817            4 :                 Z_PARAM_ZVAL(op2)
    2818            4 :         ZEND_PARSE_PARAMETERS_END();
    2819              : 
    2820            4 :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) != 0);
    2821              : }
    2822              : 
    2823         1160 : PHP_FUNCTION(Colopl_ColoplBc_Php74_lt)
    2824              : {
    2825              :         zval *op1, *op2;
    2826              : 
    2827         1160 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2828         1160 :                 Z_PARAM_ZVAL(op1)
    2829         1160 :                 Z_PARAM_ZVAL(op2)
    2830         1160 :         ZEND_PARSE_PARAMETERS_END();
    2831              : 
    2832         1160 :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) < 0);
    2833              : }
    2834              : 
    2835         1160 : PHP_FUNCTION(Colopl_ColoplBc_Php74_lte)
    2836              : {
    2837              :         zval *op1, *op2;
    2838              : 
    2839         1160 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2840         1160 :                 Z_PARAM_ZVAL(op1)
    2841         1160 :                 Z_PARAM_ZVAL(op2)
    2842         1160 :         ZEND_PARSE_PARAMETERS_END();
    2843              : 
    2844         1160 :         RETURN_BOOL(php_colopl_bc_compare(op1, op2) <= 0);
    2845              : }
    2846              : 
    2847         1160 : PHP_FUNCTION(Colopl_ColoplBc_Php74_gt)
    2848              : {
    2849              :         zval *op1, *op2;
    2850              : 
    2851         1160 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2852         1160 :                 Z_PARAM_ZVAL(op1)
    2853         1160 :                 Z_PARAM_ZVAL(op2)
    2854         1160 :         ZEND_PARSE_PARAMETERS_END();
    2855              : 
    2856         1160 :         RETURN_BOOL(php_colopl_bc_compare(op2, op1) < 0);
    2857              : }
    2858              : 
    2859         1160 : PHP_FUNCTION(Colopl_ColoplBc_Php74_gte)
    2860              : {
    2861              :         zval *op1, *op2;
    2862              : 
    2863         1160 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2864         1160 :                 Z_PARAM_ZVAL(op1)
    2865         1160 :                 Z_PARAM_ZVAL(op2)
    2866         1160 :         ZEND_PARSE_PARAMETERS_END();
    2867              : 
    2868         1160 :         RETURN_BOOL(php_colopl_bc_compare(op2, op1) <= 0);
    2869              : }
    2870              : 
    2871            4 : PHP_FUNCTION(Colopl_ColoplBc_Php74_spaceship)
    2872              : {
    2873              :         zval *op1, *op2;
    2874              : 
    2875            4 :         ZEND_PARSE_PARAMETERS_START(2, 2)
    2876            4 :                 Z_PARAM_ZVAL(op1)
    2877            4 :                 Z_PARAM_ZVAL(op2)
    2878            4 :         ZEND_PARSE_PARAMETERS_END();
    2879              : 
    2880            4 :         RETURN_LONG(php_colopl_bc_compare(op1, op2));
    2881              : }
    2882              : 
    2883              : #endif
        

Generated by: LCOV version 2.0-1