php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #62680 Function isset() throws fatal error on set array if non-existent key depth >= 3
Submitted: 2012-07-27 23:01 UTC Modified: 2012-08-25 07:24 UTC
Votes:3
Avg. Score:4.3 ± 0.9
Reproduced:3 of 3 (100.0%)
Same Version:1 (33.3%)
Same OS:3 (100.0%)
From: kriscraig@php.net Assigned: kriscraig (profile)
Status: Wont fix Package: Arrays related
PHP Version: 5.3.15 OS: Linux and Windows
Private report: No CVE-ID: None
 [2012-07-27 23:01 UTC] 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 />


Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2012-07-27 23:04 UTC] 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-28 07:34 UTC] laruence@php.net
-Status: Open +Status: Verified
 [2012-07-28 07:34 UTC] 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-30 18:27 UTC] 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-30 18:30 UTC] kriscraig@php.net
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.
 [2012-07-30 18:32 UTC] kriscraig@php.net
Woops, drop the word "ternary" from the description/title.  =)
 [2012-07-31 02:48 UTC] laruence@php.net
I'd like mark this as won't fix for 5.3, fixing this will be a big work IMO, maybe 
introduce new issues, and 5.3 is quite stable version now.
 [2012-08-25 07:19 UTC] kriscraig@php.net
@Laruence Sorry for the delay; they're keeping me busy up here!

Yeah I have no objection.  It really sucks but I have to agree.  Since it's fixed in 5.4, it really wouldn't be worth tearing into 5.3's guts just to correct this.

I'll go ahead and mark it "won't fix" for ya (as I try to think happy thoughts).  =)
 [2012-08-25 07:24 UTC] kriscraig@php.net
-Status: Verified +Status: Wont fix -Assigned To: +Assigned To: kriscraig
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Wed Dec 04 12:01:30 2024 UTC