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)) {