diff --git a/NEWS b/NEWS index 48afd654b2ef..4ea6485c80e2 100644 --- a/NEWS +++ b/NEWS @@ -51,6 +51,8 @@ PHP NEWS - FTP: . Fix double free in ext/ftp data_accept() on accept failure. (alepacheco) + . Fixed ftp_nb_put() not aborting a pending non-blocking transfer, which + leaked its data connection. (Jakub Kozub) - MBString: . Fixed bug GH-23958 (truncated encoding names resolving to full names). (Kamil Tekiela) diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index fd0f295500b8..7bfe4c69c26a 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -2329,6 +2329,14 @@ ftp_nb_put(ftpbuf_t *ftp, const char *path, const size_t path_len, php_stream *i php_error_docref(NULL, E_WARNING, "FTP\\Connection is already in use"); return PHP_FTP_FAILED; } + if (ftp->data != NULL) { + /* If there is a transfer in action, abort it. + * If we don't, we get an invalid state and memory leaks when the new connection gets opened. */ + data_close(ftp); + if (!ftp_getresp(ftp) || (ftp->resp != 226 && ftp->resp != 250)) { + goto bail; + } + } if (!ftp_type(ftp, type)) { goto bail; } diff --git a/ext/ftp/tests/ftp_nb_put_during_nb_transfer.phpt b/ext/ftp/tests/ftp_nb_put_during_nb_transfer.phpt new file mode 100644 index 000000000000..ca7968813fe5 --- /dev/null +++ b/ext/ftp/tests/ftp_nb_put_during_nb_transfer.phpt @@ -0,0 +1,42 @@ +--TEST-- +ftp_nb_put() must abort a pending non-blocking transfer, like ftp_nb_get() does +--EXTENSIONS-- +ftp +pcntl +--FILE-- +data while the previous + * databuf_t is still owned by it, and reads the pending transfer's response + * as the answer to its own command. */ +$ret = ftp_nb_put($ftp, basename(__FILE__), __FILE__, FTP_ASCII); +while ($ret == FTP_MOREDATA) { + $ret = ftp_nb_continue($ftp); +} +var_dump($ret === FTP_FINISHED); + +ftp_close($ftp); +echo "closed\n"; +?> +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +closed