diff --git a/ext/bcmath/bcmath.c b/ext/bcmath/bcmath.c index 8bb251dfb7d1c..0258c0cd3a534 100644 --- a/ext/bcmath/bcmath.c +++ b/ext/bcmath/bcmath.c @@ -29,6 +29,16 @@ #include "php_bcmath.h" #include "libbcmath/src/bcmath.h" +/* Always pair SETUP with TEARDOWN, and do so in the outer scope! + * Should not be used when data can escape the function. */ +#define BC_ARENA_SETUP \ + char bc_arena[BC_ARENA_SIZE]; \ + BCG(arena) = bc_arena; + +#define BC_ARENA_TEARDOWN \ + BCG(arena) = NULL; \ + BCG(arena_offset) = 0; + ZEND_DECLARE_MODULE_GLOBALS(bcmath) static PHP_GINIT_FUNCTION(bcmath); static PHP_GSHUTDOWN_FUNCTION(bcmath); @@ -89,6 +99,8 @@ static PHP_GINIT_FUNCTION(bcmath) ZEND_TSRMLS_CACHE_UPDATE(); #endif bcmath_globals->bc_precision = 0; + bcmath_globals->arena = NULL; + bcmath_globals->arena_offset = 0; bc_init_numbers(); } /* }}} */ @@ -99,6 +111,8 @@ static PHP_GSHUTDOWN_FUNCTION(bcmath) _bc_free_num_ex(&bcmath_globals->_zero_, 1); _bc_free_num_ex(&bcmath_globals->_one_, 1); _bc_free_num_ex(&bcmath_globals->_two_, 1); + bcmath_globals->arena = NULL; + bcmath_globals->arena_offset = 0; } /* }}} */ @@ -167,6 +181,8 @@ PHP_FUNCTION(bcadd) scale = (int) scale_param; } + BC_ARENA_SETUP; + if (php_str2num(&first, left) == FAILURE) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; @@ -185,6 +201,7 @@ PHP_FUNCTION(bcadd) bc_free_num(&first); bc_free_num(&second); bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -214,6 +231,8 @@ PHP_FUNCTION(bcsub) scale = (int) scale_param; } + BC_ARENA_SETUP; + if (php_str2num(&first, left) == FAILURE) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; @@ -232,6 +251,7 @@ PHP_FUNCTION(bcsub) bc_free_num(&first); bc_free_num(&second); bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -261,6 +281,8 @@ PHP_FUNCTION(bcmul) scale = (int) scale_param; } + BC_ARENA_SETUP; + if (php_str2num(&first, left) == FAILURE) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; @@ -279,6 +301,7 @@ PHP_FUNCTION(bcmul) bc_free_num(&first); bc_free_num(&second); bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -308,6 +331,8 @@ PHP_FUNCTION(bcdiv) scale = (int) scale_param; } + BC_ARENA_SETUP; + bc_init_num(&result); if (php_str2num(&first, left) == FAILURE) { @@ -331,6 +356,7 @@ PHP_FUNCTION(bcdiv) bc_free_num(&first); bc_free_num(&second); bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -360,6 +386,8 @@ PHP_FUNCTION(bcmod) scale = (int) scale_param; } + BC_ARENA_SETUP; + bc_init_num(&result); if (php_str2num(&first, left) == FAILURE) { @@ -383,6 +411,7 @@ PHP_FUNCTION(bcmod) bc_free_num(&first); bc_free_num(&second); bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -413,6 +442,8 @@ PHP_FUNCTION(bcpowmod) scale = (int) scale_param; } + BC_ARENA_SETUP; + bc_init_num(&result); if (php_str2num(&bc_base, base_str) == FAILURE) { @@ -458,6 +489,7 @@ PHP_FUNCTION(bcpowmod) bc_free_num(&bc_expo); bc_free_num(&bc_modulus); bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -487,6 +519,8 @@ PHP_FUNCTION(bcpow) scale = (int) scale_param; } + BC_ARENA_SETUP; + bc_init_num(&result); if (php_str2num(&first, base_str) == FAILURE) { @@ -518,6 +552,7 @@ PHP_FUNCTION(bcpow) bc_free_num(&first); bc_free_num(&bc_exponent); bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -546,6 +581,8 @@ PHP_FUNCTION(bcsqrt) scale = (int) scale_param; } + BC_ARENA_SETUP; + if (php_str2num(&result, left) == FAILURE) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; @@ -559,6 +596,7 @@ PHP_FUNCTION(bcsqrt) cleanup: { bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -588,6 +626,8 @@ PHP_FUNCTION(bccomp) scale = (int) scale_param; } + BC_ARENA_SETUP; + if (!bc_str2num(&first, ZSTR_VAL(left), ZSTR_VAL(left) + ZSTR_LEN(left), scale, false)) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; @@ -603,6 +643,7 @@ PHP_FUNCTION(bccomp) cleanup: { bc_free_num(&first); bc_free_num(&second); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -617,6 +658,8 @@ static void bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor) Z_PARAM_STR(numstr) ZEND_PARSE_PARAMETERS_END(); + BC_ARENA_SETUP; + if (php_str2num(&num, numstr) == FAILURE) { zend_argument_value_error(1, "is not well-formed"); goto cleanup; @@ -628,6 +671,7 @@ static void bcfloor_or_bcceil(INTERNAL_FUNCTION_PARAMETERS, bool is_floor) cleanup: { bc_free_num(&num); bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ @@ -676,6 +720,8 @@ PHP_FUNCTION(bcround) return; } + BC_ARENA_SETUP; + bc_init_num(&result); if (php_str2num(&num, numstr) == FAILURE) { @@ -689,6 +735,7 @@ PHP_FUNCTION(bcround) cleanup: { bc_free_num(&num); bc_free_num(&result); + BC_ARENA_TEARDOWN; }; } /* }}} */ diff --git a/ext/bcmath/libbcmath/src/init.c b/ext/bcmath/libbcmath/src/init.c index 2c109f3fb92fb..18efc1c39a2b2 100644 --- a/ext/bcmath/libbcmath/src/init.c +++ b/ext/bcmath/libbcmath/src/init.c @@ -35,14 +35,25 @@ #include #include "zend_alloc.h" -static zend_always_inline bc_num _bc_new_num_nonzeroed_ex_internal(size_t length, size_t scale, bool persistent) +static bc_num _bc_new_num_nonzeroed_ex_internal(size_t length, size_t scale, bool persistent) { - /* PHP Change: malloc() -> pemalloc(), removed free_list code, merged n_ptr and n_value */ - bc_num temp = safe_pemalloc(1, sizeof(bc_struct) + length, scale, persistent); + size_t required_size = zend_safe_address_guarded(1, sizeof(bc_struct) + (ZEND_MM_ALIGNMENT - 1) + length, scale); + required_size &= -ZEND_MM_ALIGNMENT; + bc_num temp; + + if (!persistent && BCG(arena) && required_size <= BC_ARENA_SIZE - BCG(arena_offset)) { + temp = (bc_num) (BCG(arena) + BCG(arena_offset)); + BCG(arena_offset) += required_size; + temp->n_refs = 2; /* prevent freeing */ + } else { + /* PHP Change: malloc() -> pemalloc(), removed free_list code, merged n_ptr and n_value */ + temp = pemalloc(required_size, persistent); + temp->n_refs = 1; + } + temp->n_sign = PLUS; temp->n_len = length; temp->n_scale = scale; - temp->n_refs = 1; temp->n_value = (char *) temp + sizeof(bc_struct); return temp; } diff --git a/ext/bcmath/php_bcmath.h b/ext/bcmath/php_bcmath.h index af8745cdba74f..77ebcbdb39fa6 100644 --- a/ext/bcmath/php_bcmath.h +++ b/ext/bcmath/php_bcmath.h @@ -27,11 +27,15 @@ extern zend_module_entry bcmath_module_entry; #include "php_version.h" #define PHP_BCMATH_VERSION PHP_VERSION +#define BC_ARENA_SIZE 256 + ZEND_BEGIN_MODULE_GLOBALS(bcmath) bc_num _zero_; bc_num _one_; bc_num _two_; int bc_precision; + char *arena; + size_t arena_offset; ZEND_END_MODULE_GLOBALS(bcmath) #if defined(ZTS) && defined(COMPILE_DL_BCMATH)