Skip to content

Commit

Permalink
Promote incomplete class to modification to Error
Browse files Browse the repository at this point in the history
In line with engine diagnostic promotions, property writes throw
an Error exception, while reads throw a warning.
  • Loading branch information
nikic committed Aug 28, 2020
1 parent f965e20 commit 32315c2
Show file tree
Hide file tree
Showing 5 changed files with 72 additions and 45 deletions.
24 changes: 18 additions & 6 deletions Zend/tests/bug71841.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,21 @@ Bug #71841 (EG(error_zval) is not handled well)
--FILE--
<?php
$z = unserialize('O:1:"A":0:{}');
@var_dump($z->e.=0);
@var_dump(++$z->x);
@var_dump($z->y++);
try {
var_dump($z->e.=0);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump(++$z->x);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
try {
var_dump($z->y++);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}

$y = array(PHP_INT_MAX => 0);
try {
Expand All @@ -25,9 +37,9 @@ try {
}
?>
--EXPECT--
NULL
NULL
NULL
The script tried to modify a property on an incomplete object. Please ensure that the class definition "A" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition
The script tried to modify a property on an incomplete object. Please ensure that the class definition "A" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition
The script tried to modify a property on an incomplete object. Please ensure that the class definition "A" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition
Cannot add element to the array as the next element is already occupied
Cannot add element to the array as the next element is already occupied
Cannot add element to the array as the next element is already occupied
26 changes: 13 additions & 13 deletions ext/standard/incomplete_class.c
Original file line number Diff line number Diff line change
Expand Up @@ -19,8 +19,7 @@
#include "php_incomplete_class.h"

#define INCOMPLETE_CLASS_MSG \
"The script tried to execute a method or " \
"access a property of an incomplete object. " \
"The script tried to %s on an incomplete object. " \
"Please ensure that the class definition \"%s\" of the object " \
"you are trying to operate on was loaded _before_ " \
"unserialize() gets called or provide an autoloader " \
Expand All @@ -29,28 +28,29 @@
PHPAPI zend_class_entry *php_ce_incomplete_class;
static zend_object_handlers php_incomplete_object_handlers;

static void incomplete_class_message(zend_object *object, int error_type)
static void incomplete_class_message(zend_object *object)
{
zend_string *class_name = php_lookup_class_name(object);
php_error_docref(NULL, error_type, INCOMPLETE_CLASS_MSG,
class_name ? ZSTR_VAL(class_name) : "unknown");
php_error_docref(NULL, E_WARNING, INCOMPLETE_CLASS_MSG,
"access a property", class_name ? ZSTR_VAL(class_name) : "unknown");
if (class_name) {
zend_string_release_ex(class_name, 0);
}
}

static void throw_incomplete_class_error(zend_object *object)
static void throw_incomplete_class_error(zend_object *object, const char *what)
{
zend_string *class_name = php_lookup_class_name(object);
zend_throw_error(NULL, INCOMPLETE_CLASS_MSG, class_name ? ZSTR_VAL(class_name) : "unknown");
zend_throw_error(NULL, INCOMPLETE_CLASS_MSG,
what, class_name ? ZSTR_VAL(class_name) : "unknown");
if (class_name) {
zend_string_release_ex(class_name, 0);
}
}

static zval *incomplete_class_get_property(zend_object *object, zend_string *member, int type, void **cache_slot, zval *rv) /* {{{ */
{
incomplete_class_message(object, E_NOTICE);
incomplete_class_message(object);

if (type == BP_VAR_W || type == BP_VAR_RW) {
ZVAL_ERROR(rv);
Expand All @@ -63,34 +63,34 @@ static zval *incomplete_class_get_property(zend_object *object, zend_string *mem

static zval *incomplete_class_write_property(zend_object *object, zend_string *member, zval *value, void **cache_slot) /* {{{ */
{
incomplete_class_message(object, E_NOTICE);
throw_incomplete_class_error(object, "modify a property");
return value;
}
/* }}} */

static zval *incomplete_class_get_property_ptr_ptr(zend_object *object, zend_string *member, int type, void **cache_slot) /* {{{ */
{
incomplete_class_message(object, E_NOTICE);
throw_incomplete_class_error(object, "modify a property");
return &EG(error_zval);
}
/* }}} */

static void incomplete_class_unset_property(zend_object *object, zend_string *member, void **cache_slot) /* {{{ */
{
incomplete_class_message(object, E_NOTICE);
throw_incomplete_class_error(object, "modify a property");
}
/* }}} */

static int incomplete_class_has_property(zend_object *object, zend_string *member, int check_empty, void **cache_slot) /* {{{ */
{
incomplete_class_message(object, E_NOTICE);
incomplete_class_message(object);
return 0;
}
/* }}} */

static zend_function *incomplete_class_get_method(zend_object **object, zend_string *method, const zval *key) /* {{{ */
{
throw_incomplete_class_error(*object);
throw_incomplete_class_error(*object, "call a method");
return NULL;
}
/* }}} */
Expand Down
13 changes: 8 additions & 5 deletions ext/standard/tests/serialize/incomplete_class.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,11 @@ $d = serialize(new __PHP_Incomplete_Class);
$o = unserialize($d);
var_dump($o);

$o->test = "a";
try {
$o->test = "a";
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
var_dump($o->test);
var_dump($o->test2);

Expand All @@ -16,12 +20,11 @@ echo "Done\n";
--EXPECTF--
object(__PHP_Incomplete_Class)#%d (0) {
}
The script tried to modify a property on an incomplete object. Please ensure that the class definition "unknown" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "unknown" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "unknown" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
Warning: main(): The script tried to access a property on an incomplete object. Please ensure that the class definition "unknown" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
NULL

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "unknown" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
Warning: main(): The script tried to access a property on an incomplete object. Please ensure that the class definition "unknown" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
NULL
Done
52 changes: 32 additions & 20 deletions ext/standard/tests/serialize/serialization_objects_005.phpt
Original file line number Diff line number Diff line change
Expand Up @@ -34,18 +34,34 @@ var_dump($incomplete);
var_dump(is_object($incomplete));
var_dump($incomplete->p);

$ref2 = "ref1.original";
$incomplete->p = &$ref2;
try {
$ref2 = "ref1.original";
$incomplete->p = &$ref2;
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
var_dump($incomplete->p);
$ref2 = "ref1.changed";
var_dump($incomplete->p);
$incomplete->p = "p.changed";
try {
$incomplete->p = "p.changed";
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
var_dump($ref1);

var_dump(isset($incomplete->x));
$incomplete->x = "x.new";
try {
$incomplete->x = "x.new";
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
var_dump(isset($incomplete->x));
unset($incomplete->x);
try {
unset($incomplete->x);
} catch (Error $e) {
echo $e->getMessage(), "\n";
}
var_dump($incomplete->x);

try {
Expand Down Expand Up @@ -83,31 +99,27 @@ object(__PHP_Incomplete_Class)#%d (2) {
}
bool(true)

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
Warning: main(): The script tried to access a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
NULL
The script tried to modify a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
Warning: main(): The script tried to access a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
NULL

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
Warning: main(): The script tried to access a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
NULL

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
The script tried to modify a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition
string(9) "p.changed"

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
Warning: main(): The script tried to access a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
bool(false)
The script tried to modify a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
Warning: main(): The script tried to access a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
bool(false)
The script tried to modify a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
Warning: main(): The script tried to access a property on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
NULL
The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition
The script tried to call a method on an incomplete object. Please ensure that the class definition "C" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition
Done
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,6 @@ echo "Done";
object(__PHP_Incomplete_Class)#%d (0) {
}

Notice: main(): The script tried to execute a method or access a property of an incomplete object. Please ensure that the class definition "unknown" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
Warning: main(): The script tried to access a property on an incomplete object. Please ensure that the class definition "unknown" of the object you are trying to operate on was loaded _before_ unserialize() gets called or provide an autoloader to load the class definition in %s on line %d
NULL
Done

0 comments on commit 32315c2

Please sign in to comment.