Commit 765fe90b594 for php.net

commit 765fe90b594b2b9fcbf55957b81a6565480c2e25
Merge: 6493ea617aa 1feb20156bb
Author: Ilia Alshanetsky <ilia@ilia.ws>
Date:   Sun Jul 12 21:07:01 2026 -0400

    Merge branch 'PHP-8.4' into PHP-8.5

    * PHP-8.4:
      Fix use-after-free on re-entrant ftp_close() during a transfer

diff --cc ext/ftp/ftp.c
index 5fcd41536ec,1345e378d8e..88f7431cc32
--- a/ext/ftp/ftp.c
+++ b/ext/ftp/ftp.c
@@@ -817,8 -890,13 +817,13 @@@ bool ftp_get(ftpbuf_t *ftp, php_stream
  	char			arg[MAX_LENGTH_OF_LONG];

  	if (ftp == NULL) {
 -		return 0;
 +		return false;
  	}
+ 	if (ftp->in_use) {
+ 		php_error_docref(NULL, E_WARNING, "FTP\\Connection is already in use");
 -		return 0;
++		return false;
+ 	}
+ 	ftp->in_use = true;
  	if (!ftp_type(ftp, type)) {
  		goto bail;
  	}
@@@ -894,11 -972,14 +899,13 @@@
  		goto bail;
  	}

+ 	ftp->in_use = false;
 -	return 1;
 +	return true;
  bail:
  	data_close(ftp);
+ 	ftp->in_use = false;
 -	return 0;
 +	return false;
  }
 -/* }}} */

  static zend_result ftp_send_stream_to_data_socket(ftpbuf_t *ftp, databuf_t *data, php_stream *instream, ftptype_t type, bool send_once_and_return)
  {
@@@ -979,8 -1062,13 +986,13 @@@ bool ftp_put(ftpbuf_t *ftp, const char
  	char			arg[MAX_LENGTH_OF_LONG];

  	if (ftp == NULL) {
 -		return 0;
 +		return false;
  	}
+ 	if (ftp->in_use) {
+ 		php_error_docref(NULL, E_WARNING, "FTP\\Connection is already in use");
 -		return 0;
++		return false;
+ 	}
+ 	ftp->in_use = true;
  	if (!ftp_type(ftp, type)) {
  		goto bail;
  	}
@@@ -1021,19 -1109,30 +1033,26 @@@
  	if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
  		goto bail;
  	}
+ 	ftp->in_use = false;
 -	return 1;
 +	return true;
  bail:
  	data_close(ftp);
+ 	ftp->in_use = false;
 -	return 0;
 +	return false;
  }
 -/* }}} */
 -

 -/* {{{ ftp_append */
 -int
 -ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type)
 +bool ftp_append(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *instream, ftptype_t type)
  {
 -	databuf_t		*data = NULL;
 +	databuf_t *data = NULL;

  	if (ftp == NULL) {
 -		return 0;
 +		return false;
  	}
+ 	if (ftp->in_use) {
+ 		php_error_docref(NULL, E_WARNING, "FTP\\Connection is already in use");
 -		return 0;
++		return false;
+ 	}
+ 	ftp->in_use = true;
  	if (!ftp_type(ftp, type)) {
  		goto bail;
  	}
@@@ -1061,13 -1160,18 +1080,15 @@@
  	if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250 && ftp->resp != 200)) {
  		goto bail;
  	}
+ 	ftp->in_use = false;
 -	return 1;
 +	return true;
  bail:
  	data_close(ftp);
+ 	ftp->in_use = false;
 -	return 0;
 +	return false;
  }
 -/* }}} */

 -/* {{{ ftp_size */
 -zend_long
 -ftp_size(ftpbuf_t *ftp, const char *path, const size_t path_len)
 +zend_long ftp_size(ftpbuf_t *ftp, const char *path, const size_t path_len)
  {
  	if (ftp == NULL) {
  		return -1;
@@@ -2179,9 -2366,18 +2222,14 @@@ bail
  	data_close(ftp);
  	return PHP_FTP_FAILED;
  }
 -/* }}} */
 -

 -/* {{{ ftp_nb_continue_write */
 -int
 -ftp_nb_continue_write(ftpbuf_t *ftp)
 +int ftp_nb_continue_write(ftpbuf_t *ftp)
  {
+ 	if (ftp->in_use) {
+ 		php_error_docref(NULL, E_WARNING, "FTP\\Connection is already in use");
+ 		return PHP_FTP_FAILED;
+ 	}
+
  	/* check if we can write more data */
  	if (!data_writeable(ftp, ftp->data->fd)) {
  		return PHP_FTP_MOREDATA;
@@@ -2205,5 -2405,7 +2257,6 @@@
  bail:
  	data_close(ftp);
  	ftp->nb = 0;
+ 	ftp->in_use = false;
  	return PHP_FTP_FAILED;
  }
 -/* }}} */
diff --cc ext/ftp/php_ftp.c
index f19cc4b4b6b,432270cff19..c89c1f07f7c
--- a/ext/ftp/php_ftp.c
+++ b/ext/ftp/php_ftp.c
@@@ -800,12 -803,12 +809,12 @@@ PHP_FUNCTION(ftp_nb_get
  	}

  	/* configuration */
 -	ftp->direction = 0;   /* recv */
 -	ftp->closestream = 1; /* do close */
 +	ftp->direction = false;   /* recv */
 +	ftp->closestream = true; /* do close */

  	if ((ret = ftp_nb_get(ftp, outstream, remote, remote_len, xtype, resumepos)) == PHP_FTP_FAILED) {
- 		php_stream_close(outstream);
  		ftp->stream = NULL;
+ 		php_stream_close(outstream);
  		VCWD_UNLINK(local);
  		if (*ftp->inbuf) {
  			php_error_docref(NULL, E_WARNING, "%s", ftp->inbuf);
@@@ -953,8 -946,13 +962,13 @@@ PHP_FUNCTION(ftp_nb_fput
  	}

  	/* configuration */
+ 	if (ftp->in_use) {
+ 		php_error_docref(NULL, E_WARNING, "FTP\\Connection is already in use");
+ 		RETURN_FALSE;
+ 	}
+
 -	ftp->direction = 1;   /* send */
 -	ftp->closestream = 0; /* do not close */
 +	ftp->direction = true;   /* send */
 +	ftp->closestream = false; /* do not close */

  	if (((ret = ftp_nb_put(ftp, remote, remote_len, stream, xtype, startpos)) == PHP_FTP_FAILED)) {
  		if (*ftp->inbuf) {
@@@ -1093,9 -1091,15 +1107,15 @@@ PHP_FUNCTION(ftp_nb_put
  		}
  	}

+ 	if (ftp->in_use) {
+ 		php_stream_close(instream);
+ 		php_error_docref(NULL, E_WARNING, "FTP\\Connection is already in use");
+ 		RETURN_FALSE;
+ 	}
+
  	/* configuration */
 -	ftp->direction = 1;   /* send */
 -	ftp->closestream = 1; /* do close */
 +	ftp->direction = true;   /* send */
 +	ftp->closestream = true; /* do close */

  	ret = ftp_nb_put(ftp, remote, remote_len, instream, xtype, startpos);