2009-11-12 6 views
1

왜 다음과 같은 segfault가 있으며 어떻게 방지 할 수 있습니까?PHP regex segfault를 방지해야합니다.

<?php 

$str = ' <fieldset> <label for="go-to">Go to: </label> ' 
     . str_repeat(' ', 10000) 
     . '<input type="submit" value="Go" /> </fieldset> </form>'; 

preg_match_all("@ 
</?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags 
(?:[^<]|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* #allow text and some inline tags 
[\?\!\.]+ 
@ix", $str, $matches); 

?> 

나는 그것이 ...를 기다리고 있다고 생각합니다 .... 스택 오버플로.

편집 :

위의 단순화 된 버전이 문제를 보여줍니다 패턴입니다. 더 완전한 버전 :

@ 
</?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags 
(?:[^<]|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* # continue, allow text content and some inline tags 

# normal sentence ending 
[\?\!\.]+ # valid ending characters -- note elipses allowed 
(?<!\b[ap]m\.)(?<!\b[ap]\.m\.)(?<!digg this\!)(?<!Stumble This\!) # disallow some false positives that we don't care about 
\s* 
(?:&apos;|&\#0*34;|'|&lsquo;)?\s* # closing single quotes, in the unusual case like "he said: 'go away'". 
(?:"|&quot;|&\#0*34;|&\#x0*22;|&rdquo;|&\#0*8221;|&\#x0*201D;|''|``|\xe2\x80\x9d|&\#0*148;|&\#x0*94;|\x94|\))?\s* # followed by any kind of close-quote char 
(?=\<) # should be followed by a tag. 
@ix 

목적은 유효한 영어 문장 끝 모양처럼 보이는 것으로 끝나는 것처럼 보이는 html 블록을 찾는 것입니다. 나는이 방법이 '내용'텍스트 (기사 본문과 같은)와 '레이아웃'텍스트 (탐색 요소와 같음)의 차이를 말하는 데 매우 효과적이라는 것을 발견했습니다. 때로는 태그 사이에 방대한 양의 공백이있을 경우 블로깅됩니다.

+4

멋진 별명, ʞɔıu! – Boldewyn

+0

Intresting - 충돌을 재현 할 수 있습니다. 나는 당신이 충돌을 멈출 때까지 요소를 꺼내면서 정규 표현식을 해체 할 것을 제안한다. 그런 다음 충돌을 일으키는 요소를 취할 수 있는지 확인하고 segfaults 인 가장 간단한 예제를 만들고 bugs.php.net에 로그인하십시오. –

+3

정규식 엔진의 버그라고 생각하지 않습니다. 난 그냥 당신이 거꾸로 처리하는 거대한 스택을 구축하고 있다고 생각합니다. 아마 당신이 무엇을 잡으려고하는지 설명 할 수 있다면 우리는 더 적은 역 추적으로 대체 정규 표현을 제안 할 수 있습니다. –

답변

2

우선 소유 모든 한정사와 원자 모든 그룹을 만드는 것입니다 정규식 엔진은 백 트랙킹을 가능하게하기 위해 저장해야합니다. 정규 표현식은 역 추적해야한다면 어쨌든 실패 할 것입니다. 따라서 소유량 한정 기호와 원자 그룹을 사용하고 그 쓸데없는 정보를 모두 저장하지 않아도됩니다.

편집 : 그들은 비 마지막 아니라면

(?>[^<?!.]++|(?![^?!.\s<]++<)[?!.]++|</?+(?>(?>[bisau]|em|strong|sup)\b)[^>]*+>)*+ 

추가는, 하나 이상의 상기 문자와 일치 : 당신이 두 번째 줄에 다른 대안을 추가 할 수는 문장의 마침표를 허용하는 요소의 공백 문자.

+0

테스트하지는 않았지만 여기서 머리에 못을 박은 것 같습니다. (대개 정규 표현식에 동의하는 것이 안전하지만 ...) . –

+0

필자는 PHP의 정규식 (PCRE의 일부 버전)이 소유 그룹을 지원하지 않고 원자 그룹만을 지원한다고 생각합니다. 나는 당신이 제안한 패턴이 [^ <] ++가 [+!]. +를 마지막에 잡아서 되돌아 오는 것을 허용하지 않기 때문에 효과가있을 것이라고 믿지 않습니다. –

+0

또한 슬프게도 PHP의 정규 표현식이 가변 길이 lookbehinds를 허용하지 않는다고 생각합니다. 그렇지 않으면 단지'(? : [^ <] | .....) *) (? <= [?!] + ...)' –

0

그래도 원하는대로 할 수 있습니까?

</?(?![bisa]\b)(?!em\b)[^>]*> # starting tag, must not be one of several inline tags 
(?:(?>[^<\?\!\.]*)|</?(?:(?:[bisau]|em|strong|sup)\b)[^>]*>)* #allow text and some inline tags 
[\?\!\.]+ 
+0

Close, but quite : 이것은 결국 [?, \! \.] + 앞에 [?!.]를 허용하지 않습니다. 허용 하시겠습니까? –

+0

이 버전이 귀하의 것과 다른 경우 테스트 케이스를 제공 하시겠습니까? –

0

정규 표현식으로 인해 엄청난 양의 역 추적이 발생합니다. 중간에 10000자를 사용하면 꽤 지저분 해지고 느려질 것입니다. 아직도, 나는 그것이 추락 할 것을 기대하지 않을 것이다. ..!

"@</?+(?![bisa]\b)(?!em\b)[^>]*+> 
(?>[^<]++|</?+(?>(?>[bisau]|em|strong|sup)\b)[^>]*+>)*+ 
[?!.]+ 
@ix" 

나는 제레미의 권리를 생각 : 당신을 죽이고 자체을 되돌아 아니에요, 모든 상태 정보의 I 시도 할

+0

왜 충돌하지 않습니까? 스택이 아닌 다른 방법으로 역 추적을 처리 할 수 ​​있습니까? 스택이 사용 가능한 모든 메모리를 통해 화상을 입으면 어떻게됩니까? –

+0

나는 pcre의 스택 처리가 고정 된 크기이고 실제로는 비교적 작은 IIRC라고 생각한다. –

+0

나는 아직도 추락 할 것이라고 기대하지 않을 것이다. 공간이 부족할 때 실패합니다. 그렇지만 프로그램을 중단 시키시겠습니까? 아니. –

1

필자는 세그먼트 결함이 알려진 PCRE 7.0과 함께 최신 버전의 PHP가 번들로 포함되어 있음을 확신합니다. 필자는 기술적으로 PCRE 문제이므로 PHP 문제가 아니라 문제를 해결하기위한 의도가 있다고 생각하지 않습니다.

최선의 방법을 찾으려는 시도는 대체 표현식을 작성하는 것입니다.

버그는 다음과 같습니다. http://bugs.php.net/bug.php?id=40909