1

I have a simple infinite recursive code here:

<?php
    function test() {
        test();
    }

    test();

When I try to run the same, it eats up all the memory and eventually my laptop hangs. What I am looking for is a way to catch this and stop the machine from hanging. Is there any error handler in PHP for the same?

Things I have read and tried: setting max_execution_time to, let’s say, 5 seconds and catch the error line number. This didn’t work as proposed.

Is there another way to catch and stop this?

I am using Ubuntu 16.04.1 LTS (Xenial Xerus).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
  • What OS are you running on? – alexis Apr 10 '17 at 20:21
  • Ubuntu 16.04.1 LTS –  Apr 10 '17 at 20:26
  • 1
    There is something like "pcre.recursion_limit" http://php.net/manual/en/pcre.configuration.php#ini.pcre.recursion-limit but I'm not sure if there is any possibility to catch and handle this. Better solution maybe is counting the number of recursion calls passing it to the function and breaking it with a fixed value – quentino Apr 10 '17 at 20:31
  • With this simple test it executes so quickly that you exceed the memory limit before the time limit. If this function actually did something, even `echo` then it may well reach the time limit before exhausting memory. – AbraCadaver Apr 10 '17 at 20:35
  • [Sylwester's answer](https://stackoverflow.com/questions/43332276/how-can-i-stop-an-infinite-recursive-function-in-php-from-eating-all-the-availab/43332453#43332453) is a good one, but there must be a canonical question somewhere (this one was the only (relevant) one that turned up in a web search). What is the canonical question? – Peter Mortensen Oct 26 '21 at 17:15

3 Answers3

1

Limit the shell subprocess memory usage:

Since you state you use Ubuntu, you can limit the memory for your processes:

$ ulimit -v 500000
$ php -r 'function test() { test(); } test();'
mmap() failed: [12] Cannot allocate memory
mmap() failed: [12] Cannot allocate memory
PHP Fatal error:  Out of memory (allocated 304087040) (tried to allocate 262144 bytes) in Command line code on line 1

From PHP you can set the configuration option memory_limit:

$ php -r 'ini_set("memory_limit", "500MB"); function test() { test(); } test();'
PHP Fatal error:  Allowed memory size of 2097152 bytes exhausted (tried to allocate 262144 bytes) in Command line code on line 1

Now you can also edit the memory_limit in the default php.ini file or you can make a specific one for your script.

$ echo 'memory_limit = 500MB' > test.ini
$ php --php-ini test.ini -r 'function test() { test(); } test();'
Fatal error: Allowed memory size of 2097152 bytes exhausted (tried to allocate 262144 bytes) in Command line code on line 1

You might want to copy the default one instead of having one just providing that one option.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Sylwester
  • 47,942
  • 4
  • 47
  • 79
  • Any way to do the same inside php script? –  Apr 10 '17 at 20:37
  • @pata I've added two more methods that use PHP options. Hope it helps. – Sylwester Apr 10 '17 at 20:58
  • Thanks a lot. This will solve my current problem. But just out of curiosity, is there any error handler in php which can automatically throw exception when the loop exceeds memory ? –  Apr 10 '17 at 21:00
  • @pata I'm afraid not. Lots of PHP error levels cannot be handled by the scripts itself. This is one of them where it's natural that you cannot since you have no more memory to do so. – Sylwester Apr 10 '17 at 21:34
0

If you need to limit the memory (rather than the CPU time) eaten up by your PHP process, see this question.

If you specifically want to limit the number of recursive call levels you allow... that's a different question, and I don't know of a way. But I'm surprised this would be a problem, because according to this question, PHP already has a 100-level recursion limit which should be enough to stop your script before it eats up significant memory.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
alexis
  • 48,685
  • 16
  • 101
  • 161
0
<?php

    function test($tryCount=1){
         $tryCount++;
         //terminate recursive if more than 10 times loop
         if($tryCount > 10){
             return false;
         }
         test($tryCount);
    }
    test();
  • That will not help if *accidentally* introducing infinite recursion. The machine will effectively freeze. – Peter Mortensen Oct 26 '21 at 15:18
  • @PeterMortensen in the above code, how would one accidentally create infinite? I guess you could pass in a very low negative number (-10000000) etc. Otherwise why isn't it safe? – James Jul 15 '22 at 13:45