]> granicus.if.org Git - php/commitdiff
Properly handle non resources passed to socket_select()
authorChristoph M. Becker <cmbecker69@gmx.de>
Sat, 12 Oct 2019 21:05:56 +0000 (23:05 +0200)
committerChristoph M. Becker <cmbecker69@gmx.de>
Fri, 18 Oct 2019 12:16:25 +0000 (14:16 +0200)
As of PHP 8.0.0, failing `zend_fetch_resource_ex()` throws a TypeError,
so we cannot simply skip non resources in the `$read`, `$write` and
`$except` arrays.  Instead we bail out.  Since these arrays are already
checked in `php_sock_array_to_fd_set()`, we remove the additional check
in `php_sock_array_from_fd_set()`.

ext/sockets/sockets.c
ext/sockets/tests/socket_select_error.phpt [new file with mode: 0644]

index f786c8b50aa2673bc71ec094c7d2a63e7d6e527d..575c213181b519a91a61adf7c3161b5901c5335b 100644 (file)
@@ -694,7 +694,7 @@ static int php_sock_array_to_fd_set(zval *sock_array, fd_set *fds, PHP_SOCKET *m
        ZEND_HASH_FOREACH_VAL(Z_ARRVAL_P(sock_array), element) {
                ZVAL_DEREF(element);
                php_sock = (php_socket*) zend_fetch_resource_ex(element, le_socket_name, le_socket);
-               if (!php_sock) continue; /* If element is not a resource, skip it */
+               if (!php_sock) return -1; /* If element is not a resource, bail out */
 
                PHP_SAFE_FD_SET(php_sock->bsd_socket, fds);
                if (php_sock->bsd_socket > *max_fd) {
@@ -723,7 +723,7 @@ static int php_sock_array_from_fd_set(zval *sock_array, fd_set *fds) /* {{{ */
        ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(sock_array), num_key, key, element) {
                ZVAL_DEREF(element);
                php_sock = (php_socket*) zend_fetch_resource_ex(element, le_socket_name, le_socket);
-               if (!php_sock) continue; /* If element is not a resource, skip it */
+               ZEND_ASSERT(php_sock); /* element is supposed to be resource */
 
                if (PHP_SAFE_FD_ISSET(php_sock->bsd_socket, fds)) {
                        /* Add fd to new array */
@@ -769,9 +769,24 @@ PHP_FUNCTION(socket_select)
        FD_ZERO(&wfds);
        FD_ZERO(&efds);
 
-       if (r_array != NULL) sets += php_sock_array_to_fd_set(r_array, &rfds, &max_fd);
-       if (w_array != NULL) sets += php_sock_array_to_fd_set(w_array, &wfds, &max_fd);
-       if (e_array != NULL) sets += php_sock_array_to_fd_set(e_array, &efds, &max_fd);
+       if (r_array != NULL) {
+               sets += retval = php_sock_array_to_fd_set(r_array, &rfds, &max_fd);
+               if (retval == -1) {
+                       return;
+               }
+       }
+       if (w_array != NULL) {
+               sets += retval = php_sock_array_to_fd_set(w_array, &wfds, &max_fd);
+               if (retval == -1) {
+                       return;
+               }
+       }
+       if (e_array != NULL) {
+               sets += retval = php_sock_array_to_fd_set(e_array, &efds, &max_fd);
+               if (retval == -1) {
+                       return;
+               }
+       }
 
        if (!sets) {
                php_error_docref(NULL, E_WARNING, "no resource arrays were passed to select");
diff --git a/ext/sockets/tests/socket_select_error.phpt b/ext/sockets/tests/socket_select_error.phpt
new file mode 100644 (file)
index 0000000..48acb33
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+socket_select() error conditions
+--SKIPIF--
+<?php
+if (!extension_loaded('sockets')) die('skip socket extension not available');
+?>
+--FILE--
+<?php
+$r = $w = $e = ['no resource'];
+try {
+    socket_select($r, $w, $e, 1);
+} catch (TypeError $ex) {
+    echo $ex->getMessage(), PHP_EOL;
+}
+?>
+--EXPECT--
+socket_select(): supplied argument is not a valid Socket resource