diff --git a/ext/ftp/ftp.c b/ext/ftp/ftp.c index 1b1af31bb0c9..900f26804b74 100644 --- a/ext/ftp/ftp.c +++ b/ext/ftp/ftp.c @@ -850,6 +850,7 @@ bool ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_ goto bail; } + bool pending_cr = false; while ((rcvd = my_recv(ftp, data->fd, data->buf, FTP_BUFSIZE))) { if (rcvd == (size_t)-1) { goto bail; @@ -869,13 +870,30 @@ bool ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_ php_stream_write(outstream, ptr, (e - ptr)); ptr = e; #else - while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) { - php_stream_write(outstream, ptr, (s - ptr)); - if (s + 1 < e && *(s + 1) == '\n') { - s++; + if (pending_cr) { + pending_cr = false; + if (*ptr == '\n') { php_stream_putc(outstream, '\n'); + ptr++; + } else { + php_stream_putc(outstream, '\r'); + } + } + while (e > ptr && (s = memchr(ptr, '\r', (e - ptr)))) { + if (s + 1 < e) { + if (*(s + 1) == '\n') { + php_stream_write(outstream, ptr, (s - ptr)); + php_stream_putc(outstream, '\n'); + ptr = s + 2; + } else { + php_stream_write(outstream, ptr, (s - ptr) + 1); + ptr = s + 1; + } + } else { + php_stream_write(outstream, ptr, (s - ptr)); + pending_cr = true; + ptr = s + 1; } - ptr = s + 1; } #endif if (ptr < e) { @@ -885,6 +903,9 @@ bool ftp_get(ftpbuf_t *ftp, php_stream *outstream, const char *path, const size_ goto bail; } } + if (pending_cr) { + php_stream_putc(outstream, '\r'); + } data_close(ftp); diff --git a/ext/ftp/tests/ftp_get_ascii_bare_cr.phpt b/ext/ftp/tests/ftp_get_ascii_bare_cr.phpt new file mode 100644 index 000000000000..1fe92bf8de7e --- /dev/null +++ b/ext/ftp/tests/ftp_get_ascii_bare_cr.phpt @@ -0,0 +1,32 @@ +--TEST-- +ftp_get() ASCII mode: bare CR is preserved, CRLF folds to LF +--EXTENSIONS-- +ftp +pcntl +--FILE-- + +--CLEAN-- + +--EXPECT-- +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/ftp/tests/server.inc b/ext/ftp/tests/server.inc index 04e2ceefa278..251536ff8202 100644 --- a/ext/ftp/tests/server.inc +++ b/ext/ftp/tests/server.inc @@ -398,6 +398,20 @@ if ($pid) { fputs($fs, str_repeat("A", 4095) . "\r\n" . str_repeat("B", 10)); fputs($s, "226 Closing data Connection.\r\n"); break; + case "bare_cr": + // A bare CR (not part of CRLF) mid-stream, plus a bare CR on + // the final byte of the first FTP_BUFSIZE (4096) read followed + // by a non-LF byte in the next read. + fputs($s, "150 File status okay; about to open data connection.\r\n"); + fputs($fs, "line1\r\nba\rre\r\nend" . str_repeat("X", 4078) . "\r" . str_repeat("Y", 10)); + fputs($s, "226 Closing data Connection.\r\n"); + break; + case "trailing_cr": + // The whole transfer ends on a bare CR. + fputs($s, "150 File status okay; about to open data connection.\r\n"); + fputs($fs, "trail\r"); + 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/snmp/snmp.c b/ext/snmp/snmp.c index 44f714bf0368..84f7cad13f74 100644 --- a/ext/snmp/snmp.c +++ b/ext/snmp/snmp.c @@ -945,6 +945,7 @@ static bool snmp_session_init(php_snmp_session **session_p, int version, zend_st if (strlen(session->peername) == 0) { php_error_docref(NULL, E_WARNING, "Unknown failure while resolving '%s'", ZSTR_VAL(hostname)); + php_network_freeaddresses(psal); return false; } /* XXX FIXME diff --git a/ext/snmp/tests/snmp_resolve_fail_leak.phpt b/ext/snmp/tests/snmp_resolve_fail_leak.phpt new file mode 100644 index 000000000000..c8793b09e928 --- /dev/null +++ b/ext/snmp/tests/snmp_resolve_fail_leak.phpt @@ -0,0 +1,16 @@ +--TEST-- +snmp: resolved address list is freed when peername resolution drains empty +--EXTENSIONS-- +snmp +--FILE-- + +--EXPECTF-- +Warning: snmpget(): Unknown failure while resolving '[127.0.0.1]' in %s on line %d +bool(false) diff --git a/ext/sockets/conversions.c b/ext/sockets/conversions.c index 4cbd4e3325ac..76a08559b809 100644 --- a/ext/sockets/conversions.c +++ b/ext/sockets/conversions.c @@ -1398,7 +1398,7 @@ static void from_zval_write_fd_array_aux(zval *elem, unsigned i, void **args, se return; } - iarr[i] = sock->bsd_socket; + iarr[i - 1] = sock->bsd_socket; return; } diff --git a/ext/sockets/tests/socket_cmsg_rights.phpt b/ext/sockets/tests/socket_cmsg_rights.phpt index 1794eaf767ac..8bfbcd57157f 100644 --- a/ext/sockets/tests/socket_cmsg_rights.phpt +++ b/ext/sockets/tests/socket_cmsg_rights.phpt @@ -58,7 +58,7 @@ if ($data["control"]) { if ($control["level"] == SOL_SOCKET && $control["type"] == SCM_RIGHTS) { foreach ($control["data"] as $resource) { - if (!is_resource($resource)) { + if (!is_resource($resource) && !($resource instanceof Socket)) { echo "FAIL RES\n"; var_dump($data); exit; diff --git a/ext/sockets/tests/socket_sendmsg_scm_rights_object.phpt b/ext/sockets/tests/socket_sendmsg_scm_rights_object.phpt new file mode 100644 index 000000000000..907ea70ac169 --- /dev/null +++ b/ext/sockets/tests/socket_sendmsg_scm_rights_object.phpt @@ -0,0 +1,77 @@ +--TEST-- +socket_sendmsg(): SCM_RIGHTS transfers Socket objects with the correct fds +--EXTENSIONS-- +sockets +--SKIPIF-- + +--FILE-- + ['x'], + 'control' => [[ + 'level' => SOL_SOCKET, + 'type' => SCM_RIGHTS, + 'data' => [$payload1, $payload2], + ]], +], 0); + +$data = [ + 'name' => [], + 'buffer_size' => 64, + 'controllen' => socket_cmsg_space(SOL_SOCKET, SCM_RIGHTS, 2), +]; +socket_recvmsg($recv, $data, 0); + +$got = $data['control'][0]['data']; +var_dump(count($got)); +var_dump($got[0] instanceof Socket); +var_dump($got[1] instanceof Socket); +socket_getsockname($got[0], $addr0); +socket_getsockname($got[1], $addr1); +var_dump($addr0 === $ppath1); +var_dump($addr1 === $ppath2); +?> +--CLEAN-- + +--EXPECT-- +int(2) +bool(true) +bool(true) +bool(true) +bool(true) diff --git a/ext/standard/io_poll.c b/ext/standard/io_poll.c index e8366c7e8802..b1eb7513f1cb 100644 --- a/ext/standard/io_poll.c +++ b/ext/standard/io_poll.c @@ -85,32 +85,12 @@ static inline void php_io_poll_throw_failed_operation( /* Event enum to bit mask mapping */ static uint32_t php_io_poll_event_enum_to_bit(zend_object *event_enum) { - zval *case_name = zend_enum_fetch_case_name(event_enum); - const char *name = Z_STRVAL_P(case_name); - - if (strcmp(name, "Read") == 0) { - return PHP_POLL_READ; - } else if (strcmp(name, "Write") == 0) { - return PHP_POLL_WRITE; - } else if (strcmp(name, "Error") == 0) { - return PHP_POLL_ERROR; - } else if (strcmp(name, "HangUp") == 0) { - return PHP_POLL_HUP; - } else if (strcmp(name, "ReadHangUp") == 0) { - return PHP_POLL_RDHUP; - } else if (strcmp(name, "OneShot") == 0) { - return PHP_POLL_ONESHOT; - } else if (strcmp(name, "EdgeTriggered") == 0) { - return PHP_POLL_ET; - } - - return 0; + return 1 << (zend_enum_fetch_case_id(event_enum) - 1); } static uint32_t php_io_poll_event_enums_to_events(zval *event_enums) { HashTable *ht; - zval *entry; uint32_t events = 0; if (Z_TYPE_P(event_enums) != IS_ARRAY) { @@ -119,7 +99,7 @@ static uint32_t php_io_poll_event_enums_to_events(zval *event_enums) ht = Z_ARRVAL_P(event_enums); - ZEND_HASH_FOREACH_VAL(ht, entry) { + ZEND_HASH_FOREACH_VAL(ht, zval *entry) { if (Z_TYPE_P(entry) != IS_OBJECT || !instanceof_function(Z_OBJCE_P(entry), php_io_poll_event_class_entry)) { return 0; @@ -179,24 +159,7 @@ static zend_result php_io_poll_events_to_event_enums(uint32_t events, zval *even /* Backend enum name to backend type mapping */ static php_poll_backend_type php_io_poll_backend_enum_to_type(zend_object *backend_enum) { - zval *case_name = zend_enum_fetch_case_name(backend_enum); - const char *name = Z_STRVAL_P(case_name); - - if (strcmp(name, "Auto") == 0) { - return PHP_POLL_BACKEND_AUTO; - } else if (strcmp(name, "Poll") == 0) { - return PHP_POLL_BACKEND_POLL; - } else if (strcmp(name, "Epoll") == 0) { - return PHP_POLL_BACKEND_EPOLL; - } else if (strcmp(name, "Kqueue") == 0) { - return PHP_POLL_BACKEND_KQUEUE; - } else if (strcmp(name, "EventPorts") == 0) { - return PHP_POLL_BACKEND_EVENTPORT; - } else if (strcmp(name, "WSAPoll") == 0) { - return PHP_POLL_BACKEND_WSAPOLL; - } - - return PHP_POLL_BACKEND_AUTO; + return zend_enum_fetch_case_id(backend_enum) - 2; } static const char *php_io_poll_backend_type_to_name(php_poll_backend_type type) @@ -333,8 +296,7 @@ static void php_io_poll_context_free_object(zend_object *obj) php_io_poll_context_object *intern = PHP_POLL_CONTEXT_OBJ_FROM_ZOBJ(obj); if (intern->watchers) { - zval *zv; - ZEND_HASH_FOREACH_VAL(intern->watchers, zv) { + ZEND_HASH_FOREACH_VAL(intern->watchers, zval *zv) { php_io_poll_watcher_object *watcher = PHP_POLL_WATCHER_OBJ_FROM_ZOBJ(Z_OBJ_P(zv)); watcher->active = false; watcher->poll_ctx = NULL; @@ -373,8 +335,7 @@ static HashTable *php_io_poll_context_get_gc(zend_object *obj, zval **table, int zend_get_gc_buffer *gc_buffer = zend_get_gc_buffer_create(); if (intern->watchers) { - zval *zv; - ZEND_HASH_FOREACH_VAL(intern->watchers, zv) { + ZEND_HASH_FOREACH_VAL(intern->watchers, zval *zv) { zend_get_gc_buffer_add_zval(gc_buffer, zv); } ZEND_HASH_FOREACH_END(); } diff --git a/ext/standard/io_poll.stub.php b/ext/standard/io_poll.stub.php index 82bc00e0aaca..83c1ba5cbe2e 100644 --- a/ext/standard/io_poll.stub.php +++ b/ext/standard/io_poll.stub.php @@ -1,6 +1,9 @@ 0) { /* Clean up orphaned filters from complete oneshot FDs */ - zend_ulong fd_key; - zval *tracking; struct kevent cleanup_change; - ZEND_HASH_FOREACH_NUM_KEY_VAL(backend_data->fd_tracking, fd_key, tracking) + ZEND_HASH_FOREACH_NUM_KEY_VAL(backend_data->fd_tracking, zend_ulong fd_key, zval *tracking) { zend_long flags = Z_LVAL_P(tracking); if (flags & KQUEUE_FD_HAS_GARBAGE) { diff --git a/main/poll/poll_fd_table.c b/main/poll/poll_fd_table.c index 97231072322c..1c76da79b7eb 100644 --- a/main/poll/poll_fd_table.c +++ b/main/poll/poll_fd_table.c @@ -34,9 +34,7 @@ php_poll_fd_table *php_poll_fd_table_init(int initial_capacity, bool persistent) void php_poll_fd_table_cleanup(php_poll_fd_table *table) { if (table) { - zval *zv; - - ZEND_HASH_FOREACH_VAL(&table->entries_ht, zv) + ZEND_HASH_FOREACH_VAL(&table->entries_ht, zval *zv) { php_poll_fd_entry *entry = Z_PTR_P(zv); pefree(entry, table->persistent); @@ -105,10 +103,7 @@ typedef bool (*php_poll_fd_iterator_func_t)(int fd, php_poll_fd_entry *entry, vo void php_poll_fd_table_foreach( php_poll_fd_table *table, php_poll_fd_iterator_func_t callback, void *user_data) { - zend_ulong fd; - zval *zv; - - ZEND_HASH_FOREACH_NUM_KEY_VAL(&table->entries_ht, fd, zv) + ZEND_HASH_FOREACH_NUM_KEY_VAL(&table->entries_ht, zend_ulong fd, zval *zv) { php_poll_fd_entry *entry = Z_PTR_P(zv); if (entry->active && !callback((int) fd, entry, user_data)) {