# Inconsistency between FETCH_DIM_IS and FETCH_OBJ_IS

- Thread: https://externals.io/message/24279
- Original archive: https://news-web.php.net/php.internals/24279
- Started by Sara Golemon on 2006-07-05T20:59:35+00:00
- Messages: 3
- Reply by email to internals@lists.php.net
- More for agents: search with https://externals.io/search.md?q={query} · JSON API at https://externals.io/api · documentation at https://externals.io/llms.txt

---

## #24279 — Sara Golemon — 2006-07-05T20:59:35+00:00

URL: https://externals.io/message/24279#24279

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

---

## #24280 — Marcus Boerger — 2006-07-06T00:43:36+00:00

URL: https://externals.io/message/24279#24280 · In reply to: #24279

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 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



Best regards,
 Marcus

---

## #24281 — Andi Gutmans — 2006-07-06T06:14:03+00:00

URL: https://externals.io/message/24279#24281 · In reply to: #24279

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_IS
> 
> 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
