cataphract                               Thu, 08 Mar 2012 12:30:59 +0000

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

Log:
- Fixed bug #61253: Wrappers opened with errors concurrency problem
#NOTE: There is a very small possibility that this will further break
#extensions that access wrapper->{err_stack, err_count}. On PECL SVN, rar is the
#only one and it may leak memory after this. I say "further break" because
#extensions that do that are already broken (will segfault) under ZTS, which is
#why this patch is necessary.
#There was what I deem as tacit acceptance from 5.3/5.4 RMs on this.

Bug: https://bugs.php.net/61253 (Assigned) Wrappers opened with errors 
concurrency problem
      
Changed paths:
    U   php/php-src/branches/PHP_5_3/NEWS
    U   php/php-src/branches/PHP_5_3/ext/standard/basic_functions.c
    U   php/php-src/branches/PHP_5_3/ext/standard/file.h
    U   php/php-src/branches/PHP_5_3/main/php_streams.h
    U   php/php-src/branches/PHP_5_3/main/streams/streams.c
    U   php/php-src/branches/PHP_5_4/ext/standard/basic_functions.c
    U   php/php-src/branches/PHP_5_4/ext/standard/file.h
    U   php/php-src/branches/PHP_5_4/main/php_streams.h
    U   php/php-src/branches/PHP_5_4/main/streams/streams.c
    U   php/php-src/trunk/ext/standard/basic_functions.c
    U   php/php-src/trunk/ext/standard/file.h
    U   php/php-src/trunk/main/php_streams.h
    U   php/php-src/trunk/main/streams/streams.c

Modified: php/php-src/branches/PHP_5_3/NEWS
===================================================================
--- php/php-src/branches/PHP_5_3/NEWS	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/branches/PHP_5_3/NEWS	2012-03-08 12:30:59 UTC (rev 324020)
@@ -76,6 +76,8 @@
     SessionHandler::write()). (Ilia)

 - Streams:
+  . Fixed bug #61253 (Wrappers opened with errors concurrency problem on ZTS).
+    (Gustavo)
   . Fixed bug #61115 (stream related segfault on fatal error in
     php_stream_context_link). (Gustavo)
   . Fixed bug #60106 (stream_socket_server silently truncates long unix

Modified: php/php-src/branches/PHP_5_3/ext/standard/basic_functions.c
===================================================================
--- php/php-src/branches/PHP_5_3/ext/standard/basic_functions.c	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/branches/PHP_5_3/ext/standard/basic_functions.c	2012-03-08 12:30:59 UTC (rev 324020)
@@ -3751,6 +3751,8 @@
 	/* Default to global filters only */
 	FG(stream_filters) = NULL;

+	FG(wrapper_errors) = NULL;
+
 	return SUCCESS;
 }
 /* }}} */

Modified: php/php-src/branches/PHP_5_3/ext/standard/file.h
===================================================================
--- php/php-src/branches/PHP_5_3/ext/standard/file.h	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/branches/PHP_5_3/ext/standard/file.h	2012-03-08 12:30:59 UTC (rev 324020)
@@ -123,6 +123,7 @@
 	php_stream_context *default_context;
 	HashTable *stream_wrappers;			/* per-request copy of url_stream_wrappers_hash */
 	HashTable *stream_filters;			/* per-request copy of stream_filters_hash */
+	HashTable *wrapper_errors;			/* key: wrapper address; value: linked list of char* */
 } php_file_globals;

 #ifdef ZTS

Modified: php/php-src/branches/PHP_5_3/main/php_streams.h
===================================================================
--- php/php-src/branches/PHP_5_3/main/php_streams.h	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/branches/PHP_5_3/main/php_streams.h	2012-03-08 12:30:59 UTC (rev 324020)
@@ -162,8 +162,8 @@
 	int is_url;						/* so that PG(allow_url_fopen) can be respected */

 	/* support for wrappers to return (multiple) error messages to the stream opener */
-	int err_count;
-	char **err_stack;
+	int err_count;					/* unused */
+	char **err_stack;				/* unusued */
 };

 #define PHP_STREAM_FLAG_NO_SEEK						1

Modified: php/php-src/branches/PHP_5_3/main/streams/streams.c
===================================================================
--- php/php-src/branches/PHP_5_3/main/streams/streams.c	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/branches/PHP_5_3/main/streams/streams.c	2012-03-08 12:30:59 UTC (rev 324020)
@@ -148,20 +148,35 @@

 /* }}} */

+static zend_llist *php_get_wrapper_errors_list(php_stream_wrapper *wrapper TSRMLS_DC)
+{
+    zend_llist *list = NULL;
+    if (!FG(wrapper_errors)) {
+        return NULL;
+    } else {
+        zend_hash_find(FG(wrapper_errors), (const char*)&wrapper,
+            sizeof wrapper, (void**)&list);
+        return list;
+    }
+}
+
 /* {{{ wrapper error reporting */
 void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption TSRMLS_DC)
 {
 	char *tmp = estrdup(path);
 	char *msg;
 	int free_msg = 0;
-	php_stream_wrapper orig_wrapper;

 	if (wrapper) {
-		if (wrapper->err_count > 0) {
+		zend_llist *err_list = php_get_wrapper_errors_list(wrapper TSRMLS_CC);
+		if (err_list) {
+			size_t l = 0;
+			int brlen;
 			int i;
-			size_t l;
-			int brlen;
-			char *br;
+			int count = zend_llist_count(err_list);
+			const char *br;
+			const char **err_buf_p;
+			zend_llist_position pos;

 			if (PG(html_errors)) {
 				brlen = 7;
@@ -171,25 +186,29 @@
 				br = "\n";
 			}

-			for (i = 0, l = 0; i < wrapper->err_count; i++) {
-				l += strlen(wrapper->err_stack[i]);
-				if (i < wrapper->err_count - 1) {
+			for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0;
+					err_buf_p;
+					err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) {
+				l += strlen(*err_buf_p);
+				if (i < count - 1) {
 					l += brlen;
 				}
 			}
 			msg = emalloc(l + 1);
 			msg[0] = '\0';
-			for (i = 0; i < wrapper->err_count; i++) {
-				strcat(msg, wrapper->err_stack[i]);
-				if (i < wrapper->err_count - 1) {
-					strcat(msg, br);
+			for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0;
+					err_buf_p;
+					err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) {
+				strcat(msg, *err_buf_p);
+				if (i < count - 1) {
+					l += brlen;
 				}
 			}

 			free_msg = 1;
 		} else {
 			if (wrapper == &php_plain_files_wrapper) {
-				msg = strerror(errno);
+				msg = strerror(errno); /* TODO: not ts on linux */
 			} else {
 				msg = "operation failed";
 			}
@@ -199,16 +218,7 @@
 	}

 	php_strip_url_passwd(tmp);
-	if (wrapper) {
-		/* see bug #52935 */
-		orig_wrapper = *wrapper;
-		wrapper->err_stack = NULL;
-		wrapper->err_count = 0;
-	}
 	php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "%s: %s", caption, msg);
-	if (wrapper) {
-		*wrapper = orig_wrapper;
-	}
 	efree(tmp);
 	if (free_msg) {
 		efree(msg);
@@ -217,21 +227,16 @@

 void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
 {
-	if (wrapper) {
-		/* tidy up the error stack */
-		int i;
-
-		for (i = 0; i < wrapper->err_count; i++) {
-			efree(wrapper->err_stack[i]);
-		}
-		if (wrapper->err_stack) {
-			efree(wrapper->err_stack);
-		}
-		wrapper->err_stack = NULL;
-		wrapper->err_count = 0;
+	if (wrapper && FG(wrapper_errors)) {
+		zend_hash_del(FG(wrapper_errors), (const char*)&wrapper, sizeof wrapper);
 	}
 }

+static void wrapper_error_dtor(void *error)
+{
+	efree(*(char**)error);
+}
+
 PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...)
 {
 	va_list args;
@@ -245,11 +250,25 @@
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", buffer);
 		efree(buffer);
 	} else {
-		/* append to stack */
-		wrapper->err_stack = erealloc(wrapper->err_stack, (wrapper->err_count + 1) * sizeof(char *));
-		if (wrapper->err_stack) {
-			wrapper->err_stack[wrapper->err_count++] = buffer;
+		zend_llist *list = NULL;
+		if (!FG(wrapper_errors)) {
+			ALLOC_HASHTABLE(FG(wrapper_errors));
+			zend_hash_init(FG(wrapper_errors), 8, NULL,
+					(dtor_func_t)zend_llist_destroy, 0);
+		} else {
+			zend_hash_find(FG(wrapper_errors), (const char*)&wrapper,
+				sizeof wrapper, (void**)&list);
 		}
+
+		if (!list) {
+			zend_llist new_list;
+			zend_llist_init(&new_list, sizeof buffer, wrapper_error_dtor, 0);
+			zend_hash_update(FG(wrapper_errors), (const char*)&wrapper,
+				sizeof wrapper, &new_list, sizeof new_list, (void**)&list);
+		}
+
+		/* append to linked list */
+		zend_llist_add_element(list, &buffer);
 	}
 }

@@ -1533,6 +1552,12 @@
 		efree(FG(stream_filters));
 		FG(stream_filters) = NULL;
 	}
+
+    if (FG(wrapper_errors)) {
+		zend_hash_destroy(FG(wrapper_errors));
+		efree(FG(wrapper_errors));
+		FG(wrapper_errors) = NULL;
+    }
 }

 int php_init_stream_wrappers(int module_number TSRMLS_DC)

Modified: php/php-src/branches/PHP_5_4/ext/standard/basic_functions.c
===================================================================
--- php/php-src/branches/PHP_5_4/ext/standard/basic_functions.c	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/branches/PHP_5_4/ext/standard/basic_functions.c	2012-03-08 12:30:59 UTC (rev 324020)
@@ -3719,6 +3719,8 @@
 	/* Default to global filters only */
 	FG(stream_filters) = NULL;

+	FG(wrapper_errors) = NULL;
+
 	return SUCCESS;
 }
 /* }}} */

Modified: php/php-src/branches/PHP_5_4/ext/standard/file.h
===================================================================
--- php/php-src/branches/PHP_5_4/ext/standard/file.h	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/branches/PHP_5_4/ext/standard/file.h	2012-03-08 12:30:59 UTC (rev 324020)
@@ -125,6 +125,7 @@
 	php_stream_context *default_context;
 	HashTable *stream_wrappers;			/* per-request copy of url_stream_wrappers_hash */
 	HashTable *stream_filters;			/* per-request copy of stream_filters_hash */
+	HashTable *wrapper_errors;			/* key: wrapper address; value: linked list of char* */
 } php_file_globals;

 #ifdef ZTS

Modified: php/php-src/branches/PHP_5_4/main/php_streams.h
===================================================================
--- php/php-src/branches/PHP_5_4/main/php_streams.h	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/branches/PHP_5_4/main/php_streams.h	2012-03-08 12:30:59 UTC (rev 324020)
@@ -164,8 +164,8 @@
 	int is_url;						/* so that PG(allow_url_fopen) can be respected */

 	/* support for wrappers to return (multiple) error messages to the stream opener */
-	int err_count;
-	char **err_stack;
+	int err_count;					/* unused */
+	char **err_stack;				/* unusued */
 };

 #define PHP_STREAM_FLAG_NO_SEEK						1

Modified: php/php-src/branches/PHP_5_4/main/streams/streams.c
===================================================================
--- php/php-src/branches/PHP_5_4/main/streams/streams.c	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/branches/PHP_5_4/main/streams/streams.c	2012-03-08 12:30:59 UTC (rev 324020)
@@ -157,20 +157,35 @@

 /* }}} */

+static zend_llist *php_get_wrapper_errors_list(php_stream_wrapper *wrapper TSRMLS_DC)
+{
+    zend_llist *list = NULL;
+    if (!FG(wrapper_errors)) {
+        return NULL;
+    } else {
+        zend_hash_find(FG(wrapper_errors), (const char*)&wrapper,
+            sizeof wrapper, (void**)&list);
+        return list;
+    }
+}
+
 /* {{{ wrapper error reporting */
 void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption TSRMLS_DC)
 {
 	char *tmp = estrdup(path);
 	char *msg;
 	int free_msg = 0;
-	php_stream_wrapper orig_wrapper;

 	if (wrapper) {
-		if (wrapper->err_count > 0) {
+		zend_llist *err_list = php_get_wrapper_errors_list(wrapper TSRMLS_CC);
+		if (err_list) {
+			size_t l = 0;
+			int brlen;
 			int i;
-			size_t l;
-			int brlen;
-			char *br;
+			int count = zend_llist_count(err_list);
+			const char *br;
+			const char **err_buf_p;
+			zend_llist_position pos;

 			if (PG(html_errors)) {
 				brlen = 7;
@@ -180,25 +195,29 @@
 				br = "\n";
 			}

-			for (i = 0, l = 0; i < wrapper->err_count; i++) {
-				l += strlen(wrapper->err_stack[i]);
-				if (i < wrapper->err_count - 1) {
+			for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0;
+					err_buf_p;
+					err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) {
+				l += strlen(*err_buf_p);
+				if (i < count - 1) {
 					l += brlen;
 				}
 			}
 			msg = emalloc(l + 1);
 			msg[0] = '\0';
-			for (i = 0; i < wrapper->err_count; i++) {
-				strcat(msg, wrapper->err_stack[i]);
-				if (i < wrapper->err_count - 1) {
-					strcat(msg, br);
+			for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0;
+					err_buf_p;
+					err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) {
+				strcat(msg, *err_buf_p);
+				if (i < count - 1) {
+					l += brlen;
 				}
 			}

 			free_msg = 1;
 		} else {
 			if (wrapper == &php_plain_files_wrapper) {
-				msg = strerror(errno);
+				msg = strerror(errno); /* TODO: not ts on linux */
 			} else {
 				msg = "operation failed";
 			}
@@ -208,16 +227,7 @@
 	}

 	php_strip_url_passwd(tmp);
-	if (wrapper) {
-		/* see bug #52935 */
-		orig_wrapper = *wrapper;
-		wrapper->err_stack = NULL;
-		wrapper->err_count = 0;
-	}
 	php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "%s: %s", caption, msg);
-	if (wrapper) {
-		*wrapper = orig_wrapper;
-	}
 	efree(tmp);
 	if (free_msg) {
 		efree(msg);
@@ -226,21 +236,16 @@

 void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
 {
-	if (wrapper) {
-		/* tidy up the error stack */
-		int i;
-
-		for (i = 0; i < wrapper->err_count; i++) {
-			efree(wrapper->err_stack[i]);
-		}
-		if (wrapper->err_stack) {
-			efree(wrapper->err_stack);
-		}
-		wrapper->err_stack = NULL;
-		wrapper->err_count = 0;
+	if (wrapper && FG(wrapper_errors)) {
+		zend_hash_del(FG(wrapper_errors), (const char*)&wrapper, sizeof wrapper);
 	}
 }

+static void wrapper_error_dtor(void *error)
+{
+	efree(*(char**)error);
+}
+
 PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...)
 {
 	va_list args;
@@ -254,11 +259,25 @@
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", buffer);
 		efree(buffer);
 	} else {
-		/* append to stack */
-		wrapper->err_stack = erealloc(wrapper->err_stack, (wrapper->err_count + 1) * sizeof(char *));
-		if (wrapper->err_stack) {
-			wrapper->err_stack[wrapper->err_count++] = buffer;
+		zend_llist *list = NULL;
+		if (!FG(wrapper_errors)) {
+			ALLOC_HASHTABLE(FG(wrapper_errors));
+			zend_hash_init(FG(wrapper_errors), 8, NULL,
+					(dtor_func_t)zend_llist_destroy, 0);
+		} else {
+			zend_hash_find(FG(wrapper_errors), (const char*)&wrapper,
+				sizeof wrapper, (void**)&list);
 		}
+
+		if (!list) {
+			zend_llist new_list;
+			zend_llist_init(&new_list, sizeof buffer, wrapper_error_dtor, 0);
+			zend_hash_update(FG(wrapper_errors), (const char*)&wrapper,
+				sizeof wrapper, &new_list, sizeof new_list, (void**)&list);
+		}
+
+		/* append to linked list */
+		zend_llist_add_element(list, &buffer);
 	}
 }

@@ -1563,6 +1582,12 @@
 		efree(FG(stream_filters));
 		FG(stream_filters) = NULL;
 	}
+
+    if (FG(wrapper_errors)) {
+		zend_hash_destroy(FG(wrapper_errors));
+		efree(FG(wrapper_errors));
+		FG(wrapper_errors) = NULL;
+    }
 }

 int php_init_stream_wrappers(int module_number TSRMLS_DC)

Modified: php/php-src/trunk/ext/standard/basic_functions.c
===================================================================
--- php/php-src/trunk/ext/standard/basic_functions.c	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/trunk/ext/standard/basic_functions.c	2012-03-08 12:30:59 UTC (rev 324020)
@@ -3754,6 +3754,8 @@
 	/* Default to global filters only */
 	FG(stream_filters) = NULL;

+	FG(wrapper_errors) = NULL;
+
 	return SUCCESS;
 }
 /* }}} */

Modified: php/php-src/trunk/ext/standard/file.h
===================================================================
--- php/php-src/trunk/ext/standard/file.h	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/trunk/ext/standard/file.h	2012-03-08 12:30:59 UTC (rev 324020)
@@ -125,6 +125,7 @@
 	php_stream_context *default_context;
 	HashTable *stream_wrappers;			/* per-request copy of url_stream_wrappers_hash */
 	HashTable *stream_filters;			/* per-request copy of stream_filters_hash */
+	HashTable *wrapper_errors;			/* key: wrapper address; value: linked list of char* */
 } php_file_globals;

 #ifdef ZTS

Modified: php/php-src/trunk/main/php_streams.h
===================================================================
--- php/php-src/trunk/main/php_streams.h	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/trunk/main/php_streams.h	2012-03-08 12:30:59 UTC (rev 324020)
@@ -162,10 +162,6 @@
 	php_stream_wrapper_ops *wops;	/* operations the wrapper can perform */
 	void *abstract;					/* context for the wrapper */
 	int is_url;						/* so that PG(allow_url_fopen) can be respected */
-
-	/* support for wrappers to return (multiple) error messages to the stream opener */
-	int err_count;
-	char **err_stack;
 };

 #define PHP_STREAM_FLAG_NO_SEEK						1

Modified: php/php-src/trunk/main/streams/streams.c
===================================================================
--- php/php-src/trunk/main/streams/streams.c	2012-03-08 12:23:22 UTC (rev 324019)
+++ php/php-src/trunk/main/streams/streams.c	2012-03-08 12:30:59 UTC (rev 324020)
@@ -157,20 +157,35 @@

 /* }}} */

+static zend_llist *php_get_wrapper_errors_list(php_stream_wrapper *wrapper TSRMLS_DC)
+{
+    zend_llist *list = NULL;
+    if (!FG(wrapper_errors)) {
+        return NULL;
+    } else {
+        zend_hash_find(FG(wrapper_errors), (const char*)&wrapper,
+            sizeof wrapper, (void**)&list);
+        return list;
+    }
+}
+
 /* {{{ wrapper error reporting */
 void php_stream_display_wrapper_errors(php_stream_wrapper *wrapper, const char *path, const char *caption TSRMLS_DC)
 {
 	char *tmp = estrdup(path);
 	char *msg;
 	int free_msg = 0;
-	php_stream_wrapper orig_wrapper;

 	if (wrapper) {
-		if (wrapper->err_count > 0) {
+		zend_llist *err_list = php_get_wrapper_errors_list(wrapper TSRMLS_CC);
+		if (err_list) {
+			size_t l = 0;
+			int brlen;
 			int i;
-			size_t l;
-			int brlen;
-			char *br;
+			int count = zend_llist_count(err_list);
+			const char *br;
+			const char **err_buf_p;
+			zend_llist_position pos;

 			if (PG(html_errors)) {
 				brlen = 7;
@@ -180,25 +195,29 @@
 				br = "\n";
 			}

-			for (i = 0, l = 0; i < wrapper->err_count; i++) {
-				l += strlen(wrapper->err_stack[i]);
-				if (i < wrapper->err_count - 1) {
+			for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0;
+					err_buf_p;
+					err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) {
+				l += strlen(*err_buf_p);
+				if (i < count - 1) {
 					l += brlen;
 				}
 			}
 			msg = emalloc(l + 1);
 			msg[0] = '\0';
-			for (i = 0; i < wrapper->err_count; i++) {
-				strcat(msg, wrapper->err_stack[i]);
-				if (i < wrapper->err_count - 1) {
-					strcat(msg, br);
+			for (err_buf_p = zend_llist_get_first_ex(err_list, &pos), i = 0;
+					err_buf_p;
+					err_buf_p = zend_llist_get_next_ex(err_list, &pos), i++) {
+				strcat(msg, *err_buf_p);
+				if (i < count - 1) {
+					l += brlen;
 				}
 			}

 			free_msg = 1;
 		} else {
 			if (wrapper == &php_plain_files_wrapper) {
-				msg = strerror(errno);
+				msg = strerror(errno); /* TODO: not ts on linux */
 			} else {
 				msg = "operation failed";
 			}
@@ -208,16 +227,7 @@
 	}

 	php_strip_url_passwd(tmp);
-	if (wrapper) {
-		/* see bug #52935 */
-		orig_wrapper = *wrapper;
-		wrapper->err_stack = NULL;
-		wrapper->err_count = 0;
-	}
 	php_error_docref1(NULL TSRMLS_CC, tmp, E_WARNING, "%s: %s", caption, msg);
-	if (wrapper) {
-		*wrapper = orig_wrapper;
-	}
 	efree(tmp);
 	if (free_msg) {
 		efree(msg);
@@ -226,21 +236,16 @@

 void php_stream_tidy_wrapper_error_log(php_stream_wrapper *wrapper TSRMLS_DC)
 {
-	if (wrapper) {
-		/* tidy up the error stack */
-		int i;
-
-		for (i = 0; i < wrapper->err_count; i++) {
-			efree(wrapper->err_stack[i]);
-		}
-		if (wrapper->err_stack) {
-			efree(wrapper->err_stack);
-		}
-		wrapper->err_stack = NULL;
-		wrapper->err_count = 0;
+	if (wrapper && FG(wrapper_errors)) {
+		zend_hash_del(FG(wrapper_errors), (const char*)&wrapper, sizeof wrapper);
 	}
 }

+static void wrapper_error_dtor(void *error)
+{
+	efree(*(char**)error);
+}
+
 PHPAPI void php_stream_wrapper_log_error(php_stream_wrapper *wrapper, int options TSRMLS_DC, const char *fmt, ...)
 {
 	va_list args;
@@ -254,11 +259,25 @@
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", buffer);
 		efree(buffer);
 	} else {
-		/* append to stack */
-		wrapper->err_stack = erealloc(wrapper->err_stack, (wrapper->err_count + 1) * sizeof(char *));
-		if (wrapper->err_stack) {
-			wrapper->err_stack[wrapper->err_count++] = buffer;
+		zend_llist *list = NULL;
+		if (!FG(wrapper_errors)) {
+			ALLOC_HASHTABLE(FG(wrapper_errors));
+			zend_hash_init(FG(wrapper_errors), 8, NULL,
+					(dtor_func_t)zend_llist_destroy, 0);
+		} else {
+			zend_hash_find(FG(wrapper_errors), (const char*)&wrapper,
+				sizeof wrapper, (void**)&list);
 		}
+
+		if (!list) {
+			zend_llist new_list;
+			zend_llist_init(&new_list, sizeof buffer, wrapper_error_dtor, 0);
+			zend_hash_update(FG(wrapper_errors), (const char*)&wrapper,
+				sizeof wrapper, &new_list, sizeof new_list, (void**)&list);
+		}
+
+		/* append to linked list */
+		zend_llist_add_element(list, &buffer);
 	}
 }

@@ -1599,6 +1618,12 @@
 		efree(FG(stream_filters));
 		FG(stream_filters) = NULL;
 	}
+
+    if (FG(wrapper_errors)) {
+		zend_hash_destroy(FG(wrapper_errors));
+		efree(FG(wrapper_errors));
+		FG(wrapper_errors) = NULL;
+    }
 }

 int php_init_stream_wrappers(int module_number TSRMLS_DC)
-- 
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php

Reply via email to