summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2020-06-19 10:46:02 +0200
committerNikita Popov <nikita.ppv@gmail.com>2020-06-19 10:46:26 +0200
commit32f377b0b94482a5b126408942646b9bd101c042 (patch)
tree70393e9c97a08b0c5971bc38c9f2a49487db9aa1
parent5621c5faf899c94baa2b41acb457494ca30368c3 (diff)
downloadphp-git-32f377b0b94482a5b126408942646b9bd101c042.tar.gz
Fixed bug #79710
Make sure we don't use zresource after the stream has been destroyed.
-rw-r--r--NEWS4
-rw-r--r--ext/spl/spl_directory.c9
-rw-r--r--ext/spl/tests/bug79710.phpt40
3 files changed, 51 insertions, 2 deletions
diff --git a/NEWS b/NEWS
index c7478ce2de..33fbff3a54 100644
--- 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)
diff --git a/ext/spl/spl_directory.c b/ext/spl/spl_directory.c
index b9e6bf91e8..6e79bc407f 100644
--- a/ext/spl/spl_directory.c
+++ b/ext/spl/spl_directory.c
@@ -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
index 0000000000..a5c065fd67
--- /dev/null
+++ b/ext/spl/tests/bug79710.phpt
@@ -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