Commit 7e7607f9199 for php.net
commit 7e7607f919939e66e9b3ef526d0e58ea8c3aafdd
Merge: 02614a25992 3249f2db547
Author: Ilija Tovilo <ilija.tovilo@me.com>
Date: Sat Mar 28 19:13:40 2026 +0100
Merge branch 'PHP-8.5'
* PHP-8.5:
Fix GH-17399: iconv memory leak on bailout
diff --cc ext/iconv/iconv.c
index 13dc7074b9b,fd3a22deb10..ed7d332397d
--- a/ext/iconv/iconv.c
+++ b/ext/iconv/iconv.c
@@@ -1049,128 -1073,123 +1073,123 @@@ static php_iconv_err_t _php_iconv_mime_
err = PHP_ICONV_ERR_UNKNOWN;
goto out;
}
- } else {
- break;
- }
- if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
+ out_reserved += 4;
+ in_left = ini_in_left;
+ in_p = ini_in_p;
}
- out_reserved += 4;
- in_left = ini_in_left;
- in_p = ini_in_p;
- }
+ prev_in_left = in_left;
- prev_in_left = in_left;
+ encoded = php_base64_encode((unsigned char *) buf, (out_size - out_left));
- encoded = php_base64_encode((unsigned char *) buf, (out_size - out_left));
+ if (char_cnt < ZSTR_LEN(encoded)) {
+ /* something went wrong! */
+ err = PHP_ICONV_ERR_UNKNOWN;
+ goto out;
+ }
- if (char_cnt < ZSTR_LEN(encoded)) {
- /* something went wrong! */
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
- smart_str_appendl(pretval, ZSTR_VAL(encoded), ZSTR_LEN(encoded));
++ smart_str_append(pretval, encoded);
+ char_cnt -= ZSTR_LEN(encoded);
+ smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
+ char_cnt -= 2;
- smart_str_append(pretval, encoded);
- char_cnt -= ZSTR_LEN(encoded);
- smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
- char_cnt -= 2;
+ zend_string_release_ex(encoded, 0);
+ encoded = NULL;
+ } break; /* case PHP_ICONV_ENC_SCHEME_BASE64: */
- zend_string_release_ex(encoded, 0);
- encoded = NULL;
- } break; /* case PHP_ICONV_ENC_SCHEME_BASE64: */
+ case PHP_ICONV_ENC_SCHEME_QPRINT: {
+ size_t ini_in_left;
+ const char *ini_in_p;
+ const unsigned char *p;
+ size_t nbytes_required;
- case PHP_ICONV_ENC_SCHEME_QPRINT: {
- size_t ini_in_left;
- const char *ini_in_p;
- const unsigned char *p;
- size_t nbytes_required;
+ smart_str_appendc(pretval, 'Q');
+ char_cnt--;
+ smart_str_appendc(pretval, '?');
+ char_cnt--;
- smart_str_appendc(pretval, 'Q');
- char_cnt--;
- smart_str_appendc(pretval, '?');
- char_cnt--;
+ prev_in_left = ini_in_left = in_left;
+ ini_in_p = in_p;
- prev_in_left = ini_in_left = in_left;
- ini_in_p = in_p;
+ for (out_size = (char_cnt - 2); out_size > 0;) {
- for (out_size = (char_cnt - 2); out_size > 0;) {
+ nbytes_required = 0;
- nbytes_required = 0;
+ out_p = buf;
+ out_left = out_size;
- out_p = buf;
- out_left = out_size;
+ if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
+ switch (errno) {
+ case EINVAL:
+ err = PHP_ICONV_ERR_ILLEGAL_CHAR;
+ goto out;
- if (iconv(cd, (ICONV_CONST char **)&in_p, &in_left, (char **) &out_p, &out_left) == (size_t)-1) {
- switch (errno) {
- case EINVAL:
- err = PHP_ICONV_ERR_ILLEGAL_CHAR;
- goto out;
+ case EILSEQ:
+ err = PHP_ICONV_ERR_ILLEGAL_SEQ;
+ goto out;
- case EILSEQ:
- err = PHP_ICONV_ERR_ILLEGAL_SEQ;
- goto out;
+ case E2BIG:
+ if (prev_in_left == in_left) {
+ err = PHP_ICONV_ERR_UNKNOWN;
+ goto out;
+ }
+ break;
- case E2BIG:
- if (prev_in_left == in_left) {
+ default:
err = PHP_ICONV_ERR_UNKNOWN;
goto out;
- }
- break;
-
- default:
+ }
+ }
+ if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
+ if (errno != E2BIG) {
err = PHP_ICONV_ERR_UNKNOWN;
goto out;
+ }
}
- }
- if (iconv(cd, NULL, NULL, (char **) &out_p, &out_left) == (size_t)-1) {
- if (errno != E2BIG) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
+
+ for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
+ nbytes_required += qp_table[*p];
}
- }
- for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
- nbytes_required += qp_table[*p];
- }
+ if (nbytes_required <= char_cnt - 2) {
+ break;
+ }
- if (nbytes_required <= char_cnt - 2) {
- break;
+ out_size -= ((nbytes_required - (char_cnt - 2)) + 2) / 3;
+ in_left = ini_in_left;
+ in_p = ini_in_p;
}
- out_size -= ((nbytes_required - (char_cnt - 2)) + 2) / 3;
- in_left = ini_in_left;
- in_p = ini_in_p;
- }
-
- for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
- if (qp_table[*p] == 1) {
- smart_str_appendc(pretval, *(char *)p);
- char_cnt--;
- } else {
- static const char qp_digits[] = "0123456789ABCDEF";
- smart_str_appendc(pretval, '=');
- smart_str_appendc(pretval, qp_digits[(*p >> 4) & 0x0f]);
- smart_str_appendc(pretval, qp_digits[(*p & 0x0f)]);
- char_cnt -= 3;
+ for (p = (unsigned char *)buf; p < (unsigned char *)out_p; p++) {
+ if (qp_table[*p] == 1) {
+ smart_str_appendc(pretval, *(char *)p);
+ char_cnt--;
+ } else {
+ static const char qp_digits[] = "0123456789ABCDEF";
+ smart_str_appendc(pretval, '=');
+ smart_str_appendc(pretval, qp_digits[(*p >> 4) & 0x0f]);
+ smart_str_appendc(pretval, qp_digits[(*p & 0x0f)]);
+ char_cnt -= 3;
+ }
}
- }
- smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
- char_cnt -= 2;
+ smart_str_appendl(pretval, "?=", sizeof("?=") - 1);
+ char_cnt -= 2;
- if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
- err = PHP_ICONV_ERR_UNKNOWN;
- goto out;
- }
+ if (iconv(cd, NULL, NULL, NULL, NULL) == (size_t)-1) {
+ err = PHP_ICONV_ERR_UNKNOWN;
+ goto out;
+ }
- } break; /* case PHP_ICONV_ENC_SCHEME_QPRINT: */
- }
- } while (in_left > 0);
+ } break; /* case PHP_ICONV_ENC_SCHEME_QPRINT: */
+ }
+ } while (in_left > 0);
- smart_str_0(pretval);
+ smart_str_0(pretval);
+ } zend_catch {
+ bailout = true;
+ } zend_end_try();
out:
if (cd != (iconv_t)(-1)) {