From 120428feb575235ec369e08dec5d58cb0689e931 Mon Sep 17 00:00:00 2001 From: Jakub Zelenka Date: Thu, 16 Nov 2023 20:42:05 +0000 Subject: [PATCH] Fix bug #79945: Stream wrappers in imagecreatefrompng causes segfault Closes GH-12696 --- ext/gd/tests/bug79945.phpt | 22 ++++++++++++++++++++++ main/php_streams.h | 3 +++ main/streams/streams.c | 9 +++++++-- 3 files changed, 32 insertions(+), 2 deletions(-) create mode 100644 ext/gd/tests/bug79945.phpt diff --git a/ext/gd/tests/bug79945.phpt b/ext/gd/tests/bug79945.phpt new file mode 100644 index 0000000000000..b985ddd48be31 --- /dev/null +++ b/ext/gd/tests/bug79945.phpt @@ -0,0 +1,22 @@ +--TEST-- +Bug #79945 (using php wrappers in imagecreatefrompng causes segmentation fault) +--EXTENSIONS-- +gd +--SKIPIF-- + +--FILE-- + +--CLEAN-- +--EXPECTF-- + +Warning: imagecreatefrompng(): "php://filter/read=convert.base64-encode/resource=%s" is not a valid PNG file in %s on line %d diff --git a/main/php_streams.h b/main/php_streams.h index e7cbc7369ed45..0837472d2f6b9 100644 --- a/main/php_streams.h +++ b/main/php_streams.h @@ -211,6 +211,9 @@ struct _php_stream { * PHP_STREAM_FCLOSE_XXX as appropriate */ uint8_t fclose_stdiocast:2; + /* whether stdio cast flushing is in progress */ + int8_t fclose_stdiocast_flush_in_progress:1; + char mode[16]; /* "rwb" etc. ala stdio */ uint32_t flags; /* PHP_STREAM_FLAG_XXX */ diff --git a/main/streams/streams.c b/main/streams/streams.c index 4cd211ad85fe5..e1399927b2783 100644 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -1294,8 +1294,13 @@ PHPAPI zend_off_t _php_stream_tell(php_stream *stream) PHPAPI int _php_stream_seek(php_stream *stream, zend_off_t offset, int whence) { if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) { - /* flush to commit data written to the fopencookie FILE* */ - fflush(stream->stdiocast); + /* flush can call seek internally so we need to prevent an infinite loop */ + if (!stream->fclose_stdiocast_flush_in_progress) { + stream->fclose_stdiocast_flush_in_progress = 1; + /* flush to commit data written to the fopencookie FILE* */ + fflush(stream->stdiocast); + stream->fclose_stdiocast_flush_in_progress = 0; + } } /* handle the case where we are in the buffer */