Bug #62680 [Ver]: Function isset() throws fatal error on set array if non-existent key depth >= 3

From: Date: Mon, 30 Jul 2012 18:30:31 +0000
Subject: Bug #62680 [Ver]: Function isset() throws fatal error on set array if non-existent key depth >= 3
References: 1  Groups: php.bugs 
Request: Send a blank email to php-bugs+get-172340@lists.php.net to get a copy of this message
Edit report at https://bugs.php.net/bug.php?id=62680&edit=1

 ID:                 62680
 Updated by:         kriscraig@php.net
 Reported by:        kriscraig@php.net
 Summary:            Function isset() throws fatal error on set array if
                     non-existent key depth >= 3
 Status:             Verified
 Type:               Bug
 Package:            Arrays related
 Operating System:   Linux and Windows
 PHP Version:        5.3.15
 Block user comment: N
 Private report:     N

 New Comment:

Oh and here's the test case:

--TEST--
Test for existence of ternary isset() bug in nested arrays.
--DESCRIPTION--
Errors should not be thrown when passing non-set arguments to isset().
--CREDIT--
Kris Craig <kriscraig@php.net>
--FILE--
<?php

$arr = array( "key" => "", 
		"key2" => array( "subkey" => array( "supersubkey" => array(
"superdupersubkey" => "Hello." ) ) ), 
		"key3" => array( "subkey" => array( "supersubkey" =>
"Hello." ) ) );

if ( isset( $arr["key"]["non_existant_key"] ) )
{
	print "Arroooo?";
}

print "DEBUG #1.<br />\r\n";

$out = ( isset( $arr["key"]["non_existent_key"] ) ? "WTF?!" : NULL );

print "DEBUG #2.<br />\r\n";

foreach ( $arr as $key => $row )
{
	print ( isset( $row["subkey"]["supersubkey"] ) ?
$row["subkey"]["supersubkey"] . "<br />\r\n" : NULL );
}

print "DEBUG #3.<br />\r\n";

/* Ternaries.  --Kris */
print ( isset(
$some_non_existent_variable[0]["subkey"]["supersubkey"]["superdupersubkey"]
) ? "BAD<br />\r\n" : "OK<br />\r\n" );
print ( isset( $arr[0]["subkey"]["supersubkey"]["superdupersubkey"] )
? "BAD-0<br />\r\n" : "OK-0<br />\r\n" );
print ( isset(
$arr["key"]["subkey"]["supersubkey"]["superdupersubkey"] ) ?
"BAD-1<br />\r\n" : "OK-1<br />\r\n" );
print ( isset(
$arr["key2"]["subkey"]["supersubkey"]["superdupersubkey"] )
? "OK-2<br />\r\n" : "BAD-2<br />\r\n" );
print ( isset(
$arr["key3"]["subkey"]["supersubkey"]["superdupersubkey"] )
? "BAD-3<br />\r\n" : "OK-3<br />\r\n" );

/* Ifcheck.  --Kris */
if ( isset(
$arr["key"]["subkey"]["supersubkey"]["superdupersubkey"] ) )
{
	die( "Error : T_PAAMAYIM_NEKUDOTAYIM is too hard to pronounce!" );
}

print "DEBUG #4.<br />\r\n";

foreach ( $arr as $key => $row )
{
	print ( isset( $row["subkey"]["supersubkey"]["superdupersubkey"] ) ?
$row["subkey"]["supersubkey"]["superdupersubkey"] . "<br
/>\r\n" : NULL );
}

print "DEBUG #5.";

?>
--EXPECT--
DEBUG #1.<br />
DEBUG #2.<br />
Array<br />
Hello.<br />
DEBUG #3.<br />
OK-0<br />
OK-1<br />
OK-2<br />
OK-3<br />
DEBUG #4.<br />
Hello.<br />
DEBUG #5.


Previous Comments:
------------------------------------------------------------------------
[2012-07-30 18:27:15] kriscraig@php.net

Ahh ok.  Is this a won't fix then since it's not in 5.4?  Or is this still something
we'd want to correct?

Thanks!

------------------------------------------------------------------------
[2012-07-28 07:34:31] laruence@php.net

yeah, this is a issue in 5.3, while 5.4 have no such issue which is due to the 
fetch_dim_is behavior changed

------------------------------------------------------------------------
[2012-07-27 23:04:52] kriscraig@php.net

I'm still fairly new to the codebase compared to most of you karma folks, so if this looks like
something a relative newbie could handle, please point me in the right direction and I'd be
happy to just assign this one to myself.  It'll probably take way longer but I imagine it would
be a good learning experience for me if I had a little guidance to get me started.

Thanks!  =)

------------------------------------------------------------------------
[2012-07-27 23:01:29] kriscraig@php.net

Description:
------------
The test script sums it up pretty well.  Basically, if I pass an array with a missing key to
isset(), it's not supposed to throw an error.  After all, isset() is generally what people use
for those kinds of sanity checks where unexpected data might be returned.

However, I just noticed (completely by accident) that, if you're passing an array with a set
key followed by three or more missing keys to isset(), PHP will throw a fatal error and script
execution will terminate at that point.

What's particularly strange about this is that it only seems to occur if the top-level array
variable AND its first key are both set.  If I use the same depth on an undefined variable or on the
defined array but with the top-level key being undefined, it works just fine.

In the example, this would mean that $non_existent_variable[...][...][...][...] is fine and
$arr[0][...][...][...] is fine ($arr is defined but $arr[0] and $non_existent_variable are not). 
However, if I do $arr["key"][...][...][...], where $arr["key"] is defined but
the subsequent [...] keys are not, a fatal error is thrown.  That's clearly a bug.

In case anyone else encounters this before it's fixed, you can work around it by adding some
additional (albeit cluttery) sanity checks.  For example, if your $arr["key"] is not an
array and that's causing the error, simply add is_array( $arr["key"] ) to the ifcheck
prior to isset and that will allow your script to proceed without dying.

I've already created a PHPT case for this.  It'd probably be a good idea to add it to
run_tests, though I'm not entirely certain how/where to do that.

Looks like this bug was previously documented in 5.2.x (https://bugs.php.net/bug.php?id=44431), but
it was closed with a comment saying that it had been fixed (or at least couldn't be
repro'd) in 5.2.6.  So I'm guess either that person wasn't properly reproducing the
conditions of the bug somehow or this is a regression.

Tested on Windows 7 x86_64 and CentOS 5.8 x86_64.  In both cases, PHP version was 5.3.15 (VC9 ZTS
build on Windows).  Tested both via Apache/mod_php and CLI.  I have not tested this on 5.4 yet.  I
don't have a 5.4 environment handy at the moment, so if somebody else could repro this on that
version I'd be much obliged.  Thanks!

Test script:
---------------
<?php

$arr = array( "key" => "", 
		"key2" => array( "subkey" => array( "supersubkey" => array(
"superdupersubkey" => "Hello." ) ) ), 
		"key3" => array( "subkey" => array( "supersubkey" =>
"Hello." ) ) );

if ( isset( $arr["key"]["non_existant_key"] ) )
{
	print "Arroooo?";
}

print "DEBUG #1.<br />\r\n";

$out = ( isset( $arr["key"]["non_existant_key"] ) ? "WTF?!" : NULL );

print "DEBUG #2.<br />\r\n";

foreach ( $arr as $key => $row )
{
	print ( isset( $row["subkey"]["supersubkey"] ) ?
$row["subkey"]["supersubkey"] . "<br />\r\n" : NULL );
}

print "DEBUG #3.<br />\r\n";

if ( isset( $arr[0]["subkey"]["supersubkey"]["superdupersubkey"] ) )
{
	die( "Error : T_PAAMAYIM_NEKUDOTAYIM is too hard to pronounce!" );
}

print ( isset( $arr[0]["subkey"]["supersubkey"]["superdupersubkey"] )
? "BAD-0<br />\r\n" : "OK-0<br />\r\n" );
print ( isset(
$arr["key"]["subkey"]["supersubkey"]["superdupersubkey"] ) ?
"BAD-1<br />\r\n" : "OK-1<br />\r\n" );
print ( isset(
$arr["key2"]["subkey"]["supersubkey"]["superdupersubkey"] )
? "OK-2<br />\r\n" : "BAD-2<br />\r\n" );
print ( isset(
$arr["key3"]["subkey"]["supersubkey"]["superdupersubkey"] )
? "BAD-3<br />\r\n" : "OK-3<br />\r\n" );

print "DEBUG #4.<br />\r\n";

foreach ( $arr as $key => $row )
{
	print ( isset( $row["subkey"]["supersubkey"]["superdupersubkey"] ) ?
$row["subkey"]["supersubkey"]["superdupersubkey"] . "<br
/>\r\n" : NULL );
}

print "DEBUG #5.";

?>


Expected result:
----------------
DEBUG #1.<br />
DEBUG #2.<br />
Array<br />
Hello.<br />
DEBUG #3.<br />
OK<br />
OK-0<br />
OK-1<br />
OK-2<br />
OK-3<br />
DEBUG #4.<br />
Hello.<br />
DEBUG #5.


Actual result:
--------------
DEBUG #1.<br />
DEBUG #2.<br />
Array<br />
Hello.<br />
DEBUG #3.<br />
OK<br />
OK-0<br />
<br />
<b>Fatal error</b>:  Cannot use string offset as an array in <b>C:\Program Files
(x86)\Apache2.2\htdocs\test8.php</b> on line <b>28</b><br />



------------------------------------------------------------------------



-- 
Edit this bug report at https://bugs.php.net/bug.php?id=62680&edit=1


Thread (9 messages)

« previous php.bugs (#172340) next »