Apache segfault neden PHP'nin gebelik match_all

3 Cevap php

MySQL sorguları dışarı atamaları çekmek için iki düzenli ifadeler kullanarak ve bir denetim izi oluşturmak için bunları kullanıyorum. Bunlardan biri alıntı sütun adları / etc gerektirir 'seçici biridir., Diğeri değil.

Her ikisi de test edilmiş ve doğru değerleri ayrıştırmak edilir. Ben yaşıyorum sorun, belirli bir sorgu ile 'seçici' sıradanifade aslında sadece Apache segfault neden olmasıdır.

Ben bu kodu regexpi bırakarak ve sadece (derleme zaman sorunu falan çeşit ekarte etmek için) çalıştırmak değildi sağlamak için koşullu değiştirerek kadar neden oldu belirlemek için çeşitli şeyler denedik. Sorunları yok. O çalışma sırasında parçalama arızası belirli sorguların karşı regexpi çalışır, ve ben neden bana söylemek için herhangi belirgin bir desen bulamıyorum sadece bu kadar.

Söz konusu kod:

if ($picky)
    preg_match_all("/[`'\"]((?:[A-Z]|[a-z]|_|[0-9])+)[`'\"] *= *'((?:[^'\\\\]|\\\\.)*)'/", $sql, $matches);
else
    preg_match_all("/[`'\"]?((?:[A-Z]|[a-z]|_|[0-9])+)[`'\"]? *= *[`'\"]?([^`'\" ,]+)[`'\"]?/", $sql, $matches);

Sadece tek tırnak sağlar - İkisi arasındaki tek fark, ilki onları olmayan isteğe yapmak için tırnak üzerindeki soru işaretlerini kaldırır ve değeri tırnak farklı kullanma seçeneği kaldırır. (Deneme amaçlı) ile ikinci ilk regexpi değiştirilmesi ve aynı verileri kullanarak sorunu ortadan kaldırır - bu regexp ile ilgisi definitely şeydir.

The specific SQL that is causing me grief is available at:
http://stackoverflow.pastebin.com/m75c2a2a0

Ben Vurgulanan bölümü kaldırdığınızda İlginçtir ki, bu tüm çalışıyor. Kendisi tarafından vurgulanmış bir bölüm sunmaya çalışırken hiçbir hata neden olur.

Ben çok burada oluyor ne kadar çapraşık ediyorum. Herkes daha fazla hata ayıklama veya bir düzeltme olarak herhangi bir öneri sunabilir?

EDIT: derece heyecan verici bir şey, ama bütünlüğü uğruna burada Apache (/ var/log/apache2/error.log itibaren ilgili günlük girdisi - hiçbir şey sitenin error.log var erişim isteği bile bir söz. log.)

[Thu Dec 10 10:08:03 2009] [notice] child pid 20835 exit signal Segmentation fault (11)

Bu sorguyu içeren her istek için Bunlardan biri.

EDIT2: Kuroki Kaze önerisiyle, ben aynı uzunlukta anlamsız çalıştı ve aynı segfault var. Oturdu ve farklı uzunluklarda bir demet denedim ve sınırı bulundu. 6035 karakterler çalışıyor. 6036 sırasında parçalama arızası.

EDIT3: Changing the values of pcre.backtrack_limit and pcre.recursion_limit in php.ini mitigated the problem somewhat. Apache no longer segfaults, but my regexp no longer matches all of the matches in the string. Apparently this is a long-known (from 2007) bug in PHP/PCRE:
http://bugs.php.net/bug.php?id=40909

Edit4: Ben geçici çözümler benim amaç satılık (ürün için kabul edilemez olduğu gibi bu özel düzenli ifadeyi değiştirmek için kullanılan aşağıda cevapları kod gönderdiniz, php.ini değişiklikleri garanti ve sıradanifade sadece kısmen kaldırıldı işlevselliği çalışma olamaz biz) gerektirir. Ben yayınlanmıştır kodu herhangi bir garanti veya destek ile kamusal alana çıktı. Ben başkası yardımcı olabilir umuyoruz. :)

Yardımlarınız için herkese teşekkürler!

Adem

3 Cevap

Sayfaları kaydetme veya diğer çok sık-idam değil işlemleri gerçekleştirirken, ben aşağıdaki kodun performans isabet kabul edilebilir olduğunu hissettim bu sadece sorguları karşı maç ihtiyacı göz önüne alındığında. Bu SQL sorgusu ayrıştırır ($sql) ve $data içine yerler isim => değer çiftleri. Iyi çalışıyor gibi görünüyor ve ince büyük sorguları işler.

			$quoted = '';
			$escaped = false;

			$key = '';
			$value = '';
			$target = 'key';

			for ($i=0; $i<strlen($sql); $i++)
			{
				if ($escaped)
				{
					$$target .= $sql[$i];
					$escaped = false;
				}
				else if ($quoted!='')
				{
					if ($sql[$i]=='\\')
						$escaped = true;
					else if ($sql[$i]==$quoted)
						$quoted = '';
					else
						$$target .= $sql[$i];
				}
				else
				{
					if ($sql[$i]=='\'' || $sql[$i]=='`')
					{
						$quoted = $sql[$i];
						$$target = '';
					}
					else if ($sql[$i]=='=')
						$target = 'value';
					else if ($sql[$i]==',')
					{
						$target = 'key';
						$data[$key] = $value;
						$key = '';
						$value = '';
					}
				}
			}

			if ($value!='')
				$data[$key] = $value;

Yardım ve yön için herkese teşekkürler!

Ben benzer bir preg_match alakalı konuda, aynı Apache segfault ile vurmak olmuştur. Neden sadece preg_match o entegre olduğunda ben kullanıyorum CMS (WordPress).

Teklif edildi "geçici çözüm" php.ini bu ayarları değiştirmek oldu:

[Pcre] ;PCRE library backtracking limit. ;pcre.backtrack_limit=100000 pcre.recursion_limit=200000000 pcre.backtrack_limit=100000000

Trade-off büyük sayfaları, render için (benim durumumda,> 200 satır, sütun biri 1500 karakter metin açıklaması ile sınırlı olduğunda), oldukça yüksek CPU kullanımı alırsınız, ve ben hala görüyorum sırasında parçalama arızası. Adil değil gibi sık sık.

Ömrünün-sonuna, bu yüzden gerçekten çok ihtiyacı (veya bütçe) yok sitemin yakın bir gerçek çözüm aramak. Ama belki bu görüyoruz sorunu azaltabilir.

Ben Vurgulanan bölümü kaldırdığınızda İlginçtir ki, bu tüm çalışıyor. Kendisi tarafından vurgulanmış bir bölüm sunmaya çalışırken hiçbir hata neden olur.

Ne teslim boyutu hakkında? Eşit uzunlukta anlamsız geçerseniz, ne olacak?

EDIT: bölme ve birleştirme bu gibi bir şey olacaktır:

$strings = explode("\n", $sql);

$matches = array(array(), array(), array());

foreach ($strings AS $string) {
	preg_match_all("/[`'\"]?((?:[A-Z]|[a-z]|_|[0-9])+)[`'\"]? *= *[`'\"]?([^`'\" ,]+)[`'\"]?/", $string, $matches_temp);
	$matches[0] = array_merge($matches[0], $matches_temp[0]);
	$matches[1] = array_merge($matches[1], $matches_temp[1]);
	$matches[2] = array_merge($matches[2], $matches_temp[2]);
}