php.net |  support |  documentation |  report a bug |  advanced search |  search howto |  statistics |  random bug |  login
Bug #74158 closes connection abruptly
Submitted: 2017-02-23 22:46 UTC Modified: 2021-09-30 13:52 UTC
Votes:1
Avg. Score:3.0 ± 0.0
Reproduced:0 of 0 (0.0%)
From: teo8976 at gmail dot com Assigned: cmb (profile)
Status: Not a bug Package: Apache2 related
PHP Version: 5.6.30 OS: linux
Private report: No CVE-ID: None
 [2017-02-23 22:46 UTC] teo8976 at gmail dot com
Description:
------------
I do a curl to an url that runs a script on my server:

curl 'https://www.mydomain.com' -H 'accept-encoding: gzip, deflate, sdch, br' -H 'accept-language: en-US,en;q=0.8,ca;q=0.6,es;q=0.4,it;q=0.2,fr;q=0.2,pt;q=0.2,de;q=0.2' -H 'upgrade-insecure-requests: 1' -H 'authorization: Basic XXXXXXXX' -H 'accept: text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8' -H 'cache-control: max-age=0' -H 'authority: www.mydomain.com' -H 'cookie: [.....]' -H 'referer: https://www.mydomain.com/whatever' -H 'user-agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36' --compressed

And I get:

* GnuTLS recv error (-110): The TLS connection was non-properly terminated.
* Closing connection 0

before any header (or anything for that matter) is received.

The request is not even logged into Apache's access log on the server, nor any error logged to error_log.


No matter what my PHP code does and how huge an error it may contain, that is NEVER, EVER an acceptable outcome.



I have figured out that the error is somehow triggered by this function:


function fetch_product_dependencies($productid, &$dependency_list)
{
        if (!is_array($dependency_list["$productid"]))
        {
                return array();
        }

        $list = array();
        foreach ($dependency_list["$productid"] AS $subproductid)
        {
                // only traverse this branch if we haven't done it before -- prevent infinte recursion
                if (!isset($list["$subproductid"]))
                {
                        $list["$subproductid"] = $subproductid;
                        $list = array_merge(
                                $list,
                                fetch_product_dependencies($subproductid, $dependency_list)
                        );
                }
        }

        return $list;
}


The way I have figured that out with absolute certainty is by bisection, by putting a die("some output") statement before calling the function (exits and outputs "some output") and then moving it after the call to the function (reproduces the issue).

Expected result:
----------------
Either there is some error in my code or there isn't.

Either way, and no matter what my code does, php must always produce a valid HTTP response, be it an error or OK response, with or without content. It can't, under any circumstances, violate the protocol and/or fail to respond completely, or cause Apache to do so.

Also, the request must always be logged to Apache's access log (if Apache is configured to do so). Nothing in PHP can ever cause a request to not be logged at all.

Actual result:
--------------
The output of curl shows that the server fails to return a valid HTTP response. Apparently it closes the connection abruptly, violating even the TLS protocol.

I guess PHP is crashing or something.

Patches

Pull Requests

History

AllCommentsChangesGit/SVN commitsRelated reports
 [2017-02-23 22:56 UTC] teo8976 at gmail dot com
ERRATA:
  curl 'https://www.mydomain.com' -H ......

should read:
  curl 'https://www.mydomain.com/path/to/some/script.php' -H ......
 [2017-02-23 23:20 UTC] teo8976 at gmail dot com
Here's a PHP script that will systematically reproduce the issue:

<?php

function fetch_product_dependencies($productid, &$dependency_list)
{
    if (!is_array($dependency_list["$productid"]))
    {
            return array();
    }

    $list = array();
    foreach ($dependency_list["$productid"] AS $subproductid)
    {
            // only traverse this branch if we haven't done it before -- prevent infinte recursion
            if (!isset($list["$subproductid"]))
            {
                    $list["$subproductid"] = $subproductid;
                    $list = array_merge(
                            $list,
                            fetch_product_dependencies($subproductid, $dependency_list)
                    );
            }
    }
    return $list;
}

$dl=array(
'a'=>array('b', 'c'),
'b'=>array('c', 'd'),
'c'=>array('a'),
);

print_r(fetch_product_dependencies('a',$dl));
 [2017-02-23 23:26 UTC] teo8976 at gmail dot com
Even this one, much simpler!

  <?php
  
  function test(&$x) {
      test($x); 
  }
  $a=array();
  test($a);


Is this the same as https://bugs.php.net/bug.php?id=72568 ?
 [2021-09-29 15:51 UTC] cmb@php.net
-Status: Open +Status: Not a bug -Assigned To: +Assigned To: cmb
 [2021-09-29 15:51 UTC] cmb@php.net
This is infinite recursion, and should trigger an out of memory
condition (if you have a memory_limit set).  Anyhow, not a bug in
PHP, but rather in your script.
 [2021-09-30 13:41 UTC] php4fan at gmail dot com
> This is infinite recursion, and should trigger 
> an out of memory condition

And it does not. That is the bug.
 [2021-09-30 13:52 UTC] cmb@php.net
<https://3v4l.org/PYPvd> (PHP 7.4.0-7.4.2 is irrelevant)
 
PHP Copyright © 2001-2024 The PHP Group
All rights reserved.
Last updated: Thu Dec 26 12:01:30 2024 UTC