Lange Zend DB-Queries bringen PHP/Apache zum Absturz

Beim Programmieren einer Anwendung mit Zend und IBM DB2 bin ich auf ein Phänomen gestoßen, das zunächst unerklärlich schien. Führte ich einen langen Query aus (in diesem Fall sollte ein längerer XML-String in ein XML-Datenfeld der IBM DB2 Express-C geschrieben werden), so stürzte Apache ohne Fehlermeldung ab. In den Logs tauchte nur „restarting“ auf, sonst nichts.

Nach etwas Recherche stellte sich heraus, dass wohl eine fehlerhafte Implementierung der PCRE-Erweiterung Schuld an dem Desaster ist. Ist Backtracking auf einen zu hohen Wert eingestellt, so konsumiert PCRE (Zend Framework benutzt preg_match(), um SQL-Queries auf Korrektheit zu prüfen) den gesamten Stack, wodurch der Prozess sang- und klanglos abgeschossen wird.

Eine Erklärung zu PCRE-Backtracking gibt es hier: http://www.regular-expressions.info/catastrophic.html.

Für PHP ist die Lösung relativ simpel, der voreingestellte Wert von 100.000 für pcre.backtrack_limit und pcre.recursion_limit muss (entgegen einiger Aussagen in diversen Bugreports und Tutorials) heruntergesetzt werden. In meiner PHP.ini sieht das zurzeit folgendermaßen aus:

1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
[Pcre]
;PCRE library backtracking limit.
; http://php.net/pcre.backtrack-limit
pcre.backtrack_limit=1000
 
;PCRE library recursion limit.
;Please note that if you set this value to a high number you may consume all
;the available process stack and eventually crash PHP (due to reaching the
;stack size limit imposed by the Operating System).
; http://php.net/pcre.recursion-limit
pcre.recursion_limit=1000

Damit laufen meine Queries (~1800 Zeichen pro Query) anstandslos durch. Bei Bedarf kann dieser Wert auch weiter abgesenkt werden, auf 500 zum Beispiel. Da die PCRE-Funktion einen Aufwand von O(2^n) hat, bringt auch diese relativ kleine Änderung wieder recht viel.