From 04cbec18d85e509dbb42d7908cc52ab2e2b5d9cf Mon Sep 17 00:00:00 2001 From: VijhnAustin Date: Thu, 22 Oct 2026 10:20:43 -0500 Subject: [PATCH] Fix GH-24492 (partial): route caller-sized string builders through the fallible allocator Several ext/standard functions grow their output buffer with the non-fallible string allocators. When the requested size crosses the soft memory_limit the allocation is not reported back to the caller; it escalates to the hard limit (memory_hard_limit_percent) and the process is terminated via _exit(137), so registered shutdown functions never run and the catchable "Allowed memory size exhausted" fatal that 8.5.11 produced for the same input is lost. Route these sites through the fallible allocation API already in the tree (zend_string_fextend / zend_string_falloc / zend_string_safe_falloc with fallible=true), propagate the NULL return, and surface the standard engine OOM via RETURN_OOM() at the userland boundary: - sprintf/printf/vprintf/vsprintf/fprintf/vfprintf (formatted_print.c; the php_sprintf_append* helpers now return bool) - pack (pack.c) - bin2hex and utf8_encode (string.c) - number_format (math.c; tmpbuf released on the failure path) - convert_uuencode (uuencode.c) - quoted_printable_encode (quot_print.c) Adds 17 .phpt regression tests, each pinning memory_hard_limit_percent=200 and asserting both the catchable fatal and that a shutdown function still runs. Other sites named in the issue (base64_encode, urlencode/rawurlencode, var_export, the bcmath family, and the main/spprintf.c PAD_CHAR path) require auditing their internal callers for NULL-safety before conversion and are intentionally left for follow-up. Co-Authored-By: Claude Opus 4.8 --- ext/standard/formatted_print.c | 155 +++++++++++++----- ext/standard/math.c | 37 ++++- ext/standard/pack.c | 18 +- ext/standard/quot_print.c | 8 +- ext/standard/string.c | 19 ++- .../tests/math/gh24492_number_format.phpt | 13 ++ .../tests/strings/gh24492_bin2hex.phpt | 14 ++ .../strings/gh24492_convert_uuencode.phpt | 13 ++ .../tests/strings/gh24492_fprintf.phpt | 13 ++ ext/standard/tests/strings/gh24492_pack.phpt | 13 ++ .../tests/strings/gh24492_pack_absolute.phpt | 13 ++ .../tests/strings/gh24492_pack_format.phpt | 14 ++ .../tests/strings/gh24492_printf.phpt | 13 ++ .../gh24492_quoted_printable_encode.phpt | 13 ++ .../tests/strings/gh24492_sprintf.phpt | 13 ++ .../strings/gh24492_sprintf_dynamic.phpt | 13 ++ .../tests/strings/gh24492_sprintf_float.phpt | 13 ++ .../strings/gh24492_sprintf_integer.phpt | 13 ++ .../tests/strings/gh24492_utf8_encode.phpt | 13 ++ .../tests/strings/gh24492_vfprintf.phpt | 13 ++ .../tests/strings/gh24492_vprintf.phpt | 13 ++ .../tests/strings/gh24492_vsprintf.phpt | 13 ++ ext/standard/uuencode.c | 11 +- 23 files changed, 415 insertions(+), 56 deletions(-) create mode 100644 ext/standard/tests/math/gh24492_number_format.phpt create mode 100644 ext/standard/tests/strings/gh24492_bin2hex.phpt create mode 100644 ext/standard/tests/strings/gh24492_convert_uuencode.phpt create mode 100644 ext/standard/tests/strings/gh24492_fprintf.phpt create mode 100644 ext/standard/tests/strings/gh24492_pack.phpt create mode 100644 ext/standard/tests/strings/gh24492_pack_absolute.phpt create mode 100644 ext/standard/tests/strings/gh24492_pack_format.phpt create mode 100644 ext/standard/tests/strings/gh24492_printf.phpt create mode 100644 ext/standard/tests/strings/gh24492_quoted_printable_encode.phpt create mode 100644 ext/standard/tests/strings/gh24492_sprintf.phpt create mode 100644 ext/standard/tests/strings/gh24492_sprintf_dynamic.phpt create mode 100644 ext/standard/tests/strings/gh24492_sprintf_float.phpt create mode 100644 ext/standard/tests/strings/gh24492_sprintf_integer.phpt create mode 100644 ext/standard/tests/strings/gh24492_utf8_encode.phpt create mode 100644 ext/standard/tests/strings/gh24492_vfprintf.phpt create mode 100644 ext/standard/tests/strings/gh24492_vprintf.phpt create mode 100644 ext/standard/tests/strings/gh24492_vsprintf.phpt diff --git a/ext/standard/formatted_print.c b/ext/standard/formatted_print.c index e8ec4271b289..5c1d02b6f220 100644 --- a/ext/standard/formatted_print.c +++ b/ext/standard/formatted_print.c @@ -45,20 +45,25 @@ static const char hexchars[] = "0123456789abcdef"; static const char HEXCHARS[] = "0123456789ABCDEF"; /* php_spintf_appendchar() {{{ */ -inline static void +inline static bool php_sprintf_appendchar(zend_string **buffer, size_t *pos, char add) { if ((*pos + 1) >= ZSTR_LEN(*buffer)) { PRINTF_DEBUG(("%s(): ereallocing buffer to %zu bytes\n", get_active_function_name(), ZSTR_LEN(*buffer))); - *buffer = zend_string_extend(*buffer, ZSTR_LEN(*buffer) << 1, 0); + zend_string *new_buffer = zend_string_fextend(*buffer, ZSTR_LEN(*buffer) << 1, 0, true); + if (UNEXPECTED(new_buffer == NULL)) { + return false; + } + *buffer = new_buffer; } PRINTF_DEBUG(("sprintf: appending '%c', pos=%zu\n", add, *pos)); ZSTR_VAL(*buffer)[(*pos)++] = add; + return true; } /* }}} */ /* php_spintf_appendchar() {{{ */ -inline static void +inline static bool php_sprintf_appendchars(zend_string **buffer, size_t *pos, char *add, size_t len) { if ((*pos + len) >= ZSTR_LEN(*buffer)) { @@ -68,16 +73,21 @@ php_sprintf_appendchars(zend_string **buffer, size_t *pos, char *add, size_t len do { nlen = nlen << 1; } while ((*pos + len) >= nlen); - *buffer = zend_string_extend(*buffer, nlen, 0); + zend_string *new_buffer = zend_string_fextend(*buffer, nlen, 0, true); + if (UNEXPECTED(new_buffer == NULL)) { + return false; + } + *buffer = new_buffer; } PRINTF_DEBUG(("sprintf: appending \"%s\", pos=%zu\n", add, *pos)); memcpy(ZSTR_VAL(*buffer) + (*pos), add, len); *pos += len; + return true; } /* }}} */ /* php_spintf_appendstring() {{{ */ -inline static void +inline static bool php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add, size_t min_width, size_t max_width, char padding, size_t alignment, size_t len, bool neg, int expprec, int always_sign) @@ -109,7 +119,11 @@ php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add, size <<= 1; } PRINTF_DEBUG(("sprintf ereallocing buffer to %zu bytes\n", size)); - *buffer = zend_string_extend(*buffer, size, 0); + zend_string *new_buffer = zend_string_fextend(*buffer, size, 0, true); + if (UNEXPECTED(new_buffer == NULL)) { + return false; + } + *buffer = new_buffer; } if (alignment == ALIGN_RIGHT) { if ((neg || always_sign) && padding=='0') { @@ -130,11 +144,12 @@ php_sprintf_appendstring(zend_string **buffer, size_t *pos, char *add, ZSTR_VAL(*buffer)[(*pos)++] = padding; } } + return true; } /* }}} */ /* php_spintf_appendint() {{{ */ -inline static void +inline static bool php_sprintf_appendint(zend_string **buffer, size_t *pos, zend_long number, size_t width, char padding, size_t alignment, int always_sign) @@ -171,14 +186,14 @@ php_sprintf_appendint(zend_string **buffer, size_t *pos, zend_long number, } PRINTF_DEBUG(("sprintf: appending " ZEND_LONG_FMT " as \"%s\", i=%u\n", number, &numbuf[i], i)); - php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0, + return php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0, padding, alignment, (NUM_BUF_SIZE - 1) - i, neg, 0, always_sign); } /* }}} */ /* php_spintf_appenduint() {{{ */ -inline static void +inline static bool php_sprintf_appenduint(zend_string **buffer, size_t *pos, zend_ulong number, size_t width, char padding, size_t alignment) @@ -204,13 +219,13 @@ php_sprintf_appenduint(zend_string **buffer, size_t *pos, } while (magn > 0 && i > 0); PRINTF_DEBUG(("sprintf: appending " ZEND_LONG_FMT " as \"%s\", i=%d\n", number, &numbuf[i], i)); - php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0, + return php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0, padding, alignment, (NUM_BUF_SIZE - 1) - i, /* neg */ false, 0, 0); } /* }}} */ /* php_spintf_appenddouble() {{{ */ -inline static void +inline static bool php_sprintf_appenddouble(zend_string **buffer, size_t *pos, double number, size_t width, char padding, @@ -240,17 +255,15 @@ php_sprintf_appenddouble(zend_string **buffer, size_t *pos, if (zend_isnan(number)) { is_negative = (number<0); - php_sprintf_appendstring(buffer, pos, "NaN", 3, 0, padding, + return php_sprintf_appendstring(buffer, pos, "NaN", 3, 0, padding, alignment, 3, is_negative, 0, always_sign); - return; } if (zend_isinf(number)) { is_negative = (number<0); char *str = is_negative ? "-INF" : "INF"; - php_sprintf_appendstring(buffer, pos, str, strlen(str), 0, padding, + return php_sprintf_appendstring(buffer, pos, str, strlen(str), 0, padding, alignment, strlen(str), is_negative, 0, always_sign); - return; } switch (fmt) { @@ -312,13 +325,13 @@ php_sprintf_appenddouble(zend_string **buffer, size_t *pos, } } - php_sprintf_appendstring(buffer, pos, s, width, 0, padding, + return php_sprintf_appendstring(buffer, pos, s, width, 0, padding, alignment, s_len, is_negative, 0, always_sign); } /* }}} */ /* php_spintf_appendd2n() {{{ */ -inline static void +inline static bool php_sprintf_append2n(zend_string **buffer, size_t *pos, zend_long number, size_t width, char padding, size_t alignment, int n, const char *chartable, int expprec) @@ -342,7 +355,7 @@ php_sprintf_append2n(zend_string **buffer, size_t *pos, zend_long number, } while (num > 0); - php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0, + return php_sprintf_appendstring(buffer, pos, &numbuf[i], width, 0, padding, alignment, (NUM_BUF_SIZE - 1) - i, /* neg */ false, expprec, 0); } @@ -433,7 +446,10 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n const char *format_orig = format; ZEND_IGNORE_VALUE(format_orig); - result = zend_string_alloc(size, 0); + result = zend_string_falloc(size, 0, true); + if (UNEXPECTED(result == NULL)) { + return NULL; + } currarg = 0; argnum = 0; @@ -444,10 +460,14 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n temppos = memchr(format, '%', format_len); if (!temppos) { - php_sprintf_appendchars(&result, &outpos, format, format_len); + if (UNEXPECTED(!php_sprintf_appendchars(&result, &outpos, format, format_len))) { + goto fail; + } break; } else if (temppos != format) { - php_sprintf_appendchars(&result, &outpos, format, temppos - format); + if (UNEXPECTED(!php_sprintf_appendchars(&result, &outpos, format, temppos - format))) { + goto fail; + } format_len -= temppos - format; format = temppos; } @@ -455,7 +475,9 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n format_len--; if (*format == '%') { - php_sprintf_appendchar(&result, &outpos, '%'); + if (UNEXPECTED(!php_sprintf_appendchar(&result, &outpos, '%'))) { + goto fail; + } format++; format_len--; } else { @@ -625,27 +647,34 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n case 's': { zend_string *t; zend_string *str = zval_get_tmp_string(tmp, &t); - php_sprintf_appendstring(&result, &outpos, + bool success = php_sprintf_appendstring(&result, &outpos, ZSTR_VAL(str), width, precision, padding, alignment, ZSTR_LEN(str), /* neg */ false, expprec, 0); zend_tmp_string_release(t); + if (UNEXPECTED(!success)) { + goto fail; + } break; } case 'd': - php_sprintf_appendint(&result, &outpos, + if (UNEXPECTED(!php_sprintf_appendint(&result, &outpos, zval_get_long(tmp), width, padding, alignment, - always_sign); + always_sign))) { + goto fail; + } break; case 'u': - php_sprintf_appenduint(&result, &outpos, + if (UNEXPECTED(!php_sprintf_appenduint(&result, &outpos, zval_get_long(tmp), - width, padding, alignment); + width, padding, alignment))) { + goto fail; + } break; case 'e': @@ -656,49 +685,63 @@ php_formatted_print(char *format, size_t format_len, zval *args, int argc, int n case 'G': case 'h': case 'H': - php_sprintf_appenddouble(&result, &outpos, + if (UNEXPECTED(!php_sprintf_appenddouble(&result, &outpos, zval_get_double(tmp), width, padding, alignment, precision, adjusting, *format, always_sign - ); + ))) { + goto fail; + } break; case 'c': - php_sprintf_appendchar(&result, &outpos, - (char) zval_get_long(tmp)); + if (UNEXPECTED(!php_sprintf_appendchar(&result, &outpos, + (char) zval_get_long(tmp)))) { + goto fail; + } break; case 'o': - php_sprintf_append2n(&result, &outpos, + if (UNEXPECTED(!php_sprintf_append2n(&result, &outpos, zval_get_long(tmp), width, padding, alignment, 3, - hexchars, expprec); + hexchars, expprec))) { + goto fail; + } break; case 'x': - php_sprintf_append2n(&result, &outpos, + if (UNEXPECTED(!php_sprintf_append2n(&result, &outpos, zval_get_long(tmp), width, padding, alignment, 4, - hexchars, expprec); + hexchars, expprec))) { + goto fail; + } break; case 'X': - php_sprintf_append2n(&result, &outpos, + if (UNEXPECTED(!php_sprintf_append2n(&result, &outpos, zval_get_long(tmp), width, padding, alignment, 4, - HEXCHARS, expprec); + HEXCHARS, expprec))) { + goto fail; + } break; case 'b': - php_sprintf_append2n(&result, &outpos, + if (UNEXPECTED(!php_sprintf_append2n(&result, &outpos, zval_get_long(tmp), width, padding, alignment, 1, - hexchars, expprec); + hexchars, expprec))) { + goto fail; + } break; case '%': - php_sprintf_appendchar(&result, &outpos, '%'); + if (UNEXPECTED(!php_sprintf_appendchar(&result, &outpos, '%'))) { + goto fail; + } break; @@ -745,7 +788,10 @@ static zval *php_formatted_print_get_array(zend_array *array, int *argc) int n; n = zend_hash_num_elements(array); - args = (zval *)safe_emalloc(n, sizeof(zval), 0); + args = (zval *)safe_femalloc(n, sizeof(zval), 0, true); + if (UNEXPECTED(args == NULL)) { + return NULL; + } n = 0; ZEND_HASH_FOREACH_VAL(array, zv) { ZVAL_COPY_VALUE(&args[n], zv); @@ -773,6 +819,9 @@ PHP_FUNCTION(sprintf) result = php_formatted_print(format, format_len, args, argc, 1); if (result == NULL) { + if (ZEND_HAS_OOM()) { + RETURN_OOM(); + } RETURN_THROWS(); } RETVAL_STR(result); @@ -795,10 +844,16 @@ PHP_FUNCTION(vsprintf) ZEND_PARSE_PARAMETERS_END(); args = php_formatted_print_get_array(array, &argc); + if (UNEXPECTED(args == NULL)) { + RETURN_OOM(); + } result = php_formatted_print(format, format_len, args, argc, -1); efree(args); if (result == NULL) { + if (ZEND_HAS_OOM()) { + RETURN_OOM(); + } RETURN_THROWS(); } RETVAL_STR(result); @@ -822,6 +877,9 @@ PHP_FUNCTION(printf) result = php_formatted_print(format, format_len, args, argc, 1); if (result == NULL) { + if (ZEND_HAS_OOM()) { + RETURN_OOM(); + } RETURN_THROWS(); } rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result)); @@ -847,10 +905,16 @@ PHP_FUNCTION(vprintf) ZEND_PARSE_PARAMETERS_END(); args = php_formatted_print_get_array(array, &argc); + if (UNEXPECTED(args == NULL)) { + RETURN_OOM(); + } result = php_formatted_print(format, format_len, args, argc, -1); efree(args); if (result == NULL) { + if (ZEND_HAS_OOM()) { + RETURN_OOM(); + } RETURN_THROWS(); } rlen = PHPWRITE(ZSTR_VAL(result), ZSTR_LEN(result)); @@ -877,6 +941,9 @@ PHP_FUNCTION(fprintf) result = php_formatted_print(format, format_len, args, argc, 2); if (result == NULL) { + if (ZEND_HAS_OOM()) { + RETURN_OOM(); + } RETURN_THROWS(); } @@ -905,10 +972,16 @@ PHP_FUNCTION(vfprintf) ZEND_PARSE_PARAMETERS_END(); args = php_formatted_print_get_array(array, &argc); + if (UNEXPECTED(args == NULL)) { + RETURN_OOM(); + } result = php_formatted_print(format, format_len, args, argc, -1); efree(args); if (result == NULL) { + if (ZEND_HAS_OOM()) { + RETURN_OOM(); + } RETURN_THROWS(); } diff --git a/ext/standard/math.c b/ext/standard/math.c index 09d982981043..b392e9f3a92f 100644 --- a/ext/standard/math.c +++ b/ext/standard/math.c @@ -1170,7 +1170,11 @@ PHPAPI zend_string *_php_math_number_format_ex(double d, int dec, const char *de if (is_negative) { reslen++; } - res = zend_string_alloc(reslen, 0); + res = zend_string_falloc(reslen, 0, true); + if (UNEXPECTED(res == NULL)) { + zend_string_release_ex(tmpbuf, 0); + return NULL; + } s = ZSTR_VAL(tmpbuf) + ZSTR_LEN(tmpbuf) - 1; t = ZSTR_VAL(res) + reslen; @@ -1300,7 +1304,11 @@ PHPAPI zend_string *_php_math_number_format_long(zend_long num, zend_long dec, c } } - res = zend_string_alloc(reslen, 0); + res = zend_string_falloc(reslen, 0, true); + if (UNEXPECTED(res == NULL)) { + zend_string_release_ex(tmpbuf, 0); + return NULL; + } s = ZSTR_VAL(tmpbuf) + ZSTR_LEN(tmpbuf) - 1; t = ZSTR_VAL(res) + reslen; @@ -1368,9 +1376,14 @@ PHP_FUNCTION(number_format) } switch (Z_TYPE_P(num)) { - case IS_LONG: - RETURN_STR(_php_math_number_format_long(Z_LVAL_P(num), dec, dec_point, dec_point_len, thousand_sep, thousand_sep_len)); + case IS_LONG: { + zend_string *formatted = _php_math_number_format_long(Z_LVAL_P(num), dec, dec_point, dec_point_len, thousand_sep, thousand_sep_len); + if (UNEXPECTED(formatted == NULL)) { + RETURN_OOM(); + } + RETURN_STR(formatted); break; + } case IS_DOUBLE: // double values of >= 2^52 can not have fractional digits anymore @@ -1379,7 +1392,13 @@ PHP_FUNCTION(number_format) (Z_DVAL_P(num) >= 4503599627370496.0 || Z_DVAL_P(num) <= -4503599627370496.0) && ZEND_DOUBLE_FITS_LONG(Z_DVAL_P(num)) )) { - RETURN_STR(_php_math_number_format_long((zend_long)Z_DVAL_P(num), dec, dec_point, dec_point_len, thousand_sep, thousand_sep_len)); + { + zend_string *formatted = _php_math_number_format_long((zend_long)Z_DVAL_P(num), dec, dec_point, dec_point_len, thousand_sep, thousand_sep_len); + if (UNEXPECTED(formatted == NULL)) { + RETURN_OOM(); + } + RETURN_STR(formatted); + } break; } @@ -1388,7 +1407,13 @@ PHP_FUNCTION(number_format) } else { dec_int = ZEND_LONG_INT_UDFL(dec) ? INT_MIN : (int)dec; } - RETURN_STR(_php_math_number_format_ex(Z_DVAL_P(num), dec_int, dec_point, dec_point_len, thousand_sep, thousand_sep_len)); + { + zend_string *formatted = _php_math_number_format_ex(Z_DVAL_P(num), dec_int, dec_point, dec_point_len, thousand_sep, thousand_sep_len); + if (UNEXPECTED(formatted == NULL)) { + RETURN_OOM(); + } + RETURN_STR(formatted); + } break; EMPTY_SWITCH_DEFAULT_CASE() diff --git a/ext/standard/pack.c b/ext/standard/pack.c index 91cd8ff775e6..ffbfb330be24 100644 --- a/ext/standard/pack.c +++ b/ext/standard/pack.c @@ -218,8 +218,15 @@ PHP_FUNCTION(pack) ZEND_PARSE_PARAMETERS_END(); /* We have a maximum of format codes to deal with */ - formatcodes = safe_emalloc(formatlen, sizeof(*formatcodes), 0); - formatargs = safe_emalloc(formatlen, sizeof(*formatargs), 0); + formatcodes = safe_femalloc(formatlen, sizeof(*formatcodes), 0, true); + if (UNEXPECTED(formatcodes == NULL)) { + RETURN_OOM(); + } + formatargs = safe_femalloc(formatlen, sizeof(*formatargs), 0, true); + if (UNEXPECTED(formatargs == NULL)) { + efree(formatcodes); + RETURN_OOM(); + } currentarg = 0; /* Preprocess format into formatcodes and formatargs */ @@ -428,7 +435,12 @@ PHP_FUNCTION(pack) } } - output = zend_string_alloc(outputsize, 0); + output = zend_string_falloc(outputsize, 0, true); + if (UNEXPECTED(output == NULL)) { + efree(formatcodes); + efree(formatargs); + RETURN_OOM(); + } outputpos = 0; currentarg = 0; diff --git a/ext/standard/quot_print.c b/ext/standard/quot_print.c index 75606c44a980..861e3309e379 100644 --- a/ext/standard/quot_print.c +++ b/ext/standard/quot_print.c @@ -144,7 +144,10 @@ PHPAPI zend_string *php_quot_print_encode(const unsigned char *str, size_t lengt const char *hex = "0123456789ABCDEF"; zend_string *ret; - ret = zend_string_safe_alloc(3, (length + (((3 * length)/(PHP_QPRINT_MAXL-9)) + 1)), 0, 0); + ret = zend_string_safe_falloc(3, (length + (((3 * length)/(PHP_QPRINT_MAXL-9)) + 1)), 0, 0, true); + if (UNEXPECTED(ret == NULL)) { + return NULL; + } d = (unsigned char*)ZSTR_VAL(ret); while (length--) { @@ -267,6 +270,9 @@ PHP_FUNCTION(quoted_printable_encode) } new_str = php_quot_print_encode((unsigned char *)ZSTR_VAL(str), ZSTR_LEN(str)); + if (UNEXPECTED(new_str == NULL)) { + RETURN_OOM(); + } RETURN_STR(new_str); } /* }}} */ diff --git a/ext/standard/string.c b/ext/standard/string.c index e6302ed7097a..26971e1d804c 100644 --- a/ext/standard/string.c +++ b/ext/standard/string.c @@ -65,7 +65,10 @@ static zend_string *php_bin2hex(const unsigned char *old, const size_t oldlen) zend_string *result; size_t i, j; - result = zend_string_safe_alloc(oldlen, 2 * sizeof(char), 0, 0); + result = zend_string_safe_falloc(oldlen, 2 * sizeof(char), 0, 0, true); + if (UNEXPECTED(result == NULL)) { + return NULL; + } for (i = j = 0; i < oldlen; i++) { ZSTR_VAL(result)[j++] = hexconvtab[old[i] >> 4]; @@ -165,6 +168,9 @@ PHP_FUNCTION(bin2hex) ZEND_PARSE_PARAMETERS_END(); result = php_bin2hex((unsigned char *)ZSTR_VAL(data), ZSTR_LEN(data)); + if (UNEXPECTED(result == NULL)) { + RETURN_OOM(); + } RETURN_STR(result); } @@ -6390,7 +6396,10 @@ static zend_string *php_utf8_encode(const char *s, size_t len) zend_string *str; unsigned char c; - str = zend_string_safe_alloc(len, 2, 0, 0); + str = zend_string_safe_falloc(len, 2, 0, 0, true); + if (UNEXPECTED(str == NULL)) { + return NULL; + } ZSTR_LEN(str) = 0; while (pos > 0) { /* The lower 256 codepoints of Unicode are identical to Latin-1, @@ -6454,7 +6463,11 @@ PHP_FUNCTION(utf8_encode) Z_PARAM_STRING(arg, arg_len) ZEND_PARSE_PARAMETERS_END(); - RETURN_STR(php_utf8_encode(arg, arg_len)); + zend_string *result = php_utf8_encode(arg, arg_len); + if (UNEXPECTED(result == NULL)) { + RETURN_OOM(); + } + RETURN_STR(result); } /* }}} */ diff --git a/ext/standard/tests/math/gh24492_number_format.phpt b/ext/standard/tests/math/gh24492_number_format.phpt new file mode 100644 index 000000000000..4a31bf288894 --- /dev/null +++ b/ext/standard/tests/math/gh24492_number_format.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: number_format allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_bin2hex.phpt b/ext/standard/tests/strings/gh24492_bin2hex.phpt new file mode 100644 index 000000000000..65799063f9db --- /dev/null +++ b/ext/standard/tests/strings/gh24492_bin2hex.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-24492: bin2hex allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 4 +shutdown diff --git a/ext/standard/tests/strings/gh24492_convert_uuencode.phpt b/ext/standard/tests/strings/gh24492_convert_uuencode.phpt new file mode 100644 index 000000000000..59f40146ca3f --- /dev/null +++ b/ext/standard/tests/strings/gh24492_convert_uuencode.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: convert_uuencode allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_fprintf.phpt b/ext/standard/tests/strings/gh24492_fprintf.phpt new file mode 100644 index 000000000000..5e156989f24a --- /dev/null +++ b/ext/standard/tests/strings/gh24492_fprintf.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: fprintf allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_pack.phpt b/ext/standard/tests/strings/gh24492_pack.phpt new file mode 100644 index 000000000000..0318e7ac521e --- /dev/null +++ b/ext/standard/tests/strings/gh24492_pack.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: pack allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_pack_absolute.phpt b/ext/standard/tests/strings/gh24492_pack_absolute.phpt new file mode 100644 index 000000000000..c8b4947d1910 --- /dev/null +++ b/ext/standard/tests/strings/gh24492_pack_absolute.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: pack_absolute allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_pack_format.phpt b/ext/standard/tests/strings/gh24492_pack_format.phpt new file mode 100644 index 000000000000..dc1ca92f38ac --- /dev/null +++ b/ext/standard/tests/strings/gh24492_pack_format.phpt @@ -0,0 +1,14 @@ +--TEST-- +GH-24492: pack_format allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 4 +shutdown diff --git a/ext/standard/tests/strings/gh24492_printf.phpt b/ext/standard/tests/strings/gh24492_printf.phpt new file mode 100644 index 000000000000..b4e0842169ab --- /dev/null +++ b/ext/standard/tests/strings/gh24492_printf.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: printf allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_quoted_printable_encode.phpt b/ext/standard/tests/strings/gh24492_quoted_printable_encode.phpt new file mode 100644 index 000000000000..8952a5cf4028 --- /dev/null +++ b/ext/standard/tests/strings/gh24492_quoted_printable_encode.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: quoted_printable_encode allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_sprintf.phpt b/ext/standard/tests/strings/gh24492_sprintf.phpt new file mode 100644 index 000000000000..35ce124e9184 --- /dev/null +++ b/ext/standard/tests/strings/gh24492_sprintf.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: sprintf allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_sprintf_dynamic.phpt b/ext/standard/tests/strings/gh24492_sprintf_dynamic.phpt new file mode 100644 index 000000000000..4895de923b53 --- /dev/null +++ b/ext/standard/tests/strings/gh24492_sprintf_dynamic.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: sprintf_dynamic allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_sprintf_float.phpt b/ext/standard/tests/strings/gh24492_sprintf_float.phpt new file mode 100644 index 000000000000..96ab0e7533af --- /dev/null +++ b/ext/standard/tests/strings/gh24492_sprintf_float.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: sprintf_float allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_sprintf_integer.phpt b/ext/standard/tests/strings/gh24492_sprintf_integer.phpt new file mode 100644 index 000000000000..75cdf4c8156a --- /dev/null +++ b/ext/standard/tests/strings/gh24492_sprintf_integer.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: sprintf_integer allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_utf8_encode.phpt b/ext/standard/tests/strings/gh24492_utf8_encode.phpt new file mode 100644 index 000000000000..25d71a761aa3 --- /dev/null +++ b/ext/standard/tests/strings/gh24492_utf8_encode.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: utf8_encode allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_vfprintf.phpt b/ext/standard/tests/strings/gh24492_vfprintf.phpt new file mode 100644 index 000000000000..a5402661af27 --- /dev/null +++ b/ext/standard/tests/strings/gh24492_vfprintf.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: vfprintf allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_vprintf.phpt b/ext/standard/tests/strings/gh24492_vprintf.phpt new file mode 100644 index 000000000000..c28cec3e9b42 --- /dev/null +++ b/ext/standard/tests/strings/gh24492_vprintf.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: vprintf allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/tests/strings/gh24492_vsprintf.phpt b/ext/standard/tests/strings/gh24492_vsprintf.phpt new file mode 100644 index 000000000000..84efa8d7ca7f --- /dev/null +++ b/ext/standard/tests/strings/gh24492_vsprintf.phpt @@ -0,0 +1,13 @@ +--TEST-- +GH-24492: vsprintf allocation failure must not reach the hard memory limit +--INI-- +memory_limit=16M +memory_hard_limit_percent=200 +--FILE-- + +--EXPECTF-- +Fatal error: Allowed memory size of 16777216 bytes exhausted %S(tried to allocate %d bytes) in %s on line 3 +shutdown diff --git a/ext/standard/uuencode.c b/ext/standard/uuencode.c index 0389fdd9f979..f8ca49909343 100644 --- a/ext/standard/uuencode.c +++ b/ext/standard/uuencode.c @@ -71,7 +71,10 @@ PHPAPI zend_string *php_uuencode(const char *src, size_t src_len) /* {{{ */ /* encoded length is ~ 38% greater than the original Use 1.5 for easier calculation. */ - dest = zend_string_safe_alloc(src_len/2, 3, 46, 0); + dest = zend_string_safe_falloc(src_len/2, 3, 46, 0, true); + if (UNEXPECTED(dest == NULL)) { + return NULL; + } p = (unsigned char *) ZSTR_VAL(dest); s = (unsigned char *) src; e = s + src_len; @@ -209,7 +212,11 @@ PHP_FUNCTION(convert_uuencode) Z_PARAM_STR(src) ZEND_PARSE_PARAMETERS_END(); - RETURN_STR(php_uuencode(ZSTR_VAL(src), ZSTR_LEN(src))); + zend_string *dest = php_uuencode(ZSTR_VAL(src), ZSTR_LEN(src)); + if (UNEXPECTED(dest == NULL)) { + RETURN_OOM(); + } + RETURN_STR(dest); } /* }}} */