From d695cd81e0e79be2efae842a08ef2dcd74b09f49 Mon Sep 17 00:00:00 2001 From: Gina Peter Bnayard Date: Sat, 14 Sep 2024 17:00:32 +0200 Subject: [PATCH] ext/standard/dir.c: Directory class should behave like other opaque objects --- ext/standard/dir.c | 13 ++++++++ ext/standard/dir.stub.php | 6 +++- ext/standard/dir_arginfo.h | 4 +-- .../DirectoryClass_cannot_clone.phpt | 15 ++++++++++ .../DirectoryClass_cannot_construct.phpt | 14 +++++++++ .../DirectoryClass_cannot_serialize.phpt | 15 ++++++++++ .../directory/DirectoryClass_error_001.phpt | 27 ----------------- .../DirectoryClass_readonly_handle.phpt | 26 ++++++++++++++++ .../DirectoryClass_readonly_path.phpt | 26 ++++++++++++++++ ...flection_create_instance_no_construct.phpt | 30 +++++++++++++++++++ ... DirectoryClass_reflection_structure.phpt} | 20 +------------ 11 files changed, 147 insertions(+), 49 deletions(-) create mode 100644 ext/standard/tests/directory/DirectoryClass_cannot_clone.phpt create mode 100644 ext/standard/tests/directory/DirectoryClass_cannot_construct.phpt create mode 100644 ext/standard/tests/directory/DirectoryClass_cannot_serialize.phpt delete mode 100644 ext/standard/tests/directory/DirectoryClass_error_001.phpt create mode 100644 ext/standard/tests/directory/DirectoryClass_readonly_handle.phpt create mode 100644 ext/standard/tests/directory/DirectoryClass_readonly_path.phpt create mode 100644 ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt rename ext/standard/tests/directory/{DirectoryClass_basic_001.phpt => DirectoryClass_reflection_structure.phpt} (70%) diff --git a/ext/standard/dir.c b/ext/standard/dir.c index 1af6efe211a7e..06e3b5c9489ad 100644 --- a/ext/standard/dir.c +++ b/ext/standard/dir.c @@ -48,10 +48,17 @@ php_dir_globals dir_globals; #endif static zend_class_entry *dir_class_entry_ptr; +static zend_object_handlers dir_class_object_handlers; #define Z_DIRECTORY_PATH_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 0) #define Z_DIRECTORY_HANDLE_P(zv) OBJ_PROP_NUM(Z_OBJ_P(zv), 1) +static zend_function *dir_classd_get_constructor(zend_object *object) +{ + zend_throw_error(NULL, "Cannot directly construct Directory, use dir() instead"); + return NULL; +} + #define FETCH_DIRP() \ myself = getThis(); \ if (!myself) { \ @@ -115,6 +122,12 @@ PHP_MINIT_FUNCTION(dir) register_dir_symbols(module_number); dir_class_entry_ptr = register_class_Directory(); + dir_class_entry_ptr->default_object_handlers = &dir_class_object_handlers; + + memcpy(&dir_class_object_handlers, &std_object_handlers, sizeof(zend_object_handlers)); + dir_class_object_handlers.get_constructor = dir_classd_get_constructor; + dir_class_object_handlers.clone_obj = NULL; + dir_class_object_handlers.compare = zend_objects_not_comparable; #ifdef ZTS ts_allocate_id(&dir_globals_id, sizeof(php_dir_globals), NULL, NULL); diff --git a/ext/standard/dir.stub.php b/ext/standard/dir.stub.php index 6177d9fb590e6..1ceafdee0d9a0 100644 --- a/ext/standard/dir.stub.php +++ b/ext/standard/dir.stub.php @@ -87,7 +87,11 @@ */ const SCANDIR_SORT_NONE = UNKNOWN; -class Directory +/** + * @strict-properties + * @not-serializable + */ +final class Directory { public readonly string $path; diff --git a/ext/standard/dir_arginfo.h b/ext/standard/dir_arginfo.h index 47ab180ed7b17..017c961af562f 100644 --- a/ext/standard/dir_arginfo.h +++ b/ext/standard/dir_arginfo.h @@ -1,5 +1,5 @@ /* This is a generated file, edit the .stub.php file instead. - * Stub hash: 4b0f093770ff9a6cad9db033e0b62b412408b937 */ + * Stub hash: 3fdc106d96cf9e728886637eecdb43c2552b174f */ ZEND_BEGIN_ARG_WITH_TENTATIVE_RETURN_TYPE_INFO_EX(arginfo_class_Directory_close, 0, 0, IS_VOID, 0) ZEND_END_ARG_INFO() @@ -58,7 +58,7 @@ static zend_class_entry *register_class_Directory(void) zend_class_entry ce, *class_entry; INIT_CLASS_ENTRY(ce, "Directory", class_Directory_methods); - class_entry = zend_register_internal_class_with_flags(&ce, NULL, 0); + class_entry = zend_register_internal_class_with_flags(&ce, NULL, ZEND_ACC_FINAL|ZEND_ACC_NO_DYNAMIC_PROPERTIES|ZEND_ACC_NOT_SERIALIZABLE); zval property_path_default_value; ZVAL_UNDEF(&property_path_default_value); diff --git a/ext/standard/tests/directory/DirectoryClass_cannot_clone.phpt b/ext/standard/tests/directory/DirectoryClass_cannot_clone.phpt new file mode 100644 index 0000000000000..250c0ac0ac74b --- /dev/null +++ b/ext/standard/tests/directory/DirectoryClass_cannot_clone.phpt @@ -0,0 +1,15 @@ +--TEST-- +Cannot serialize instance of Directory class constructed via Reflection. +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Error: Trying to clone an uncloneable object of class Directory diff --git a/ext/standard/tests/directory/DirectoryClass_cannot_construct.phpt b/ext/standard/tests/directory/DirectoryClass_cannot_construct.phpt new file mode 100644 index 0000000000000..1d88b32036e4a --- /dev/null +++ b/ext/standard/tests/directory/DirectoryClass_cannot_construct.phpt @@ -0,0 +1,14 @@ +--TEST-- +Cannot directly instantiate Directory class. +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Error: Cannot directly construct Directory, use dir() instead diff --git a/ext/standard/tests/directory/DirectoryClass_cannot_serialize.phpt b/ext/standard/tests/directory/DirectoryClass_cannot_serialize.phpt new file mode 100644 index 0000000000000..32c169e892aff --- /dev/null +++ b/ext/standard/tests/directory/DirectoryClass_cannot_serialize.phpt @@ -0,0 +1,15 @@ +--TEST-- +Cannot serialize instance of Directory class constructed via Reflection. +--FILE-- +getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +Exception: Serialization of 'Directory' is not allowed diff --git a/ext/standard/tests/directory/DirectoryClass_error_001.phpt b/ext/standard/tests/directory/DirectoryClass_error_001.phpt deleted file mode 100644 index 251c6b64885f5..0000000000000 --- a/ext/standard/tests/directory/DirectoryClass_error_001.phpt +++ /dev/null @@ -1,27 +0,0 @@ ---TEST-- -Changing Directory::$handle property ---FILE-- -handle = "Havoc!"; -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} -var_dump($d->handle); - -$d = dir(getcwd()); -try { - unset($d->handle); -} catch (Error $e) { - echo $e->getMessage(), "\n"; -} -var_dump($d->handle); - -?> ---EXPECTF-- -Cannot modify readonly property Directory::$handle -resource(%d) of type (stream) -Cannot unset readonly property Directory::$handle -resource(%d) of type (stream) diff --git a/ext/standard/tests/directory/DirectoryClass_readonly_handle.phpt b/ext/standard/tests/directory/DirectoryClass_readonly_handle.phpt new file mode 100644 index 0000000000000..f3f70a6b22a16 --- /dev/null +++ b/ext/standard/tests/directory/DirectoryClass_readonly_handle.phpt @@ -0,0 +1,26 @@ +--TEST-- +Changing Directory::$handle property +--FILE-- +handle = "Havoc!"; +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +var_dump($d->handle); + +try { + unset($d->handle); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +var_dump($d->handle); + +?> +--EXPECTF-- +Error: Cannot modify readonly property Directory::$handle +resource(%d) of type (stream) +Error: Cannot unset readonly property Directory::$handle +resource(%d) of type (stream) diff --git a/ext/standard/tests/directory/DirectoryClass_readonly_path.phpt b/ext/standard/tests/directory/DirectoryClass_readonly_path.phpt new file mode 100644 index 0000000000000..1dcf8ac8e5225 --- /dev/null +++ b/ext/standard/tests/directory/DirectoryClass_readonly_path.phpt @@ -0,0 +1,26 @@ +--TEST-- +Changing Directory::$handle property +--FILE-- +path = "Havoc!"; +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +var_dump($d->path == __DIR__); + +try { + unset($d->path); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} +var_dump($d->path == __DIR__); + +?> +--EXPECTF-- +Error: Cannot modify readonly property Directory::$path +bool(true) +Error: Cannot unset readonly property Directory::$path +bool(true) diff --git a/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt b/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt new file mode 100644 index 0000000000000..35b07591635fd --- /dev/null +++ b/ext/standard/tests/directory/DirectoryClass_reflection_create_instance_no_construct.phpt @@ -0,0 +1,30 @@ +--TEST-- +Cannot use instance of Directory class constructed via Reflection. +--FILE-- +isInstantiable()); +try { + $d = $rc->newInstanceWithoutConstructor(); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +var_dump($d); +try { + var_dump($d->read()); +} catch (\Throwable $e) { + echo $e::class, ': ', $e->getMessage(), PHP_EOL; +} + +?> +--EXPECT-- +bool(true) +object(Directory)#2 (0) { + ["path"]=> + uninitialized(string) + ["handle"]=> + uninitialized(mixed) +} +Error: Unable to find my handle property diff --git a/ext/standard/tests/directory/DirectoryClass_basic_001.phpt b/ext/standard/tests/directory/DirectoryClass_reflection_structure.phpt similarity index 70% rename from ext/standard/tests/directory/DirectoryClass_basic_001.phpt rename to ext/standard/tests/directory/DirectoryClass_reflection_structure.phpt index c345ea30b84b4..76576d6922d46 100644 --- a/ext/standard/tests/directory/DirectoryClass_basic_001.phpt +++ b/ext/standard/tests/directory/DirectoryClass_reflection_structure.phpt @@ -11,20 +11,10 @@ echo "Structure of Directory class:\n"; $rc = new ReflectionClass("Directory"); echo $rc; -echo "Cannot instantiate a valid Directory directly:\n"; -$d = new Directory(getcwd()); -var_dump($d); - -try { - var_dump($d->read()); -} catch (\Error $e) { - echo $e->getMessage() . "\n"; -} - ?> --EXPECTF-- Structure of Directory class: -Class [ class Directory ] { +Class [ final class Directory ] { - Constants [0] { } @@ -63,11 +53,3 @@ Class [ class Directory ] { } } } -Cannot instantiate a valid Directory directly: -object(Directory)#%d (0) { - ["path"]=> - uninitialized(string) - ["handle"]=> - uninitialized(mixed) -} -Unable to find my handle property