Skip to content

Commit 56c1d74

Browse files
committed
prevent instantiation and cloning of __PHP_Incomplete_Class
1 parent 96be28c commit 56c1d74

File tree

7 files changed

+87
-6
lines changed

7 files changed

+87
-6
lines changed

ext/standard/basic_functions.stub.php

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,6 +1487,8 @@
14871487
#[AllowDynamicProperties]
14881488
final class __PHP_Incomplete_Class
14891489
{
1490+
private function __construct() {}
1491+
private function __clone(): void {}
14901492
}
14911493

14921494
class AssertionError extends Error

ext/standard/basic_functions_arginfo.h

Lines changed: 14 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/basic_functions_decl.h

Lines changed: 4 additions & 4 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

ext/standard/incomplete_class.c

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,8 @@ static zend_object *php_create_incomplete_object(zend_class_entry *class_type)
111111
PHPAPI void php_register_incomplete_class_handlers(void)
112112
{
113113
memcpy(&php_incomplete_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
114+
115+
php_incomplete_object_handlers.get_constructor = incomplete_class_get_constructor;
114116
php_incomplete_object_handlers.read_property = incomplete_class_get_property;
115117
php_incomplete_object_handlers.has_property = incomplete_class_has_property;
116118
php_incomplete_object_handlers.unset_property = incomplete_class_unset_property;
@@ -122,6 +124,26 @@ PHPAPI void php_register_incomplete_class_handlers(void)
122124
}
123125
/* }}} */
124126

127+
/* {{{ Private constructor preventing instantiation */
128+
static ZEND_COLD zend_function *incomplete_class_get_constructor(zend_object *object) /* {{{ */
129+
{
130+
zend_throw_error(NULL, "Instantiation of class Closure is not allowed");
131+
return NULL;
132+
}
133+
134+
ZEND_COLD ZEND_METHOD(__PHP_Incomplete_Class, __construct)
135+
{
136+
zend_throw_error(NULL, "Instantiation of class __PHP_Incomplete_Class is not allowed");
137+
}
138+
/* }}} */
139+
140+
/* {{{ Private clone preventing cloning */
141+
ZEND_COLD ZEND_METHOD(__PHP_Incomplete_Class, __clone)
142+
{
143+
zend_throw_error(NULL, "Cannot clone __PHP_Incomplete_Class using __clone()");
144+
}
145+
/* }}} */
146+
125147
/* {{{ php_lookup_class_name */
126148
PHPAPI zend_string *php_lookup_class_name(zend_object *object)
127149
{
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
--TEST--
2+
__PHP_Incomplete_Class cannot be cloned
3+
--FILE--
4+
<?php
5+
$o = unserialize('O:3:"Foo":0:{}');
6+
var_dump($o::class);
7+
8+
$rc = new ReflectionClass("__PHP_Incomplete_Class");
9+
var_dump($rc->isCloneable());
10+
var_dump(clone($o));
11+
?>
12+
--EXPECTF--
13+
string(22) "__PHP_Incomplete_Class"
14+
bool(false)
15+
16+
Fatal error: Uncaught Error: Call to private method __PHP_Incomplete_Class::__clone() from global scope in %s:%d
17+
Stack trace:
18+
#0 {main}
19+
thrown in %s on line %d
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
--TEST--
2+
__PHP_Incomplete_Class cannot be instantiated
3+
--FILE--
4+
<?php
5+
var_dump(__PHP_Incomplete_Class::class);
6+
var_dump(new __PHP_Incomplete_Class());
7+
?>
8+
--EXPECTF--
9+
string(22) "__PHP_Incomplete_Class"
10+
11+
Fatal error: Uncaught Error: Call to private __PHP_Incomplete_Class::__construct() from global scope in %s:%d
12+
Stack trace:
13+
#0 {main}
14+
thrown in %s on line %d
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
--TEST--
2+
ReflectionClass::newInstanceWithoutConstructor cannot instantiate __PHP_Incomplete_Class
3+
--FILE--
4+
<?php
5+
$rc = new ReflectionClass("__PHP_Incomplete_Class");
6+
$rc->newInstanceWithoutConstructor();
7+
--EXPECTF--
8+
Fatal error: Uncaught ReflectionException: Class __PHP_Incomplete_Class is an internal class marked as final that cannot be instantiated without invoking its constructor in %s:%d
9+
Stack trace:
10+
#0 %s(%d): ReflectionClass->newInstanceWithoutConstructor()
11+
#1 {main}
12+
thrown in %s on line %d

0 commit comments

Comments
 (0)