2009-12-10 4 views
3

저는 두 개의 정규식을 사용하여 MySQL 쿼리에서 할당을 가져오고이를 사용하여 감사 내역을 만듭니다. 그들 중 하나는 따옴표 붙은 열 이름/etc를 요구하는 '까다로운'것이고, 다른 하나는 그렇지 않습니다.PHP의 preg-match_all은 Apache Segfault를 야기합니다.

둘 다 테스트되고 값을 올바르게 구문 분석합니다. 내가 겪고있는 문제는 특정 쿼리에서 '까다로운'regexp는 실제로 아파치를 segfault로 만드는 것입니다.

나는 이것이 코드에서 regexp를 떠나는 원인이었고, 조건부를 수정하여 실행되지 않았 음을 확인하기 위해 다양한 것을 시도했다. (어떤 종류의 컴파일 타임 이슈를 배제하기 위해서였다.). 문제 없음. 그것은 segfaults 특정 쿼리에 대해 정규식을 실행하는 경우에만, 그리고 왜 나에게 말해 어떤 명백한 패턴을 찾을 수 없습니다.

문제의 코드 :

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); 

둘 사이의 유일한 차이점은 첫 번째 그들을 비 선택하기 위해 따옴표에 물음표를 제거한다는 것이다 따옴표의 다른 종류를 사용하는 옵션을 제거 값에 - 작은 따옴표 만 허용합니다. 첫 번째 정규 표현식을 두 번째 정규 표현식으로 바꾸고 (테스트 목적으로) 동일한 데이터를 사용하면 문제가 해결됩니다. 확실히 정규 표현식과 관련이 있습니다. 내가 강조 표시된 부분을 제거 할 때, 모든 것이 잘 작동 흥미롭게
http://stackoverflow.pastebin.com/m75c2a2a0

: 나에게 슬픔의 원인이되는

특정 SQL은에서 확인할 수있다. 강조 표시된 섹션을 단독으로 제출하려고 시도하면 오류가 발생하지 않습니다.

나는 여기서 무슨 일이 일어나고 있는지 꽤 당황 스럽다. 누구든지 디버깅이나 수정에 대한 제안을 할 수 있습니까?

EDIT : 굉장히 흥분되는 일은 없지만 여기서는 Apache의 관련 로그 항목 (/var/log/apache2/error.log)이 있습니다. 사이트의 error.log에는 아무 것도 없습니다. 액세스 로그에서 요청).

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

해당 쿼리를 포함하는 요청마다이 중 하나가 필요합니다.

EDIT2 : Kuroki Kaze의 제안에 따라 나는 같은 길이의 횡설수설을 시도했고 같은 세그 폴트를 얻었다. 토 그리고 다른 길이의 뭉치를 시도하고 한계를 발견했습니다. 6035 문자가 정상적으로 작동합니다. 6036 segfaults.

EDIT3 : pcre.backtrack_limitpcre.recursion_limit의 값을 php.ini으로 변경하면 문제가 다소 완화됩니다. 아파치는 더 이상 segfaults가 아니지만, 내 regexp는 더 이상 문자열의 모든 일치 항목과 일치하지 않습니다.
http://bugs.php.net/bug.php?id=40909

EDIT4 : 분명히 이것은 PHP/PCRE에서 오랜 알려진 (2007) 버그는 내가 해결 방법은 허용하지 않았다 나는이 특정 정규 표현식을 대체하기 위해 사용되는 아래의 답변에서 코드를 게시 나의 목적 (판매용 제품, php.ini 변경 및 regexp가 부분적으로 만 작동하는 제거 된 기능 만 제공)은 보장 할 수 없습니다. 게시 된 코드는 어떤 종류의 보증이나 지원없이 공개 도메인으로 공개됩니다. 나는 그것이 다른 누군가를 도울 수 있기를 바랍니다. :)

도움을 주신 모든 분들께 감사드립니다.내가 강조 표시된 부분을 제거 할 때

아담 흥미롭게

답변

1

페이지를 저장하거나 자주 실행되지 않는 다른 작업을 수행 할 때 쿼리와 비교할 때만 필요하다는 점을 감안할 때 다음 코드의 성능 저하가 용인 될 수 있음을 느꼈습니다. SQL 쿼리 ($sql)를 파싱하고 이름 => 값 쌍을 $data에 배치합니다. 잘 작동하고 큰 쿼리를 잘 처리하는 것 같습니다.

  $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; 

모두에게 도움과 지침을 주셔서 감사합니다.

4

은 모두 잘 작동합니다. 강조 표시된 섹션을 단독으로 제출하려고 시도하면 오류가 발생하지 않습니다.

제출 크기는 어떻습니까? 똑같은 길이의 횡설수설을 지나치면 무슨 일이 일어날까요?

편집 : 분할 및 병합은 다음과 같이 보일 것입니다 :

$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]); 
} 
+0

또한 'preg' 기능이 현재 사용되지 않습니다. –

+2

아니요, thats ereg. – ryeguy

+1

전화하세요. 동일한 길이의 'X'문자열은 동일한 오류를 발생시킵니다. 나는 그걸 가지고 놀았고 정확히 6035 문자의 쿼리 길이가 잘 작동한다는 것을 알았다. 6036 segfaults. – NuclearDog

4

나는 비슷한는 preg_match 관련 문제, 같은 아파치는 segfault 명중되었다. 그것을 일으키는 preg_match만이 내가 사용하고있는 CMS (WordPress)에 내장되어 있습니다. 제공 하였다

"해결"는 php.ini 파일이 설정을 변경 하였다 :

[PCRE] ; PCRE 라이브러리 되돌아 제한. ; pcre.backtrack_limit = 100,000 pcre.recursion_limit = 200000000 = 100000000 pcre.backtrack_limit

절충 200 행> 제 경우 (큰 페이지를 렌더링하기위한 상기 열 중 하나가 한정 될 때 1500 자 텍스트 설명), CPU 사용률이 상당히 높아지고 여전히 세그 폴트가 표시됩니다. 그냥 자주.

내 사이트의 수명이 거의 다되었으므로 실제 솔루션을 찾기 위해 많은 예산이나 예산이 필요하지 않습니다. 그러나 이것이 현재보고있는 문제를 완화 할 수 있습니다.

+1

그 값을 올리면 문제가 완화되지는 않았지만 그 값은 떨어졌습니다. 불행히도 regexp는 긴 필드 (page_content)와 더 이상 일치하지 않습니다. segfault를 멈추는 것은 분명히 나에게 좋은 임시 작업이지만 감사합니다 :) PHP/PCRE에서 오랫동안 알려진 버그 인 것 같습니다. http://bugs.php.net/bug.php ? id = 40909 – NuclearDog

관련 문제