From f355717c0e96c453eb5192b6bcf4ec96754720d6 Mon Sep 17 00:00:00 2001 From: Nikita Popov Date: Thu, 25 Jul 2019 11:16:14 +0200 Subject: [PATCH 1/4] Remove include "sanity check" to get better error Instead of rejecting directories / non-regular files early with a generic error, we should just accept them and error later when a read is attempted. This is more general and will generate a better error message. --- Zend/tests/require_directory.phpt | 14 ++++++++++++++ Zend/zend_language_scanner.l | 2 ++ ext/standard/tests/file/bug35740.phpt | 2 +- main/streams/plain_wrapper.c | 26 +------------------------- 4 files changed, 18 insertions(+), 26 deletions(-) create mode 100644 Zend/tests/require_directory.phpt diff --git a/Zend/tests/require_directory.phpt b/Zend/tests/require_directory.phpt new file mode 100644 index 0000000000000..f3c32aeb45944 --- /dev/null +++ b/Zend/tests/require_directory.phpt @@ -0,0 +1,14 @@ +--TEST-- +Including a directory generates an error +--FILE-- + +--EXPECTF-- +Notice: require(): read of %d bytes failed with errno=21 Is a directory in %s on line %d + +Fatal error: require(): Failed opening required '%s' (include_path='%s') in %s on line %d diff --git a/Zend/zend_language_scanner.l b/Zend/zend_language_scanner.l index 1537fa36f8ed7..30e7015e39f00 100644 --- a/Zend/zend_language_scanner.l +++ b/Zend/zend_language_scanner.l @@ -517,6 +517,8 @@ ZEND_API int open_file_for_scanning(zend_file_handle *file_handle) zend_string *compiled_filename; if (zend_stream_fixup(file_handle, &buf, &size) == FAILURE) { + /* Still add it to open_files so the file_handle destruction logic works correctly. */ + zend_llist_add_element(&CG(open_files), file_handle); return FAILURE; } diff --git a/ext/standard/tests/file/bug35740.phpt b/ext/standard/tests/file/bug35740.phpt index 29e8d8ebf83ec..8a84dfa73905e 100644 --- a/ext/standard/tests/file/bug35740.phpt +++ b/ext/standard/tests/file/bug35740.phpt @@ -8,7 +8,7 @@ include (__DIR__); echo "Done\n"; ?> --EXPECTF-- -Warning: include(%s): failed to open stream: %s in %s on line %d +Notice: include(): read of %s bytes failed with errno=21 Is a directory in %s on line %d Warning: include(): Failed opening '%s' for inclusion (include_path='%s') in %s on line %d Done diff --git a/main/streams/plain_wrapper.c b/main/streams/plain_wrapper.c index bce58f7df2b7e..3ccf6b838af38 100644 --- a/main/streams/plain_wrapper.c +++ b/main/streams/plain_wrapper.c @@ -128,7 +128,6 @@ typedef struct { unsigned is_pipe:1; /* don't try and seek */ unsigned cached_fstat:1; /* sb is valid */ unsigned is_pipe_blocking:1; /* allow blocking read() on pipes, currently Windows only */ - unsigned no_forced_fstat:1; /* Use fstat cache even if forced */ unsigned _reserved:28; int lock_flag; /* stores the lock state */ @@ -153,7 +152,7 @@ typedef struct { static int do_fstat(php_stdio_stream_data *d, int force) { - if (!d->cached_fstat || (force && !d->no_forced_fstat)) { + if (!d->cached_fstat || force) { int fd; int r; @@ -1084,30 +1083,7 @@ PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, zen efree(persistent_id); } - /* WIN32 always set ISREG flag */ #ifndef PHP_WIN32 - /* sanity checks for include/require. - * We check these after opening the stream, so that we save - * on fstat() syscalls */ - if (options & STREAM_OPEN_FOR_INCLUDE) { - php_stdio_stream_data *self = (php_stdio_stream_data*)ret->abstract; - int r; - - r = do_fstat(self, 0); - if ((r == 0 && !S_ISREG(self->sb.st_mode))) { - if (opened_path) { - zend_string_release_ex(*opened_path, 0); - *opened_path = NULL; - } - php_stream_close(ret); - return NULL; - } - - /* Make sure the fstat result is reused when we later try to get the - * file size. */ - self->no_forced_fstat = 1; - } - if (options & STREAM_USE_BLOCKING_PIPE) { php_stdio_stream_data *self = (php_stdio_stream_data*)ret->abstract; self->is_pipe_blocking = 1; From c65fb63d68675de36630a64cf841d38f32702e3d Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Sun, 31 Aug 2025 07:44:01 +0200 Subject: [PATCH 2/4] Fix typo in error message for require_directory test --- Zend/tests/require_directory.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Zend/tests/require_directory.phpt b/Zend/tests/require_directory.phpt index f3c32aeb45944..4fc776aadf88d 100644 --- a/Zend/tests/require_directory.phpt +++ b/Zend/tests/require_directory.phpt @@ -9,6 +9,6 @@ require $dir; ?> --EXPECTF-- -Notice: require(): read of %d bytes failed with errno=21 Is a directory in %s on line %d +Notice: require(): Read of %d bytes failed with errno=21 Is a directory in %s on line %d Fatal error: require(): Failed opening required '%s' (include_path='%s') in %s on line %d From a17c111dc0a29f5fef2a1a6acafff24ececf5a2f Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Sun, 31 Aug 2025 07:44:20 +0200 Subject: [PATCH 3/4] Fix notice message formatting in bug35740.phpt --- ext/standard/tests/file/bug35740.phpt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/ext/standard/tests/file/bug35740.phpt b/ext/standard/tests/file/bug35740.phpt index 8a84dfa73905e..993ebc6e15656 100644 --- a/ext/standard/tests/file/bug35740.phpt +++ b/ext/standard/tests/file/bug35740.phpt @@ -8,7 +8,7 @@ include (__DIR__); echo "Done\n"; ?> --EXPECTF-- -Notice: include(): read of %s bytes failed with errno=21 Is a directory in %s on line %d +Notice: include(): Read of %s bytes failed with errno=21 Is a directory in %s on line %d Warning: include(): Failed opening '%s' for inclusion (include_path='%s') in %s on line %d Done From 01c9744fba1bbc2b0ae54e597d445401311e414b Mon Sep 17 00:00:00 2001 From: Joe Watkins Date: Sun, 31 Aug 2025 08:04:12 +0200 Subject: [PATCH 4/4] Update error message in require_directory test --- Zend/tests/require_directory.phpt | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/Zend/tests/require_directory.phpt b/Zend/tests/require_directory.phpt index 4fc776aadf88d..2372853addfa2 100644 --- a/Zend/tests/require_directory.phpt +++ b/Zend/tests/require_directory.phpt @@ -11,4 +11,7 @@ require $dir; --EXPECTF-- Notice: require(): Read of %d bytes failed with errno=21 Is a directory in %s on line %d -Fatal error: require(): Failed opening required '%s' (include_path='%s') in %s on line %d +Fatal error: Uncaught Error: Failed opening required '%s' (include_path='.:') in %s:%d +Stack trace: +#0 {main} + thrown in %s on line %d