]> granicus.if.org Git - php/commitdiff
Fixed bug #79710
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 19 Jun 2020 08:46:02 +0000 (10:46 +0200)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 19 Jun 2020 08:46:26 +0000 (10:46 +0200)
Make sure we don't use zresource after the stream has been destroyed.

NEWS
ext/spl/spl_directory.c
ext/spl/tests/bug79710.phpt [new file with mode: 0644]

diff --git a/NEWS b/NEWS
index c7478ce2de06aa6d3281b781d7d9e08750a81ea6..33fbff3a54f271c443e2eb3f68cb8d1f81c62aa3 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -26,6 +26,10 @@ PHP                                                                        NEWS
   . Fixed bug #79664 (PDOStatement::getColumnMeta fails on empty result set).
     (cmb)
 
+- SPL:
+  . Fixed bug #79710 (Reproducible segfault in error_handler during GC
+    involved an SplFileObject). (Nikita)
+
 - Standard:
   . Fixed bug #74267 (segfault with streams and invalid data). (cmb)
 
index b9e6bf91e8b4310c8babe9ff41f30ee6f7158977..6e79bc407fef274550d54f3a3506883d0debc697 100644 (file)
@@ -96,6 +96,7 @@ static void spl_filesystem_object_destroy_object(zend_object *object) /* {{{ */
                                php_stream_pclose(intern->u.file.stream);
                        }
                        intern->u.file.stream = NULL;
+                       ZVAL_UNDEF(&intern->u.file.zresource);
                }
                break;
        default:
@@ -2062,12 +2063,16 @@ static int spl_filesystem_file_call(spl_filesystem_object *intern, zend_function
 {
        zend_fcall_info fci;
        zend_fcall_info_cache fcic;
-       zval *zresource_ptr = &intern->u.file.zresource, retval;
+       zval *zresource_ptr = &intern->u.file.zresource, *params, retval;
        int result;
        int num_args = pass_num_args + (arg2 ? 2 : 1);
 
-       zval *params = (zval*)safe_emalloc(num_args, sizeof(zval), 0);
+       if (Z_ISUNDEF_P(zresource_ptr)) {
+               zend_throw_exception_ex(spl_ce_RuntimeException, 0, "Object not initialized");
+               return FAILURE;
+       }
 
+       params = (zval*)safe_emalloc(num_args, sizeof(zval), 0);
        params[0] = *zresource_ptr;
 
        if (arg2) {
diff --git a/ext/spl/tests/bug79710.phpt b/ext/spl/tests/bug79710.phpt
new file mode 100644 (file)
index 0000000..a5c065f
--- /dev/null
@@ -0,0 +1,40 @@
+--TEST--
+Bug #79710: Reproducible segfault in error_handler during GC involved an SplFileObject
+--FILE--
+<?php
+
+class Target
+{
+    public $sfo;
+    public function __construct($sfo) {
+        $this->sfo = $sfo;
+    }
+    public function __destruct() {
+        // If the SplFileObject is destructed first,
+        // underlying FD is no longer valid and will cause error upon calling flock
+        $this->sfo->flock(2);
+    }
+}
+
+class Run
+{
+    static $sfo;
+    static $foo;
+    public static function main() {
+        // Creation ordering is important for repro
+        // $sfo needed to be destructed before $foo.
+        Run::$sfo = new SplTempFileObject();
+        Run::$foo = new Target(Run::$sfo);
+    }
+}
+
+Run::main();
+
+?>
+--EXPECTF--
+Fatal error: Uncaught RuntimeException: Object not initialized in %s:%d
+Stack trace:
+#0 %s(%d): SplFileObject->flock(2)
+#1 [internal function]: Target->__destruct()
+#2 {main}
+  thrown in %s on line %d