The problem described here occurs both in 4.2.3RC2 & 4.3.0-dev.
The attached patch is against  4.3.0-dev (HEAD) and as far as my testing shows 
addresses the problem.

The source of the segfault is a buffer overflow that results when estimated 
number of times the separator will be inserted is less the then actual 
number.  There is no 'true' way of checking the number of separators to be 
inserted, since this number will often depend on the data contained in the 
string itself. So, the solution is to add a check that will reallocate more 
memory if the initial estimate on the string size proves to be incorrect.

Unless, there are better solutions as alternatives to the patch or any strong 
objections I'll commit this patch to both 4.2.3RC2 & 4.3.0-dev in the 
morning.

Ilia

P.S.
The segv can be replicated by the attached php script (segfault-4.2.3RC2.txt) 
submitted by Martin Jansen.
Index: string.c
===================================================================
RCS file: /repository/php4/ext/standard/string.c,v
retrieving revision 1.286
diff -u -3 -p -r1.286 string.c
--- string.c	25 Aug 2002 19:08:07 -0000	1.286
+++ string.c	5 Sep 2002 01:47:59 -0000
@@ -595,7 +595,7 @@ PHP_FUNCTION(wordwrap)
 	const char *text, *breakchar = "\n";
 	char *newtext;
 	int textlen, breakcharlen = 1, newtextlen;
-	long current = 0, laststart = 0, lastspace = 0;
+	long current = 0, laststart = 0, lastspace = 0, mem_alloced = 0;
 	long linelength = 75;
 	zend_bool docut = 0;
 
@@ -646,6 +646,7 @@ PHP_FUNCTION(wordwrap)
 			newtextlen = textlen * (breakcharlen + 1) + 1;
 		}
 		newtext = emalloc(newtextlen);
+		mem_alloced = newtextlen;
 
 		/* now keep track of the actual new text length */
 		newtextlen = 0;
@@ -657,6 +658,12 @@ PHP_FUNCTION(wordwrap)
 			if (text[current] == breakchar[0]
 				&& current + breakcharlen < textlen
 				&& !strncmp(text+current, breakchar, breakcharlen)) {
+				
+				if ((newtextlen+current-laststart+breakcharlen) >= mem_alloced) {
+					mem_alloced += textlen-current+((textlen-current)/linelength + 1) * breakcharlen + 1;
+					newtext = erealloc(newtext, mem_alloced);
+				}
+				
 				memcpy(newtext+newtextlen, text+laststart, current-laststart+breakcharlen);
 				newtextlen += current-laststart+breakcharlen;
 				current += breakcharlen - 1;
@@ -666,6 +673,11 @@ PHP_FUNCTION(wordwrap)
 			 * copy and insert a break, or just keep track of it */
 			else if (text[current] == ' ') {
 				if (current - laststart >= linelength) {
+					if ((newtextlen+current-laststart+breakcharlen) >= mem_alloced) {
+						mem_alloced += textlen-current+((textlen-current)/linelength + 1) * breakcharlen + 1;
+						newtext = erealloc(newtext, mem_alloced);
+					}
+
 					memcpy(newtext+newtextlen, text+laststart, current-laststart);
 					newtextlen += current - laststart;
 					memcpy(newtext+newtextlen, breakchar, breakcharlen);
@@ -679,6 +691,11 @@ PHP_FUNCTION(wordwrap)
 			 * copy and insert a break. */
 			else if (current - laststart >= linelength
 					&& docut && laststart >= lastspace) {
+				if ((newtextlen+current-laststart+breakcharlen) >= mem_alloced) {
+					mem_alloced += textlen-current+((textlen-current)/linelength + 1) * breakcharlen + 1;
+					newtext = erealloc(newtext, mem_alloced);
+				}
+					
 				memcpy(newtext+newtextlen, text+laststart, current-laststart);
 				newtextlen += current - laststart;
 				memcpy(newtext+newtextlen, breakchar, breakcharlen);
@@ -690,6 +707,10 @@ PHP_FUNCTION(wordwrap)
 			 * up the laststart */
 			else if (current - laststart >= linelength
 					&& laststart < lastspace) {
+				if ((newtextlen+lastspace-laststart+breakcharlen) >= mem_alloced) {
+					mem_alloced += textlen-current+((textlen-current)/linelength + 1) * breakcharlen + 1;
+					newtext = erealloc(newtext, mem_alloced);
+				}
 				memcpy(newtext+newtextlen, text+laststart, lastspace-laststart);
 				newtextlen += lastspace - laststart;
 				memcpy(newtext+newtextlen, breakchar, breakcharlen);
@@ -700,8 +721,15 @@ PHP_FUNCTION(wordwrap)
 
 		/* copy over any stragglers */
 		if (laststart != current) {
+			if ((newtextlen+current - laststart) >= mem_alloced) {
+				mem_alloced += current-laststart+1;
+				newtext = erealloc(newtext, mem_alloced);
+			}
+		
 			memcpy(newtext+newtextlen, text+laststart, current-laststart);
 			newtextlen += current - laststart;
+		} else {
+			newtext = erealloc(newtext, newtextlen+1);
 		}
 
 		newtext[newtextlen] = '\0';
<?php

$var = 'Unser Waldhof liegt inmitten der ursprünglichen Landschaft des Dreiländerecks 
Deutschland – Luxemburg –Belgien. Umgeben von Wäldern, Wiesen und Feldern sind unsere 
Ferienwohnungen ein idealer Ausgangspunkt für ausgedehnte Streifzüge durch eine 
intakte Natur. Wanderer und Naturfreunde können bei uns die wohltuende Ruhe einer 
ländlichen Region genießen.

Kinder fühlen sich auf unserem Bauerhof besonders wohl, denn hier können sie den 
artgerechten Umgang mit unseren Kühen und Kälbern, den Hühnern und Katzen, unseren 
beiden Ponys Max & Moritz sowie unserem Hofhund Sanny hautnah kennen lernen. Aber auch 
die angebotenen Traktorfahrten erfreuen sich bei unseren kleinen Gästen größter 
Beliebtheit.

Unsere beiden Wohnungen sind modern und ansprechend eingerichtet und verfügen über 
eine voll ausgestattete Einbauküche, Telefon, Radio sowie einen Fernseher mit 
Sat-Anschluß.
Der "Kornspeicher" bietet auf 80qm Platz für bis zu 8 Personen. Die Ferienwohnung 
besteht aus 2 Schlafzimmern, Küche, Wohnraum mit Schlafcouch, Essecke sowie einem Bad 
mit Dusche und WC.
Der "Heuboden" bietet auf 50 qm Platz für 4 Personen. Die Ferienwohnung besteht aus 
einem Schlafzimmer, Wohnküche mit Schrankbett sowie einem Bad mit Dusche und WC.

Eine Terrasse mit bequemen Liegestühlen sowie ein Hobbyraum mit Spielen, Büchern und 
einer Tischtennisplatte sowie einem Fußballkicker stehen unseren Gästen ebenfalls zur 
Verfügung. Für unsere kleinen Gäste stehen eine Schaukel, ein Sandkasten und ein 
Baumhaus bereit.

Wir würden uns freuen, Ihnen und Ihren Kindern ein erholsames Naturerlebnis 
ermöglichen zu können.
';

echo strlen($var)."\n";
printf("%f\n",(strlen($var)/43));
//$wrapped = wordwrap($var,43,"\n                        | ");


for( $i=50; $i<200; $i++ ) {
        echo $i."\n";
        flush();
        wordwrap($var, 43, str_repeat(" ", $i));
}

//wordwrap($var, 43, str_repeat(" ", 80));

//$wrapped = wordwrap($var,43,"\n                                                      
                              ");
?>

-- 
PHP Development Mailing List <http://www.php.net/>
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to