php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #79921 memory exhausted, on array definition, in require
Submitted: 2020-08-01 08:21 UTC Modified: 2020-08-03 17:18 UTC
From: chandleg at wizardsworks dot org Assigned:
Status: Wont fix Package: Scripting Engine problem
PHP Version: 7.2.32 OS: Slackware Linux
Private report: No CVE-ID: None
Have you experienced this issue?
Rate the importance of this bug to you:

 [2020-08-01 08:21 UTC] chandleg at wizardsworks dot org
Description:
------------
I have a 10006 line "config" file, which is an array set for data values.
The format is: array(int, int, int, float, array, array, array)
Exerpt:

<?php
$star_map = array (
array(-587, 418, -182, 849.85998846869, array(2, 2), array(5.96541E+29, 5.96541E+29), array(278538822.144, 278538822.144),
array(-949, 457, -877, 1603.2251869279, array(2, 2), array(5.96541E+29, 5.96541E+29), array(278538822.144, 278538822.144),
array(1087, -401, 144, 1543.9799221492, array(2, 2), array(5.96541E+29, 5.96541E+29), array(278538822.144, 278538822.144),

........

array(-685, 113, -82, 972.20059658488, array(2), array(5.96541E+29), array(278538822.144),
array(554, 244, -57, 785.54503371863, array(2, 2), array(5.96541E+29, 5.96541E+29), array(278538822.144, 278538822.144),
array(1022, -77, -865, 1684.3969247182, array(2, 2), array(5.96541E+29, 5.96541E+29), array(278538822.144, 278538822.144),
);
?>


Test script:
---------------
<?php
require "./config.php";
?>

Expected result:
----------------
I would expect it to properly import the inline code.

Actual result:
--------------
redacted:~/public_html/game/tmp$ php index.php
PHP Parse error:  memory exhausted in ./chart.php on line 2500


Patches

Add a Patch

Pull Requests

Add a Pull Request

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2020-08-01 08:28 UTC] chandleg at wizardsworks dot org
I meant to mention the array format is variable
array of:
array(int, int, int, float, array, array, array)
Where each 3rd level array is of 1-3 elements, but the same number of elements of the other arrays in the 2nd level.

Also the 100006 line file is 1.2Meg.

It appears to be running out of stack/heap trying to load it, but I thought that arrays in PHP were unlimited size, the best calculation I have on this, is it should be around 22Meg in memory.

It's tossing "memory exhausted" in the parser, not in the running, so I'm wondering what the limit for either a require, or an array is.

I am fairly certain I have function files I include larger than 10,000 lines, and I am extremely certain I have arrays with element counts over 300,000.
 [2020-08-01 15:22 UTC] cmb@php.net
-Status: Open +Status: Feedback -Package: Unknown/Other Function +Package: Scripting Engine problem -Assigned To: +Assigned To: cmb
 [2020-08-01 15:22 UTC] cmb@php.net
Does that also happen with any of the actively supported PHP
versions[1]?

[1] <https://www.php.net/supported-versions.php>
 [2020-08-01 21:42 UTC] chandleg at wizardsworks dot org
-Status: Feedback +Status: Assigned
 [2020-08-01 21:42 UTC] chandleg at wizardsworks dot org
I genuinely don't know.  Of all the machines I have this one has the latest version of PHP installed.
I can drop the config file in a place to test, if someone who does have a machine laying around with a newer version installed wants to try.
 [2020-08-01 21:43 UTC] chandleg at wizardsworks dot org
Alternatively I can also post the code used to generate the file itself.
 [2020-08-02 09:56 UTC] cmb@php.net
-Status: Assigned +Status: Open -Assigned To: cmb +Assigned To:
 [2020-08-02 09:56 UTC] cmb@php.net
> Alternatively I can also post the code used to generate the file
> itself.

That may be helpful.
 [2020-08-03 05:13 UTC] chandleg at wizardsworks dot org
This will generate a config, one which should result in 10006 lines of output, which can be redirected to a file.
I run it: php create.php >config.php


<?php

$num_stars = 10000;
$star_map = array();

$width = 2500;
$height = 1000;
$x_origin = ( $width / 2 );
$y_origin = ( $height / 2 );

$sol_radius = 696347055.36;
$sol_mass = 1.98847 * pow(10, 30);
$light_year = 9.4607 * pow(10, 15);
$G = 6.67408 * pow(10, -11);
$c = 299792458;
#### BlackHole, Class D, Class M, Class K, Class, G, Class F, Class A, Class B, Class O
$star_radius = array(0, ( 2.765945676 * pow(10, -27) ), 0.4, 0.9, 1.1, 1.3, 2.5, 7, 15);
$star_mass = array(0, 1.4, 0.3, 0.8, 1.1, 1.7, 3.2, 18, 60);

#### 1-800 Binary, 801-819% Trinary, 820-900% Single
$star_systems_chart = array(array(1, 158), array(159, 979), array(980, 1000));

#### BlackHole, Class D, Class M, Class K, Class, G, Class F, Class A, Class B, Class O
$star_system_distribution_chart = array(array(1, 100000), array(100001, 150000), array(150001, 866964), array(866965, 936965), array(936966, 971996), array(971996, 991996), array(991997, 998997), array(998998, 999998), array(999999, 1000000));


#$star_colors = array( $BlackHole, $Neutron, $Class_M, $Class_K, $Class_G, $Class_F, $Class_A, $Class_B, $Class_O );

function find_in_chart ( $value, $chart )
  {
    for ( $x = 0; $x < count($chart); $x = $x + 1 )
      {
        if (( $value >= $chart[$x][0] ) and ( $value <= $chart[$x][1] ))
          {
            return $x;
          }
        else
          {
          }
      }
  }

function devation ( $value, $low, $high )
  {
    $dev = rand(( $low / 100 ), ( $high / 100 ));
    return ( $value + ( $value * $dev ) );
  }

function blackhole ( )
  {
    global $G, $c, $sol_radius, $sol_mass;
    $mass = ( rand(3, 70) * $sol_mass );
    $radius = (( 2 * $mass * $G ) / pow($c, 2));
    return array($mass, $radius);
  }

function array_output ( $tmp_array )
  {
    $tmp = "array(";
    foreach ( $tmp_array as $key => $value )
      {
        $tmp = $tmp . $value . ", ";
      }
    return trim($tmp, ", ") . "), ";
  }

echo "<?php\n\$star_map = array (\n";
for ( $x = 1; $x <= $num_stars; $x = $x + 1 )
  {
    $i = rand(( 1 - $x_origin ), $x_origin);
    $j = rand(( 1 - $y_origin ), $y_origin);
    $k = rand(-1000, 1000);
#### Calculate distance between origin and end of vector
    $distance = sqrt(pow($i, 2) + pow($i, 2) + pow($k, 2));
#### 1-800 Binary, 801-819% Trinary, 820-900% Single, 901-908 Neutron Star, 909-1000 BlackHole
    $star_system_count = rand(1, 1000);
    $stars = ( find_in_chart($star_system_count, $star_systems_chart) + 1 );
    $star_system = array();
    $masses = array();
    $radius = array();
    for ( $y = 1 ; $y <= $stars; $y = $y + 1 )
      {
#        $class = rand(0, 6);
####    Class
        $Class = find_in_chart(rand(1, 1000000), $star_system_distribution_chart);
        $star_system[$y] = $Class;
        if ( $Class != 0 )
          {
####        Mass
            $masses[$y] = devation($sol_mass * $star_mass[$Class], -10, 10);
####        Radius
            $radius[$y] = devation($sol_radius * $star_radius[$Class], -10, 10);
          }
        else
          {
            $tmp = blackhole();
            $masses[$y] = $tmp[0];
            $radius[$y] = $tmp[1];
          }
      }

    $star_map[] = array($i, $j, $k, $distance, $star_system, $masses, $radius);
    echo "array($i, $j, $k, $distance, ";
    echo array_output($star_system);
    echo array_output($masses);
    echo array_output($radius);
    echo "\n";
  }
echo ");\n?>\n"

?>
 [2020-08-03 08:48 UTC] nikic@php.net
-Status: Open +Status: Wont fix
 [2020-08-03 08:48 UTC] nikic@php.net
I can reproduce the issue with the provided script. The problem is that your generated code missing a ")," at the end of each line, which means that instead of generating a simple array of arrays, it generates a 10000-level deeply nested array, and the parser runs out of parser stack memory. Now we *could* raise YYMAXDEPTH from the default of 10000, but given that the generated code is incorrect (and would fail to parse anyway in the end), this example does not seem like a good motivation to do so.
 [2020-08-03 17:18 UTC] chandleg at wizardsworks dot org
You are completely correct, and I am _very_ sorry to have wasted your time...
I had the following code in there at some point, and through a revision change/merge it got stomped out...  I can't believe I didn't see that.

    echo array_output($masses);
    echo trim(array_output($radius), ", ");
    echo "),\n";
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Fri Mar 29 06:01:29 2024 UTC