When executing ZEND_FETCH_OBJ_IS on a non-object, the handler dispatches to zend_fetch_property_address_read_helper with type==BP_VAR_IS and ends up generating an error (isset() is supposed to be quiet) here:
if (Z_TYPE_P(container) != IS_OBJECT || !Z_OBJ_HT_P(container)->read_property) {
zend_error(E_NOTICE, "Trying to get property of non-object");
*retval = EG(uninitialized_zval_ptr);
SELECTIVE_PZVAL_LOCK(*retval, &opline->result);
AI_USE_PTR(EX_T(opline->result.u.var).var);
It's cousin ZEND_FETCH_DIM_IS winds up at zend_fetch_dimension_address() where the non-arrayness of op1 is handled via these case statements:
case IS_NULL: {
/* for read-mode only */
if (result) {
result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
PZVAL_LOCK(result->var.ptr_ptr);
}
if (type==BP_VAR_W || type==BP_VAR_RW) {
zend_error(E_WARNING, "Cannot use a NULL
value as an array");
}
break;
}
default: {
switch (type) {
case BP_VAR_UNSET:
zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
/ break missing intentionally */
case BP_VAR_R:
case BP_VAR_IS:
retval = &EG(uninitialized_zval_ptr);
break;
default:
retval = &EG(error_zval_ptr);
break;
}
if (result) {
result->var.ptr_ptr = retval;
PZVAL_LOCK(*result->var.ptr_ptr);
}
if (type==BP_VAR_W || type==BP_VAR_RW) {
zend_error(E_WARNING, "Cannot use a scalar value as an array");
}
}
Which indicate the expected behavior of silent failure. It's probably gone undetected till now as it requires fetching a property or dimension offset from a property in a third (non-object) variable within an isset() statement:
$foo = NULL;
isset($foo->bar->baz);
Unless someone can suggest why Objects should be noisy inside isset(), I'd like to suggest the following fix:
Index: Zend/zend_vm_def.h
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.120
diff -u -r1.120 zend_vm_def.h
--- Zend/zend_vm_def.h 13 Jun 2006 12:56:20 -0000 1.120
+++ Zend/zend_vm_def.h 5 Jul 2006 20:52:41 -0000
@@ -1176,7 +1176,9 @@
if (Z_TYPE_P(container) != IS_OBJECT || !Z_OBJ_HT_P(container)->read_property) {
-
zend_error(E_NOTICE, "Trying to get property of non-object");
-
if (type != BP_VAR_IS) {
-
zend_error(E_NOTICE, "Trying to get property of non-object");
-
} *retval = EG(uninitialized_zval_ptr); SELECTIVE_PZVAL_LOCK(*retval, &opline->result); AI_USE_PTR(EX_T(opline->result.u.var).var);
I suggest only excluding BP_VAR_IS since the matching behavior for unset()/DIM is to throw a notice. I could potentially see excluding BP_VAR_R in order to match read/DIM, but personally I never liked that behavior :)
-Sara
Hello Sara,
nice catch, fix looks pretty correct to me
best regards
marcus
Wednesday, July 5, 2006, 10:59:35 PM, you wrote:
When executing ZEND_FETCH_OBJ_IS on a non-object, the handler dispatches
to zend_fetch_property_address_read_helper with type==BP_VAR_IS and ends
up generating an error (isset() is supposed to be quiet) here:
if (Z_TYPE_P(container) != IS_OBJECT ||
!Z_OBJ_HT_P(container)->read_property) {
zend_error(E_NOTICE, "Trying to get property of non-object");
*retval = EG(uninitialized_zval_ptr);
SELECTIVE_PZVAL_LOCK(*retval, &opline->result);
AI_USE_PTR(EX_T(opline->result.u.var).var);
It's cousin ZEND_FETCH_DIM_IS winds up at zend_fetch_dimension_address()
where the non-arrayness of op1 is handled via these case statements:
case IS_NULL: {
/* for read-mode only */
if (result) {
result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
PZVAL_LOCK(result->var.ptr_ptr);
}
if (type==BP_VAR_W || type==BP_VAR_RW) {
zend_error(E_WARNING, "Cannot use aNULL
value as an array");
}
break;
}
default: {
switch (type) {
case BP_VAR_UNSET:
zend_error(E_WARNING, "Cannot unset offset in a non-array variable");
/ break missing intentionally */
case BP_VAR_R:
case BP_VAR_IS:
retval = &EG(uninitialized_zval_ptr);
break;
default:
retval = &EG(error_zval_ptr);
break;
}
if (result) {
result->var.ptr_ptr = retval;
PZVAL_LOCK(*result->var.ptr_ptr);
}
if (type==BP_VAR_W || type==BP_VAR_RW) {
zend_error(E_WARNING, "Cannot use a scalar value as an array");
}
}
Which indicate the expected behavior of silent failure. It's probably
gone undetected till now as it requires fetching a property or dimension
offset from a property in a third (non-object) variable within an isset() statement:
$foo = NULL;
isset($foo->bar->baz);
Unless someone can suggest why Objects should be noisy inside isset(),
I'd like to suggest the following fix:
Index: Zend/zend_vm_def.h
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.120
diff -u -r1.120 zend_vm_def.h
--- Zend/zend_vm_def.h 13 Jun 2006 12:56:20 -0000 1.120
+++ Zend/zend_vm_def.h 5 Jul 2006 20:52:41 -0000
@@ -1176,7 +1176,9 @@
if (Z_TYPE_P(container) != IS_OBJECT ||
!Z_OBJ_HT_P(container)->read_property) {
zend_error(E_NOTICE, "Trying to get property of non-object");
if (type != BP_VAR_IS) {
zend_error(E_NOTICE, "Trying to get property of non-object");
} *retval = EG(uninitialized_zval_ptr); SELECTIVE_PZVAL_LOCK(*retval, &opline->result); AI_USE_PTR(EX_T(opline->result.u.var).var);
I suggest only excluding BP_VAR_IS since the matching behavior for
unset()/DIM is to throw a notice. I could potentially see excluding
BP_VAR_R in order to match read/DIM, but personally I never liked that behavior :)
-Sara
Best regards,
Marcus
Looks good to me. Thanks!
-----Original Message-----
From: Sara Golemon [mailto:pollita@php.net]
Sent: Wednesday, July 05, 2006 2:00 PM
To: internals@lists.php.net
Subject: [PHP-DEV] Inconsistency between FETCH_DIM_IS and FETCH_OBJ_ISWhen executing ZEND_FETCH_OBJ_IS on a non-object, the handler
dispatches to zend_fetch_property_address_read_helper with
type==BP_VAR_IS and ends up generating an error (isset() is
supposed to be quiet) here:if (Z_TYPE_P(container) != IS_OBJECT ||
!Z_OBJ_HT_P(container)->read_property) {
zend_error(E_NOTICE, "Trying to get property of non-object");
*retval = EG(uninitialized_zval_ptr);
SELECTIVE_PZVAL_LOCK(*retval, &opline->result);
AI_USE_PTR(EX_T(opline->result.u.var).var);It's cousin ZEND_FETCH_DIM_IS winds up at
zend_fetch_dimension_address() where the non-arrayness of op1
is handled via these case statements:
case IS_NULL: {
/* for read-mode only */
if (result) {
result->var.ptr_ptr = &EG(uninitialized_zval_ptr);
PZVAL_LOCK(result->var.ptr_ptr);
}
if (type==BP_VAR_W || type==BP_VAR_RW) {
zend_error(E_WARNING, "Cannot use aNULL
value as an array");
}
break;
}
default: {
switch (type) {
case BP_VAR_UNSET:
zend_error(E_WARNING, "Cannot unset
offset in a non-array variable");
/ break missing intentionally */
case BP_VAR_R:
case BP_VAR_IS:
retval = &EG(uninitialized_zval_ptr);
break;
default:
retval = &EG(error_zval_ptr);
break;
}
if (result) {
result->var.ptr_ptr = retval;
PZVAL_LOCK(*result->var.ptr_ptr);
}
if (type==BP_VAR_W || type==BP_VAR_RW) {
zend_error(E_WARNING, "Cannot use a
scalar value as an array");
}
}Which indicate the expected behavior of silent failure. It's
probably gone undetected till now as it requires fetching a
property or dimension offset from a property in a third
(non-object) variable within an isset() statement:$foo = NULL;
isset($foo->bar->baz);Unless someone can suggest why Objects should be noisy inside
isset(), I'd like to suggest the following fix:Index: Zend/zend_vm_def.h
RCS file: /repository/ZendEngine2/zend_vm_def.h,v
retrieving revision 1.120
diff -u -r1.120 zend_vm_def.h
--- Zend/zend_vm_def.h 13 Jun 2006 12:56:20 -0000 1.120
+++ Zend/zend_vm_def.h 5 Jul 2006 20:52:41 -0000
@@ -1176,7 +1176,9 @@if (Z_TYPE_P(container) != IS_OBJECT ||
!Z_OBJ_HT_P(container)->read_property) {
zend_error(E_NOTICE, "Trying to get property
of non-object");
if (type != BP_VAR_IS) {
zend_error(E_NOTICE, "Trying to get
property of non-object");
} *retval = EG(uninitialized_zval_ptr); SELECTIVE_PZVAL_LOCK(*retval, &opline->result); AI_USE_PTR(EX_T(opline->result.u.var).var);
I suggest only excluding BP_VAR_IS since the matching
behavior for unset()/DIM is to throw a notice. I could
potentially see excluding BP_VAR_R in order to match
read/DIM, but personally I never liked that behavior :)-Sara