stas                                     Wed, 13 Apr 2011 06:32:41 +0000

Revision: http://svn.php.net/viewvc?view=revision&revision=310194

Log:
fix bug #54238 (use-after-free in substr_replace())

Bug: http://bugs.php.net/54238 (error getting bug information)
      
Changed paths:
    U   php/php-src/branches/PHP_5_3/NEWS
    U   php/php-src/branches/PHP_5_3/ext/standard/string.c
    A   php/php-src/branches/PHP_5_3/ext/standard/tests/strings/bug54238.phpt
    U   php/php-src/trunk/ext/standard/string.c
    A   php/php-src/trunk/ext/standard/tests/strings/bug54238.phpt

Modified: php/php-src/branches/PHP_5_3/NEWS
===================================================================
--- php/php-src/branches/PHP_5_3/NEWS	2011-04-13 03:32:19 UTC (rev 310193)
+++ php/php-src/branches/PHP_5_3/NEWS	2011-04-13 06:32:41 UTC (rev 310194)
@@ -17,6 +17,7 @@
   . Implemented FR #54459 (Range function accuracy). (Adam)
   . Fixed bug #54454 (substr_compare incorrectly reports equality in some
     cases). (Pierrick)
+  . Fixed bug #54238 (use-after-free in substr_replace()). (Stas)
   . Fixed bug #54180 (parse_url() incorrectly parses path when ? in fragment).
     (tomas dot brastavicius at quantum dot lt, Pierrick)
   . Fixed bug #48465 (sys_get_temp_dir() possibly inconsistent when using

Modified: php/php-src/branches/PHP_5_3/ext/standard/string.c
===================================================================
--- php/php-src/branches/PHP_5_3/ext/standard/string.c	2011-04-13 03:32:19 UTC (rev 310193)
+++ php/php-src/branches/PHP_5_3/ext/standard/string.c	2011-04-13 06:32:41 UTC (rev 310194)
@@ -2352,20 +2352,35 @@

 		zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(str), &pos_str);
 		while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(str), (void **) &tmp_str, &pos_str) == SUCCESS) {
-			convert_to_string_ex(tmp_str);
+			zval *orig_str;
+			zval dummy;
+			if(Z_TYPE_PP(tmp_str) != IS_STRING) {
+				dummy = **tmp_str;
+				orig_str = &dummy;
+				zval_copy_ctor(orig_str);
+				convert_to_string(orig_str);
+			} else {
+				orig_str = *tmp_str;
+			}

 			if (Z_TYPE_PP(from) == IS_ARRAY) {
 				if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(from), (void **) &tmp_from, &pos_from)) {
-					convert_to_long_ex(tmp_from);
+					if(Z_TYPE_PP(tmp_from) != IS_LONG) {
+						zval dummy = **tmp_from;
+						zval_copy_ctor(&dummy);
+						convert_to_long(&dummy);
+						f = Z_LVAL(dummy);
+					} else {
+						f = Z_LVAL_PP(tmp_from);
+					}

-					f = Z_LVAL_PP(tmp_from);
 					if (f < 0) {
-						f = Z_STRLEN_PP(tmp_str) + f;
+						f = Z_STRLEN_P(orig_str) + f;
 						if (f < 0) {
 							f = 0;
 						}
-					} else if (f > Z_STRLEN_PP(tmp_str)) {
-						f = Z_STRLEN_PP(tmp_str);
+					} else if (f > Z_STRLEN_P(orig_str)) {
+						f = Z_STRLEN_P(orig_str);
 					}
 					zend_hash_move_forward_ex(Z_ARRVAL_PP(from), &pos_from);
 				} else {
@@ -2374,72 +2389,94 @@
 			} else {
 				f = Z_LVAL_PP(from);
 				if (f < 0) {
-					f = Z_STRLEN_PP(tmp_str) + f;
+					f = Z_STRLEN_P(orig_str) + f;
 					if (f < 0) {
 						f = 0;
 					}
-				} else if (f > Z_STRLEN_PP(tmp_str)) {
-					f = Z_STRLEN_PP(tmp_str);
+				} else if (f > Z_STRLEN_P(orig_str)) {
+					f = Z_STRLEN_P(orig_str);
 				}
 			}

 			if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) {
 				if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(len), (void **) &tmp_len, &pos_len)) {
-					convert_to_long_ex(tmp_len);
+					if(Z_TYPE_PP(tmp_len) != IS_LONG) {
+						zval dummy = **tmp_len;
+						zval_copy_ctor(&dummy);
+						convert_to_long(&dummy);
+						l = Z_LVAL(dummy);
+					} else {
+						l = Z_LVAL_PP(tmp_len);
+					}

 					l = Z_LVAL_PP(tmp_len);
 					zend_hash_move_forward_ex(Z_ARRVAL_PP(len), &pos_len);
 				} else {
-					l = Z_STRLEN_PP(tmp_str);
+					l = Z_STRLEN_P(orig_str);
 				}
 			} else if (argc > 3) {
 				l = Z_LVAL_PP(len);
 			} else {
-				l = Z_STRLEN_PP(tmp_str);
+				l = Z_STRLEN_P(orig_str);
 			}

 			if (l < 0) {
-				l = (Z_STRLEN_PP(tmp_str) - f) + l;
+				l = (Z_STRLEN_P(orig_str) - f) + l;
 				if (l < 0) {
 					l = 0;
 				}
 			}

-			if ((f + l) > Z_STRLEN_PP(tmp_str)) {
-				l = Z_STRLEN_PP(tmp_str) - f;
+			if ((f + l) > Z_STRLEN_P(orig_str)) {
+				l = Z_STRLEN_P(orig_str) - f;
 			}

-			result_len = Z_STRLEN_PP(tmp_str) - l;
+			result_len = Z_STRLEN_P(orig_str) - l;

 			if (Z_TYPE_PP(repl) == IS_ARRAY) {
 				if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) {
-					convert_to_string_ex(tmp_repl);
-					result_len += Z_STRLEN_PP(tmp_repl);
+					zval *repl_str;
+					zval zrepl;
+					if(Z_TYPE_PP(tmp_repl) != IS_STRING) {
+						zrepl = **tmp_repl;
+						repl_str = &zrepl;
+						zval_copy_ctor(repl_str);
+						convert_to_string(repl_str);
+					} else {
+						repl_str = *tmp_repl;
+					}
+
+					result_len += Z_STRLEN_P(repl_str);
 					zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl);
 					result = emalloc(result_len + 1);

-					memcpy(result, Z_STRVAL_PP(tmp_str), f);
-					memcpy((result + f), Z_STRVAL_PP(tmp_repl), Z_STRLEN_PP(tmp_repl));
-					memcpy((result + f + Z_STRLEN_PP(tmp_repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
+					memcpy(result, Z_STRVAL_P(orig_str), f);
+					memcpy((result + f), Z_STRVAL_P(repl_str), Z_STRLEN_P(repl_str));
+					memcpy((result + f + Z_STRLEN_P(repl_str)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
+					if(Z_TYPE_PP(tmp_repl) != IS_STRING) {
+						zval_dtor(repl_str);
+					}
 				} else {
 					result = emalloc(result_len + 1);

-					memcpy(result, Z_STRVAL_PP(tmp_str), f);
-					memcpy((result + f), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
+					memcpy(result, Z_STRVAL_P(orig_str), f);
+					memcpy((result + f), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
 				}
 			} else {
 				result_len += Z_STRLEN_PP(repl);

 				result = emalloc(result_len + 1);

-				memcpy(result, Z_STRVAL_PP(tmp_str), f);
+				memcpy(result, Z_STRVAL_P(orig_str), f);
 				memcpy((result + f), Z_STRVAL_PP(repl), Z_STRLEN_PP(repl));
-				memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
+				memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
 			}

 			result[result_len] = '\0';
 			add_next_index_stringl(return_value, result, result_len, 0);
-
+			if(Z_TYPE_PP(tmp_str) != IS_STRING) {
+				zval_dtor(orig_str);
+			}
 			zend_hash_move_forward_ex(Z_ARRVAL_PP(str), &pos_str);
 		} /*while*/
 	} /* if */

Added: php/php-src/branches/PHP_5_3/ext/standard/tests/strings/bug54238.phpt
===================================================================
--- php/php-src/branches/PHP_5_3/ext/standard/tests/strings/bug54238.phpt	                        (rev 0)
+++ php/php-src/branches/PHP_5_3/ext/standard/tests/strings/bug54238.phpt	2011-04-13 06:32:41 UTC (rev 310194)
@@ -0,0 +1,25 @@
+--TEST--
+Bug #54238 (use-after-free in substr_replace())
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+$f = array(array('A', 'A'));
+
+$z = substr_replace($f, $f, $f, 1);
+var_dump($z, $f);
+?>
+--EXPECT--
+array(1) {
+  [0]=>
+  string(9) "AArrayray"
+}
+array(1) {
+  [0]=>
+  array(2) {
+    [0]=>
+    string(1) "A"
+    [1]=>
+    string(1) "A"
+  }
+}

Modified: php/php-src/trunk/ext/standard/string.c
===================================================================
--- php/php-src/trunk/ext/standard/string.c	2011-04-13 03:32:19 UTC (rev 310193)
+++ php/php-src/trunk/ext/standard/string.c	2011-04-13 06:32:41 UTC (rev 310194)
@@ -2352,20 +2352,35 @@

 		zend_hash_internal_pointer_reset_ex(Z_ARRVAL_PP(str), &pos_str);
 		while (zend_hash_get_current_data_ex(Z_ARRVAL_PP(str), (void **) &tmp_str, &pos_str) == SUCCESS) {
-			convert_to_string_ex(tmp_str);
+			zval *orig_str;
+			zval dummy;
+			if(Z_TYPE_PP(tmp_str) != IS_STRING) {
+				dummy = **tmp_str;
+				orig_str = &dummy;
+				zval_copy_ctor(orig_str);
+				convert_to_string(orig_str);
+			} else {
+				orig_str = *tmp_str;
+			}

 			if (Z_TYPE_PP(from) == IS_ARRAY) {
 				if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(from), (void **) &tmp_from, &pos_from)) {
-					convert_to_long_ex(tmp_from);
+					if(Z_TYPE_PP(tmp_from) != IS_LONG) {
+						zval dummy = **tmp_from;
+						zval_copy_ctor(&dummy);
+						convert_to_long(&dummy);
+						f = Z_LVAL(dummy);
+					} else {
+						f = Z_LVAL_PP(tmp_from);
+					}

-					f = Z_LVAL_PP(tmp_from);
 					if (f < 0) {
-						f = Z_STRLEN_PP(tmp_str) + f;
+						f = Z_STRLEN_P(orig_str) + f;
 						if (f < 0) {
 							f = 0;
 						}
-					} else if (f > Z_STRLEN_PP(tmp_str)) {
-						f = Z_STRLEN_PP(tmp_str);
+					} else if (f > Z_STRLEN_P(orig_str)) {
+						f = Z_STRLEN_P(orig_str);
 					}
 					zend_hash_move_forward_ex(Z_ARRVAL_PP(from), &pos_from);
 				} else {
@@ -2374,72 +2389,94 @@
 			} else {
 				f = Z_LVAL_PP(from);
 				if (f < 0) {
-					f = Z_STRLEN_PP(tmp_str) + f;
+					f = Z_STRLEN_P(orig_str) + f;
 					if (f < 0) {
 						f = 0;
 					}
-				} else if (f > Z_STRLEN_PP(tmp_str)) {
-					f = Z_STRLEN_PP(tmp_str);
+				} else if (f > Z_STRLEN_P(orig_str)) {
+					f = Z_STRLEN_P(orig_str);
 				}
 			}

 			if (argc > 3 && Z_TYPE_PP(len) == IS_ARRAY) {
 				if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(len), (void **) &tmp_len, &pos_len)) {
-					convert_to_long_ex(tmp_len);
+					if(Z_TYPE_PP(tmp_len) != IS_LONG) {
+						zval dummy = **tmp_len;
+						zval_copy_ctor(&dummy);
+						convert_to_long(&dummy);
+						l = Z_LVAL(dummy);
+					} else {
+						l = Z_LVAL_PP(tmp_len);
+					}

 					l = Z_LVAL_PP(tmp_len);
 					zend_hash_move_forward_ex(Z_ARRVAL_PP(len), &pos_len);
 				} else {
-					l = Z_STRLEN_PP(tmp_str);
+					l = Z_STRLEN_P(orig_str);
 				}
 			} else if (argc > 3) {
 				l = Z_LVAL_PP(len);
 			} else {
-				l = Z_STRLEN_PP(tmp_str);
+				l = Z_STRLEN_P(orig_str);
 			}

 			if (l < 0) {
-				l = (Z_STRLEN_PP(tmp_str) - f) + l;
+				l = (Z_STRLEN_P(orig_str) - f) + l;
 				if (l < 0) {
 					l = 0;
 				}
 			}

-			if ((f + l) > Z_STRLEN_PP(tmp_str)) {
-				l = Z_STRLEN_PP(tmp_str) - f;
+			if ((f + l) > Z_STRLEN_P(orig_str)) {
+				l = Z_STRLEN_P(orig_str) - f;
 			}

-			result_len = Z_STRLEN_PP(tmp_str) - l;
+			result_len = Z_STRLEN_P(orig_str) - l;

 			if (Z_TYPE_PP(repl) == IS_ARRAY) {
 				if (SUCCESS == zend_hash_get_current_data_ex(Z_ARRVAL_PP(repl), (void **) &tmp_repl, &pos_repl)) {
-					convert_to_string_ex(tmp_repl);
-					result_len += Z_STRLEN_PP(tmp_repl);
+					zval *repl_str;
+					zval zrepl;
+					if(Z_TYPE_PP(tmp_repl) != IS_STRING) {
+						zrepl = **tmp_repl;
+						repl_str = &zrepl;
+						zval_copy_ctor(repl_str);
+						convert_to_string(repl_str);
+					} else {
+						repl_str = *tmp_repl;
+					}
+
+					result_len += Z_STRLEN_P(repl_str);
 					zend_hash_move_forward_ex(Z_ARRVAL_PP(repl), &pos_repl);
 					result = emalloc(result_len + 1);

-					memcpy(result, Z_STRVAL_PP(tmp_str), f);
-					memcpy((result + f), Z_STRVAL_PP(tmp_repl), Z_STRLEN_PP(tmp_repl));
-					memcpy((result + f + Z_STRLEN_PP(tmp_repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
+					memcpy(result, Z_STRVAL_P(orig_str), f);
+					memcpy((result + f), Z_STRVAL_P(repl_str), Z_STRLEN_P(repl_str));
+					memcpy((result + f + Z_STRLEN_P(repl_str)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
+					if(Z_TYPE_PP(tmp_repl) != IS_STRING) {
+						zval_dtor(repl_str);
+					}
 				} else {
 					result = emalloc(result_len + 1);

-					memcpy(result, Z_STRVAL_PP(tmp_str), f);
-					memcpy((result + f), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
+					memcpy(result, Z_STRVAL_P(orig_str), f);
+					memcpy((result + f), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
 				}
 			} else {
 				result_len += Z_STRLEN_PP(repl);

 				result = emalloc(result_len + 1);

-				memcpy(result, Z_STRVAL_PP(tmp_str), f);
+				memcpy(result, Z_STRVAL_P(orig_str), f);
 				memcpy((result + f), Z_STRVAL_PP(repl), Z_STRLEN_PP(repl));
-				memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_PP(tmp_str) + f + l, Z_STRLEN_PP(tmp_str) - f - l);
+				memcpy((result + f + Z_STRLEN_PP(repl)), Z_STRVAL_P(orig_str) + f + l, Z_STRLEN_P(orig_str) - f - l);
 			}

 			result[result_len] = '\0';
 			add_next_index_stringl(return_value, result, result_len, 0);
-
+			if(Z_TYPE_PP(tmp_str) != IS_STRING) {
+				zval_dtor(orig_str);
+			}
 			zend_hash_move_forward_ex(Z_ARRVAL_PP(str), &pos_str);
 		} /*while*/
 	} /* if */

Added: php/php-src/trunk/ext/standard/tests/strings/bug54238.phpt
===================================================================
--- php/php-src/trunk/ext/standard/tests/strings/bug54238.phpt	                        (rev 0)
+++ php/php-src/trunk/ext/standard/tests/strings/bug54238.phpt	2011-04-13 06:32:41 UTC (rev 310194)
@@ -0,0 +1,25 @@
+--TEST--
+Bug #54238 (use-after-free in substr_replace())
+--INI--
+error_reporting=E_ALL&~E_NOTICE
+--FILE--
+<?php
+$f = array(array('A', 'A'));
+
+$z = substr_replace($f, $f, $f, 1);
+var_dump($z, $f);
+?>
+--EXPECT--
+array(1) {
+  [0]=>
+  string(9) "AArrayray"
+}
+array(1) {
+  [0]=>
+  array(2) {
+    [0]=>
+    string(1) "A"
+    [1]=>
+    string(1) "A"
+  }
+}
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to