From 71a93b7beb4f34cbf0603d546161dbf45b8a471c Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Wed, 5 Aug 2020 14:44:13 +0200 Subject: [PATCH 1/3] PHPLIB-345: Fix PHP shutdown error with dangling writable streams --- src/GridFS/StreamWrapper.php | 12 ++++++++++++ tests/GridFS/BucketFunctionalTest.php | 18 ++++++++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/GridFS/StreamWrapper.php b/src/GridFS/StreamWrapper.php index 871e0b2bf..d2034108a 100644 --- a/src/GridFS/StreamWrapper.php +++ b/src/GridFS/StreamWrapper.php @@ -57,6 +57,14 @@ class StreamWrapper /** @var ReadableStream|WritableStream|null */ private $stream; + public function __destruct() + { + /* This destructor is a workaround for PHP trying to use the stream well + * after all objects have been destructed. This causes autoloading + * issues and possibly segmentation faults during PHP shutdown. */ + $this->stream = null; + } + /** * Return the stream's file document. * @@ -88,6 +96,10 @@ public static function register($protocol = 'gridfs') */ public function stream_close() { + if (! $this->stream) { + return; + } + $this->stream->close(); } diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php index 4ebb3fe0f..500924160 100644 --- a/tests/GridFS/BucketFunctionalTest.php +++ b/tests/GridFS/BucketFunctionalTest.php @@ -18,10 +18,12 @@ use function array_merge; use function call_user_func; use function current; +use function exec; use function fclose; use function fread; use function fwrite; use function hash_init; +use function implode; use function is_callable; use function min; use function sprintf; @@ -29,6 +31,7 @@ use function stream_get_contents; use function strlen; use function substr; +use const PHP_EOL; /** * Functional tests for the Bucket class. @@ -708,6 +711,21 @@ public function testExistingIndexIsReused() $this->assertIndexNotExists($this->chunksCollection->getCollectionName(), 'files_id_1_n_1'); } + public function testDanglingOpenWritableStream() + { + $path = __DIR__ . '/../../vendor/autoload.php'; + @exec( + <<test->selectGridFSBucket()->openUploadStream('filename', ['disableMD5' => true]);" 2>&1 +CMD, + $output + ); + + $output = implode(PHP_EOL, $output); + + $this->assertSame('', $output); + } + /** * Asserts that a collection with the given name does not exist on the * server. From 237f2fea5759bd7d34a7d1e82aea43a6e25c3628 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 1 Sep 2020 08:34:54 +0200 Subject: [PATCH 2/3] Apply feedback from code review --- src/GridFS/StreamWrapper.php | 2 +- tests/GridFS/BucketFunctionalTest.php | 12 ++++++++++-- 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/GridFS/StreamWrapper.php b/src/GridFS/StreamWrapper.php index d2034108a..a5136b349 100644 --- a/src/GridFS/StreamWrapper.php +++ b/src/GridFS/StreamWrapper.php @@ -60,7 +60,7 @@ class StreamWrapper public function __destruct() { /* This destructor is a workaround for PHP trying to use the stream well - * after all objects have been destructed. This causes autoloading + * after all objects have been destructed. This can cause autoloading * issues and possibly segmentation faults during PHP shutdown. */ $this->stream = null; } diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php index 500924160..00ecefe45 100644 --- a/tests/GridFS/BucketFunctionalTest.php +++ b/tests/GridFS/BucketFunctionalTest.php @@ -30,8 +30,10 @@ use function str_repeat; use function stream_get_contents; use function strlen; +use function strncasecmp; use function substr; use const PHP_EOL; +use const PHP_OS; /** * Functional tests for the Bucket class. @@ -713,14 +715,20 @@ public function testExistingIndexIsReused() public function testDanglingOpenWritableStream() { + if (! strncasecmp(PHP_OS, 'WIN', 3)) { + $this->markTestSkipped('Test does not apply to Windows'); + } + $path = __DIR__ . '/../../vendor/autoload.php'; @exec( <<test->selectGridFSBucket()->openUploadStream('filename', ['disableMD5' => true]);" 2>&1 +php -r "require '$path'; \\\$stream = (new MongoDB\Client)->test->selectGridFSBucket()->openUploadStream('filename', ['disableMD5' => true]);" 2>&1 CMD, - $output + $output, + $return ); + $this->assertSame(0, $return); $output = implode(PHP_EOL, $output); $this->assertSame('', $output); From 73803166f70b305fb934657cccf8831d05f63fc1 Mon Sep 17 00:00:00 2001 From: Andreas Braun Date: Tue, 1 Sep 2020 10:52:33 +0200 Subject: [PATCH 3/3] Extract HEREDOC code to variable to avoid phpcs issues --- tests/GridFS/BucketFunctionalTest.php | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/tests/GridFS/BucketFunctionalTest.php b/tests/GridFS/BucketFunctionalTest.php index 00ecefe45..0a8523812 100644 --- a/tests/GridFS/BucketFunctionalTest.php +++ b/tests/GridFS/BucketFunctionalTest.php @@ -720,10 +720,12 @@ public function testDanglingOpenWritableStream() } $path = __DIR__ . '/../../vendor/autoload.php'; - @exec( - <<test->selectGridFSBucket()->openUploadStream('filename', ['disableMD5' => true]);" 2>&1 -CMD, +CMD; + + @exec( + $command, $output, $return );