properly check whether an ion int/decimal fits a zend_long
authorMichael Wallner <mike@php.net>
Tue, 14 Dec 2021 11:33:53 +0000 (12:33 +0100)
committerMichael Wallner <mike@php.net>
Tue, 14 Dec 2021 11:54:08 +0000 (12:54 +0100)
ion.c
ion_private.h

diff --git a/ion.c b/ion.c
index 5ec89a1627309c368df47814c4ba71c8465ae397..3e8ba015131f2feaea946b2820ba7d59cf609849 100644 (file)
--- a/ion.c
+++ b/ion.c
 #define DECNUMDIGITS 34 /* DECQUAD_Pmax */
 #include "ionc/ion.h"
 
+static decContext g_dec_ctx;
+static ION_INT *g_ion_int_zend_max, *g_ion_int_zend_min;
+static ION_DECIMAL g_ion_dec_zend_max, g_ion_dec_zend_min;
+
 #include "php_ion.h"
 #define ZEND_ARG_VARIADIC_OBJ_TYPE_MASK(pass_by_ref, name, classname, type_mask, default_value) \
        { #name, ZEND_TYPE_INIT_CLASS_CONST_MASK(#classname, type_mask | _ZEND_ARG_INFO_FLAGS(pass_by_ref, 1, 0)), default_value },
@@ -1447,6 +1451,18 @@ PHP_RSHUTDOWN_FUNCTION(ion)
 
 PHP_MINIT_FUNCTION(ion)
 {
+       if (!g_ion_int_zend_max) {
+               decContextDefault(&g_dec_ctx, DEC_INIT_DECIMAL64);
+
+               ion_int_alloc(NULL, &g_ion_int_zend_max);
+               ion_int_from_long(g_ion_int_zend_max, ZEND_LONG_MAX);
+               ion_decimal_from_ion_int(&g_ion_dec_zend_max, &g_dec_ctx, g_ion_int_zend_max);
+
+               ion_int_alloc(NULL, &g_ion_int_zend_min);
+               ion_int_from_long(g_ion_int_zend_min, ZEND_LONG_MIN);
+               ion_decimal_from_ion_int(&g_ion_dec_zend_min, &g_dec_ctx, g_ion_int_zend_min);
+       }
+
        ce_Annotation = register_class_ion_Annotation();
 
        php_ion_register(type, Type);
@@ -1494,6 +1510,14 @@ PHP_MINIT_FUNCTION(ion)
        return SUCCESS;
 }
 
+PHP_MSHUTDOWN_FUNCTION(ion)
+{
+       if (g_ion_int_zend_max) {
+               ion_int_free(g_ion_int_zend_max);
+               ion_int_free(g_ion_int_zend_min);
+       }
+       return SUCCESS;
+}
 PHP_MINFO_FUNCTION(ion)
 {
        php_info_print_table_start();
@@ -1521,7 +1545,7 @@ zend_module_entry ion_module_entry = {
        "ion",                                  /* Extension name */
        ext_functions,                  /* zend_function_entry */
        PHP_MINIT(ion),                 /* PHP_MINIT - Module initialization */
-       NULL,                                   /* PHP_MSHUTDOWN - Module shutdown */
+       PHP_MSHUTDOWN(ion),             /* PHP_MSHUTDOWN - Module shutdown */
        PHP_RINIT(ion),                 /* PHP_RINIT - Request initialization */
        PHP_RSHUTDOWN(ion),             /* PHP_RSHUTDOWN - Request shutdown */
        PHP_MINFO(ion),                 /* PHP_MINFO - Module info */
index 8c0ec60eadf7852423294aa4d5f261f8a882ab2f..2a5112628a64faf26c4d8de233f9c4045b456406 100644 (file)
@@ -442,6 +442,27 @@ static inline void php_ion_decimal_to_int(ION_DECIMAL *dec, decContext *ctx, zen
        ion_int_free(ii);
 }
 
+static inline bool php_ion_decimal_fits_zend_long(php_ion_decimal *obj)
+{
+       int32_t result;
+
+       if (!ion_decimal_is_integer(&obj->dec)) {
+               return false;
+       }
+
+       result  = 1;
+       ion_decimal_compare(&obj->dec, &g_ion_dec_zend_max, &g_dec_ctx, &result);
+       if (result == 1) {
+               return false;
+       }
+       result = -1;
+       ion_decimal_compare(&obj->dec, &g_ion_dec_zend_min, &g_dec_ctx, &result);
+       if (result == -1) {
+               return false;
+       }
+       return true;
+}
+
 static inline void php_ion_decimal_ctor(php_ion_decimal *obj)
 {
        if (!obj->ctx) {
@@ -453,7 +474,7 @@ static inline void php_ion_decimal_ctor(php_ion_decimal *obj)
        }
        update_property_obj(&obj->std, ZEND_STRL("context"), obj->ctx);
 
-       if (ion_decimal_is_integer(&obj->dec)) {
+       if (php_ion_decimal_fits_zend_long(obj)) {
                zend_long l;
                php_ion_decimal_to_int(&obj->dec, &php_ion_obj(decimal_ctx, obj->ctx)->ctx, &l);
                zend_update_property_long(obj->std.ce, &obj->std, ZEND_STRL("number"), l);