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