diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index 66a05a95f4ed..1b1af31bb0c9 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -871,7 +871,7 @@ bool ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_ #else while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) { php_stream_write(outstream, ptr, (s - ptr)); - if (*(s + 1) == '\n') { + if (s + 1 < e && *(s + 1) == '\n') { s++; php_stream_putc(outstream, '\n'); } diff --git a/ext/ftp/tests/ftp_get_ascii_crlf_boundary.phpt b/ext/ftp/tests/ftp_get_ascii_crlf_boundary.phpt new file mode 100644 index 000000000000..4c3a70b647c6 --- /dev/null +++ b/ext/ftp/tests/ftp_get_ascii_crlf_boundary.phpt @@ -0,0 +1,25 @@ +--TEST-- +ftp_get() ASCII mode: CRLF straddling the FTP_BUFSIZE read boundary +--EXTENSIONS-- +ftp +pcntl +--FILE-- + +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) diff --git a/ext/ftp/tests/server.inc b/ext/ftp/tests/server.inc index 97f4f07d0020..04e2ceefa278 100644 --- a/ext/ftp/tests/server.inc +++ b/ext/ftp/tests/server.inc @@ -391,6 +391,13 @@ if ($pid) { // Just a side channel for getting the received file size. fputs($s, "425 Can't open data connection (".$GLOBALS['rest_pos'].").\r\n"); break; + case "crlf_boundary": + // A CRLF whose CR lands on the final byte of the first + // FTP_BUFSIZE (4096) read, so the LF arrives in the next read. + fputs($s, "150 File status okay; about to open data connection.\r\n"); + fputs($fs, str_repeat("A", 4095) . "\r\n" . str_repeat("B", 10)); + fputs($s, "226 Closing data Connection.\r\n"); + break; default: fputs($s, "550 {$matches[1]}: No such file or directory \r\n"); diff --git a/ext/standard/io_poll.c b/ext/standard/io_poll.c index 4bb7f6a80688..c36306a0b49b 100644 --- a/ext/standard/io_poll.c +++ b/ext/standard/io_poll.c @@ -68,11 +68,9 @@ typedef struct php_stream_poll_handle_data { } php_stream_poll_handle_data; /* Accessor macros */ -#define PHP_POLL_CONTEXT_OBJ_FROM_ZOBJ(_obj) \ - ((php_io_poll_context_object *) ((char *) (_obj) - offsetof(php_io_poll_context_object, std))) +#define PHP_POLL_CONTEXT_OBJ_FROM_ZOBJ(_obj) ZEND_CONTAINER_OF(_obj, php_io_poll_context_object, std) -#define PHP_POLL_WATCHER_OBJ_FROM_ZOBJ(_obj) \ - ((php_io_poll_watcher_object *) ((char *) (_obj) - offsetof(php_io_poll_watcher_object, std))) +#define PHP_POLL_WATCHER_OBJ_FROM_ZOBJ(_obj) ZEND_CONTAINER_OF(_obj, php_io_poll_watcher_object, std) #define PHP_POLL_WATCHER_OBJ_FROM_ZV(_zv) PHP_POLL_WATCHER_OBJ_FROM_ZOBJ(Z_OBJ_P(_zv)) #define PHP_POLL_CONTEXT_OBJ_FROM_ZV(_zv) PHP_POLL_CONTEXT_OBJ_FROM_ZOBJ(Z_OBJ_P(_zv)) diff --git a/main/php_poll.h b/main/php_poll.h index 254f885a6d3b..c73052712940 100644 --- a/main/php_poll.h +++ b/main/php_poll.h @@ -158,8 +158,7 @@ struct php_poll_handle_object { zend_object std; }; -#define PHP_POLL_HANDLE_OBJ_FROM_ZOBJ(obj) \ - ((php_poll_handle_object *) ((char *) (obj) - offsetof(php_poll_handle_object, std))) +#define PHP_POLL_HANDLE_OBJ_FROM_ZOBJ(obj) ZEND_CONTAINER_OF(obj, php_poll_handle_object, std) #define PHP_POLL_HANDLE_OBJ_FROM_ZV(zv) PHP_POLL_HANDLE_OBJ_FROM_ZOBJ(Z_OBJ_P(zv)) diff --git a/win32/build/config.w32 b/win32/build/config.w32 index e099167c076a..a0f26033306f 100644 --- a/win32/build/config.w32 +++ b/win32/build/config.w32 @@ -312,7 +312,7 @@ ADD_SOURCES("win32", "dllmain.c readdir.c \ ADD_FLAG("CFLAGS_BD_WIN32", "/D ZEND_ENABLE_STATIC_TSRMLS_CACHE=1"); -PHP_INSTALL_HEADERS("", "Zend/ TSRM/ main/ main/poll/ main/streams/ win32/"); +PHP_INSTALL_HEADERS("", "Zend/ TSRM/ main/ main/streams/ win32/"); PHP_INSTALL_HEADERS("Zend/Optimizer", "zend_call_graph.h zend_cfg.h zend_dfg.h zend_dump.h zend_func_info.h zend_inference.h zend_optimizer.h zend_ssa.h zend_worklist.h"); STDOUT.WriteBlankLines(1);