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