Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Apache / PHP on Windows crashes with regular expression

I have discovered that the following PHP code crashes when it runs on a Windows Apache server:

<?php

$test = "0,4,447,11329,316,415,142,5262,6001,9527,11259,11236,1140,9770,9177,9043,11090,268,5270,9907,9196,10226,".
        "9399,1476,9368,6929,1659,11074,10869,8774,739,11344,10482,6399,8910,8997,11198,137,10148,10371,5128,767,2483,".
        "211,9973,10726,9299,778,11157,9497,275,9418,11141,241,5288,11324,776,10960,9289,7944,222,10686,11428,9723,".
        "10615,11399,9869,9083,10180,10043,9957,9387,9215,8869,9667,10174,10902,6607,9282,1259,395,10411,152,9344,8949,".
        "10923,8976,11042,11519,10704,10979,216,10044,9201,1721,5831,881,9721,1757,11054,1335,6151,9526,9081,111,498,".
        "2960,438,5313,206,318,10820,8192,6039,9161,11012,1717,1360,10757,4314,11280,9647,9346,10546,11006,9553,10365,".
        "6148,10565,4532,2776,4124,8853,6145,478,4539,540,9981,726,7186,11122,324,10524,1139,7900,9581,6869,1724,10851,".
        "10059,10018,11032,1290,3818,782,796,917,8740,6935,11439,10799,10948,249,2068,8778,6289,295,2766,9425,791,309,".
        "4753,10418,771,260,10835,10441,6434,10164,10475,10842,9013,11224,2247,8972,2141,2078,2152,475,9077,6291,10285,".
        "8067,753,6660,10889,431,2503,6007,9180,810,11447,2461,3689,7104,10150,10921,895,10598,747,10570,305,4497,11055,".
        "11496,10938,10722,8761,10086,11482,6780,6685,6918,10286,10659,9996,4074,9118,907,5192,283,2230,8884,6966,".
        "8820,8132,3598,9599,6796,11257,7049,5992,8637,4168,9017,7950,7165,10721,10037,1071,8044,759,11429,6380,".
        "10239,1593,9455,9704,10357,6737,2958,4051,9754,6564,11407,8716,7485,1528,6857,7406,9579,7259,1609,7820,".
        "4448,10289,1123,7005,8123,9316,914,9655,5280,9710,7822,510,10795,10476,8706,6160,8248,6978,9300,10643,".
        "7106,10250,519,7860,4733,904,8773,4714,8695,8633,6105,3312,11548,9580,10389,4886,4587,513,8485,4606,".
        "6471,581,526,637,3523,3772,3153,9336,9120,7633,3755,10087,524,10015,8563,556,1230,570,3652,569"
        .",8473,10209,3886,573,5363,4715,3865,9452,1218,7066,575,577,4724,7655"
        ;

$hest = preg_match('/^\d+(?:,\d+)+$/', $test);
var_dump($hest);
?>

Interestingly enough, the code works if the string is a little shorter - if I comment out the last part (line) of the string, the code runs and works as expected.

However, as the code is presented here, the code causes Apache to crash and respawn - no error is logged. If I try to run the code directly through PHP it works as expected, so the problem is somehow related to Apache.

I have experimented with the "pcre.recursion_limit" setting, and found that if I lower this to 689 it doesn't die, but instead the preg_match() call fails with a PREG_RECURSION_LIMIT_ERROR. For higher values of pcre.recursion_limit Apache dies.

Apache 2.2.11 PHP 5.3.0

I have also tested this on a Debian server where I do NOT see the error, and with different versions of PHP and Apache on Windows, where the error occurs as described above, so it seems that it may be Windows related.

Have anyone seens this before? I would really like a hint of some sort!

UPDATE: I is because of a "bug" in Apache for Windows - well, not really a bug, but it seems that Apache is compiled with a small stacksize, and that causes this error in PCRE when PHP uses it. See http://bugs.php.net/bug.php?id=47689

like image 416
AHM Avatar asked Aug 11 '10 09:08

AHM


2 Answers

It's always a good idea to lower "pcre.recursion_limit", because the default high value can corrupt the process stack (see http://php.net/manual/en/pcre.configuration.php) - this is exactly what happens with your mod_php install. Since preg functions don't throw an error when recursion/backtracking limits are reached, it may be useful to have a wrapper like

function match($re, $text) {
    preg_match($re, $text, $m);
    if(preg_last_error())
         trigger_error("preg: " . preg_last_error());
    return $m;
 }

At least, this lets you know when something goes wrong.

Besides that, try to simplify your patterns when possible, for example /^\d[\d,]*\d$/ does the same as above, but with zero recursion.

like image 140
user187291 Avatar answered Sep 28 '22 10:09

user187291


Increase the Apache stack and the problem will go away, or use the httpd config to increase it.

Most Apache builds have a way too small stack size while we have a normal one for the PHP builds. It explains why the same expressions will work in CLI and not in Apache (stack is per process and the process is owned/defined by Apache).

like image 36
Pierre Avatar answered Sep 28 '22 08:09

Pierre