]> granicus.if.org Git - php/commitdiff
- Fixed bug #54623 (Segfault when when writing to a persistent socket after
authorGustavo André dos Santos Lopes <cataphract@php.net>
Sun, 1 May 2011 03:57:01 +0000 (03:57 +0000)
committerGustavo André dos Santos Lopes <cataphract@php.net>
Sun, 1 May 2011 03:57:01 +0000 (03:57 +0000)
  closing a copy of the socket).

NEWS
ext/standard/tests/streams/bug54623.phpt [new file with mode: 0644]
main/streams/streams.c

diff --git a/NEWS b/NEWS
index 2a11f90cb36c1eaac445084d5c02ed8f74434c11..16ac3f6260c3aaa7acb852a6562ec0a991fca787 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -109,6 +109,10 @@ PHP                                                                        NEWS
   . Fixed bug #54281 (Crash in non-initialized RecursiveIteratorIterator).
     (Felipe)
 
+- Streams:
+  . Fixed bug #54623 (Segfault when when writing to a persistent socket after
+    closing a copy of the socket). (Gustavo)
+
 17 Mar 2011, PHP 5.3.6
 - Upgraded bundled Sqlite3 to version 3.7.4. (Ilia)
 - Upgraded bundled PCRE to version 8.11. (Ilia)
diff --git a/ext/standard/tests/streams/bug54623.phpt b/ext/standard/tests/streams/bug54623.phpt
new file mode 100644 (file)
index 0000000..cd83854
--- /dev/null
@@ -0,0 +1,17 @@
+--TEST--
+Bug #54623: Segfault when when writing to a persistent socket after closing a copy of the socket
+--FILE--
+<?php
+$sock = pfsockopen('udp://127.0.0.1', '63844');
+var_dump((int)$sock);
+fwrite($sock, "1");
+$sock2 = pfsockopen('udp://127.0.0.1', '63844');
+var_dump((int)$sock2);
+fwrite($sock2, "2");
+fclose($sock2);
+fwrite($sock, "3");
+--EXPECTF--
+int(%d)
+int(%d)
+
+Warning: fwrite(): %d is not a valid stream resource in %s on line %d
index 9de8f2451c49599c308de6f40d2eb2495aadc022..9c0501716551115a40802fef250f60c416bb8580 100755 (executable)
@@ -112,9 +112,32 @@ PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream *
        if (zend_hash_find(&EG(persistent_list), (char*)persistent_id, strlen(persistent_id)+1, (void*) &le) == SUCCESS) {
                if (Z_TYPE_P(le) == le_pstream) {
                        if (stream) {
+                               HashPosition pos;
+                               zend_rsrc_list_entry *regentry;
+                               ulong index = -1; /* intentional */
+
+                               /* see if this persistent resource already has been loaded to the
+                                * regular list; allowing the same resource in several entries in the
+                                * regular list causes trouble (see bug #54623) */
+                               zend_hash_internal_pointer_reset_ex(&EG(regular_list), &pos);
+                               while (zend_hash_get_current_data_ex(&EG(regular_list),
+                                               (void **)&regentry, &pos) == SUCCESS) {
+                                       if (regentry->ptr == le->ptr) {
+                                               zend_hash_get_current_key_ex(&EG(regular_list), NULL, NULL,
+                                                       &index, 0, &pos);
+                                               break;
+                                       }
+                                       zend_hash_move_forward_ex(&EG(regular_list), &pos);
+                               }
+                               
                                *stream = (php_stream*)le->ptr;
-                               le->refcount++;
-                               (*stream)->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, *stream, le_pstream);
+                               if (index == -1) { /* not found in regular list */
+                                       le->refcount++;
+                                       (*stream)->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, *stream, le_pstream);
+                               } else {
+                                       regentry->refcount++;
+                                       (*stream)->rsrc_id = index;
+                               }
                        }
                        return PHP_STREAM_PERSISTENT_SUCCESS;
                }
@@ -404,7 +427,7 @@ fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remov
                                stream->orig_path = NULL;
                        }
 
-# if defined(PHP_WIN32)
+# if defined(PHP_WIN32_)
                        OutputDebugString(leakinfo);
 # else
                        fprintf(stderr, "%s", leakinfo);