summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ext/exif/exif.c5
-rw-r--r--ext/pgsql/pgsql.c2
-rw-r--r--ext/standard/exec.c6
-rw-r--r--ext/standard/file.c12
-rw-r--r--ext/standard/fsock.c4
-rw-r--r--ext/standard/image.c5
-rw-r--r--ext/zlib/zlib.c10
-rwxr-xr-xmain/php_streams.h20
-rwxr-xr-xmain/streams.c54
-rw-r--r--main/user_streams.c2
10 files changed, 83 insertions, 37 deletions
diff --git a/ext/exif/exif.c b/ext/exif/exif.c
index 7fdf6c9f87..86aab27497 100644
--- a/ext/exif/exif.c
+++ b/ext/exif/exif.c
@@ -3254,7 +3254,6 @@ PHP_FUNCTION(exif_imagetype)
{
zval **arg1;
php_stream * stream;
- int rsrc_id;
int itype = 0;
if (ZEND_NUM_ARGS() != 1)
@@ -3269,11 +3268,9 @@ PHP_FUNCTION(exif_imagetype)
RETURN_FALSE;
}
- rsrc_id = ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream());
-
itype = itype = php_getimagetype(stream, NULL TSRMLS_CC);
- zend_list_delete(rsrc_id);
+ php_stream_close(stream);
if ( itype == IMAGE_FILETYPE_UNKNOWN) {
RETURN_FALSE;
diff --git a/ext/pgsql/pgsql.c b/ext/pgsql/pgsql.c
index e82379127e..6e870c20b0 100644
--- a/ext/pgsql/pgsql.c
+++ b/ext/pgsql/pgsql.c
@@ -1478,7 +1478,7 @@ PHP_FUNCTION(pg_trace)
php_stream_close(stream);
RETURN_FALSE;
}
- ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream());
+ php_stream_auto_cleanup(stream);
PQtrace(pgsql, fp);
RETURN_TRUE;
}
diff --git a/ext/standard/exec.c b/ext/standard/exec.c
index f5f337fee5..4b6b75c768 100644
--- a/ext/standard/exec.c
+++ b/ext/standard/exec.c
@@ -49,7 +49,6 @@ int php_Exec(int type, char *cmd, pval *array, pval *return_value TSRMLS_DC)
int buflen = 0;
int t, l, output=1;
int overflow_limit, lcmd, ldir;
- int rsrc_id;
char *b, *c, *d=NULL;
php_stream *stream = NULL;
#if PHP_SIGCHILD
@@ -143,8 +142,6 @@ int php_Exec(int type, char *cmd, pval *array, pval *return_value TSRMLS_DC)
*/
stream = php_stream_fopen_from_pipe(fp, "rb");
- if (stream)
- rsrc_id = ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream());
if (type != 3) {
l=0;
@@ -219,8 +216,7 @@ int php_Exec(int type, char *cmd, pval *array, pval *return_value TSRMLS_DC)
}
}
- /* the zend_list_delete will pclose our popen'ed process */
- zend_list_delete(rsrc_id);
+ php_stream_close(stream);
#if HAVE_SYS_WAIT_H
if (WIFEXITED(FG(pclose_ret))) {
diff --git a/ext/standard/file.c b/ext/standard/file.c
index a58b511902..cf76315f2b 100644
--- a/ext/standard/file.c
+++ b/ext/standard/file.c
@@ -113,7 +113,7 @@ static void _file_stream_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
{
php_stream *stream = (php_stream*)rsrc->ptr;
/* the stream might be a pipe, so set the return value for pclose */
- FG(pclose_ret) = php_stream_close(stream);
+ FG(pclose_ret) = php_stream_free(stream, PHP_STREAM_FREE_CLOSE | PHP_STREAM_FREE_RSRC_DTOR);
}
PHPAPI int php_file_le_stream(void)
@@ -528,7 +528,7 @@ PHP_NAMED_FUNCTION(php_if_tmpfile)
stream = php_stream_fopen_tmpfile();
if (stream) {
- ZEND_REGISTER_RESOURCE(return_value, stream, le_stream);
+ php_stream_to_zval(stream, return_value);
}
else {
RETURN_FALSE;
@@ -593,7 +593,9 @@ PHP_NAMED_FUNCTION(php_if_fopen)
RETURN_FALSE;
}
FG(fgetss_state) = 0;
- ZEND_REGISTER_RESOURCE(return_value, stream, le_stream);
+
+ php_stream_to_zval(stream, return_value);
+
return;
}
/* }}} */
@@ -676,9 +678,9 @@ PHP_FUNCTION(popen)
if (stream == NULL) {
zend_error(E_WARNING, "popen(\"%s\", \"%s\"): %s", Z_STRVAL_PP(arg1), p, strerror(errno));
RETVAL_FALSE;
+ } else {
+ php_stream_to_zval(stream, return_value);
}
- else
- ZEND_REGISTER_RESOURCE(return_value, stream, le_stream);
efree(p);
}
diff --git a/ext/standard/fsock.c b/ext/standard/fsock.c
index 84a12eb9fc..21eb6e8256 100644
--- a/ext/standard/fsock.c
+++ b/ext/standard/fsock.c
@@ -141,7 +141,7 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
(void *) &stream) == SUCCESS)
{
efree(hashkey);
- ZEND_REGISTER_RESOURCE(return_value, stream, php_file_le_stream());
+ php_stream_to_zval(stream, return_value);
return;
}
@@ -241,7 +241,7 @@ static void php_fsockopen_stream(INTERNAL_FUNCTION_PARAMETERS, int persistent)
RETURN_FALSE;
}
- ZEND_REGISTER_RESOURCE(return_value, stream, php_file_le_stream());
+ php_stream_to_zval(stream, return_value);
}
/* }}} */
diff --git a/ext/standard/image.c b/ext/standard/image.c
index 9d6896c608..f12c8cb39e 100644
--- a/ext/standard/image.c
+++ b/ext/standard/image.c
@@ -684,7 +684,6 @@ PHPAPI int php_getimagetype(php_stream * stream, char *filetype TSRMLS_DC)
PHP_FUNCTION(getimagesize)
{
zval **arg1, **info = NULL;
- int rsrc_id;
int itype = 0;
char temp[64];
struct gfxinfo *result = NULL;
@@ -723,8 +722,6 @@ PHP_FUNCTION(getimagesize)
RETURN_FALSE;
}
- rsrc_id = ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream());
-
itype = php_getimagetype(stream, NULL TSRMLS_CC);
switch( itype) {
case IMAGE_FILETYPE_GIF:
@@ -763,7 +760,7 @@ PHP_FUNCTION(getimagesize)
break;
}
- zend_list_delete(rsrc_id);
+ php_stream_close(stream);
if (result) {
if (array_init(return_value) == FAILURE) {
diff --git a/ext/zlib/zlib.c b/ext/zlib/zlib.c
index f4323a8b8b..9c46953f83 100644
--- a/ext/zlib/zlib.c
+++ b/ext/zlib/zlib.c
@@ -255,15 +255,9 @@ static gzFile php_gzopen_wrapper(char *path, char *mode, int options TSRMLS_DC)
stream = php_stream_open_wrapper(path, mode, options | REPORT_ERRORS, NULL);
if (stream) {
- if (SUCCESS == php_stream_cast(stream, PHP_STREAM_AS_FD|PHP_STREAM_CAST_TRY_HARD, (void**)&fd, 1))
+ if (SUCCESS == php_stream_cast(stream, PHP_STREAM_CAST_RELEASE|PHP_STREAM_AS_FD|PHP_STREAM_CAST_TRY_HARD, (void**)&fd, 1))
{
- gzFile ret = gzdopen(fd, mode);
- if (ret) {
- /* arrange to clean up the actual stream */
- ZEND_REGISTER_RESOURCE(NULL, stream, php_file_le_stream());
-/* php_stream_auto_cleanup(stream); */
- return ret;
- }
+ return gzdopen(fd, mode);
}
php_stream_close(stream);
}
diff --git a/main/php_streams.h b/main/php_streams.h
index 98a62286f8..4a63edcd5c 100755
--- a/main/php_streams.h
+++ b/main/php_streams.h
@@ -120,10 +120,15 @@ struct _php_stream {
int is_persistent;
char mode[16]; /* "rwb" etc. ala stdio */
+ int rsrc_id; /* used for auto-cleanup */
+ int in_free; /* to prevent recursion during free */
/* so we know how to clean it up correctly. This should be set to
* PHP_STREAM_FCLOSE_XXX as appropriate */
int fclose_stdiocast;
FILE *stdiocast; /* cache this, otherwise we might leak! */
+#if ZEND_DEBUG
+ int __exposed; /* non-zero if exposed as a zval somewhere */
+#endif
}; /* php_stream */
/* state definitions when closing down; these are private to streams.c */
#define PHP_STREAM_FCLOSE_NONE 0
@@ -135,9 +140,24 @@ PHPAPI php_stream *_php_stream_alloc(php_stream_ops *ops, void *abstract,
int persistent, const char *mode STREAMS_DC TSRMLS_DC);
#define php_stream_alloc(ops, thisptr, persistent, mode) _php_stream_alloc((ops), (thisptr), (persistent), (mode) STREAMS_CC TSRMLS_CC)
+#define php_stream_get_resource_id(stream) (stream)->rsrc_id
+
+#if ZEND_DEBUG
+/* use this to tell the stream that it is OK if we don't explicitly close it */
+# define php_stream_auto_cleanup(stream) { (stream)->__exposed++; }
+/* use this to assign the stream to a zval and tell the stream that is
+ * has been exported to the engine; it will expect to be closed automatically
+ * when the resources are auto-destructed */
+# define php_stream_to_zval(stream, zval) { ZVAL_RESOURCE(zval, (stream)->rsrc_id); (stream)->__exposed++; }
+#else
+# define php_stream_auto_cleanup(stream) /* nothing */
+# define php_stream_to_zval(stream, zval) { ZVAL_RESOURCE(zval, (stream)->rsrc_id); }
+#endif
+
#define PHP_STREAM_FREE_CALL_DTOR 1 /* call ops->close */
#define PHP_STREAM_FREE_RELEASE_STREAM 2 /* pefree(stream) */
#define PHP_STREAM_FREE_PRESERVE_HANDLE 4 /* tell ops->close to not close it's underlying handle */
+#define PHP_STREAM_FREE_RSRC_DTOR 8 /* called from the resource list dtor */
#define PHP_STREAM_FREE_CLOSE (PHP_STREAM_FREE_CALL_DTOR | PHP_STREAM_FREE_RELEASE_STREAM)
PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC);
#define php_stream_free(stream, close_options) _php_stream_free((stream), (close_options) TSRMLS_CC)
diff --git a/main/streams.c b/main/streams.c
index 687535e4b9..419745b9d4 100755
--- a/main/streams.c
+++ b/main/streams.c
@@ -25,6 +25,7 @@
#include "php_globals.h"
#include "php_network.h"
#include "php_open_temporary_file.h"
+#include "ext/standard/file.h"
#ifdef HAVE_SYS_MMAN_H
#include <sys/mman.h>
@@ -35,6 +36,7 @@
#endif
#define CHUNK_SIZE 8192
+#define PHP_STREAM_MAX_MEM 2 * 1024 * 1024
#ifdef PHP_WIN32
#define EWOULDBLOCK WSAEWOULDBLOCK
@@ -78,7 +80,7 @@ PHPAPI php_stream *_php_stream_alloc(php_stream_ops *ops, void *abstract, int pe
ret->ops = ops;
ret->abstract = abstract;
ret->is_persistent = persistent;
-
+ ret->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, ret, php_file_le_stream());
strlcpy(ret->mode, mode, sizeof(ret->mode));
return ret;
@@ -89,6 +91,15 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /*
{
int ret = 1;
+ if (stream->in_free)
+ return 1;
+
+ stream->in_free++;
+
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) == 0) {
+ /* Remove entry from the resource list */
+ zend_list_delete(stream->rsrc_id);
+ }
if (close_options & PHP_STREAM_FREE_CALL_DTOR) {
if (stream->fclose_stdiocast == PHP_STREAM_FCLOSE_FOPENCOOKIE) {
/* calling fclose on an fopencookied stream will ultimately
@@ -98,6 +109,7 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /*
php_stream_free.
Lets let the cookie code clean it all up.
*/
+ stream->in_free = 0;
return fclose(stream->stdiocast);
}
@@ -125,6 +137,21 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /*
stream->wrapperdata = NULL;
}
+#if ZEND_DEBUG
+ if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) && (stream->__exposed == 0) && (EG(error_reporting) & E_WARNING)) {
+ /* it leaked: Lets deliberately NOT pefree it so that the memory manager shows it
+ * as leaked; it will log a warning, but lets help it out and display what kind
+ * of stream it was. */
+ char leakbuf[512];
+ snprintf(leakbuf, sizeof(leakbuf), __FILE__ "(%d) : Stream of type '%s' 0x%08X was not closed\n", __LINE__, stream->ops->label, (unsigned int)stream);
+# if defined(PHP_WIN32)
+ OutputDebugString(leakbuf);
+# else
+ fprintf(stderr, leakbuf);
+# endif
+ }
+ else
+#endif
pefree(stream, stream->is_persistent);
}
@@ -619,8 +646,10 @@ php_stream_ops php_stream_stdio_ops = {
php_stdiop_gets, php_stdiop_cast,
"STDIO"
};
+/* }}} */
-PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path STREAMS_DC TSRMLS_DC) /* {{{ */
+/* {{{ php_stream_fopen_with_path */
+PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char *path, char **opened_path STREAMS_DC TSRMLS_DC)
{
/* code ripped off from fopen_wrappers.c */
char *pathbuf, *ptr, *end;
@@ -737,6 +766,7 @@ PHPAPI php_stream *_php_stream_fopen_with_path(char *filename, char *mode, char
}
/* }}} */
+/* {{{ php_stream_fopen */
PHPAPI php_stream *_php_stream_fopen(const char *filename, const char *mode, char **opened_path STREAMS_DC TSRMLS_DC)
{
FILE *fp;
@@ -811,7 +841,8 @@ static COOKIE_IO_FUNCTIONS_T stream_cookie_functions =
#endif
/* }}} */
-PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC) /* {{{ */
+/* {{{ php_stream_cast */
+PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show_err TSRMLS_DC)
{
int flags = castas & PHP_STREAM_CAST_MASK;
castas &= ~PHP_STREAM_CAST_MASK;
@@ -902,8 +933,10 @@ exit_success:
return SUCCESS;
-} /* }}} */
+}
+/* }}} */
+/* {{{ wrapper init and registration */
int php_init_stream_wrappers(TSRMLS_D)
{
if (PG(allow_url_fopen)) {
@@ -935,7 +968,9 @@ PHPAPI int php_unregister_url_stream_wrapper(char *protocol TSRMLS_DC)
}
return SUCCESS;
}
+/* }}} */
+/* {{{ php_stream_open_url */
static php_stream *php_stream_open_url(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
{
php_stream_wrapper *wrapper;
@@ -977,7 +1012,9 @@ static php_stream *php_stream_open_url(char *path, char *mode, int options, char
}
return NULL;
}
+/* }}} */
+/* {{{ php_stream_open_wrapper */
PHPAPI php_stream *_php_stream_open_wrapper(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
{
php_stream *stream = NULL;
@@ -1034,13 +1071,15 @@ out:
}
return stream;
}
+/* }}} */
+/* {{{ php_stream_open_wrapper_as_file */
PHPAPI FILE * _php_stream_open_wrapper_as_file(char *path, char *mode, int options, char **opened_path STREAMS_DC TSRMLS_DC)
{
FILE *fp = NULL;
php_stream *stream = NULL;
- stream = php_stream_open_wrapper(path, mode, options, opened_path);
+ stream = php_stream_open_wrapper_rel(path, mode, options, opened_path);
if (stream == NULL)
return NULL;
@@ -1055,9 +1094,9 @@ PHPAPI FILE * _php_stream_open_wrapper_as_file(char *path, char *mode, int optio
}
return fp;
}
+/* }}} */
-#define PHP_STREAM_MAX_MEM 2 * 1024 * 1024
-
+/* {{{ php_stream_make_seekable */
PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstream, int flags STREAMS_DC TSRMLS_DC)
{
assert(newstream != NULL);
@@ -1090,6 +1129,7 @@ PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstr
return PHP_STREAM_RELEASED;
}
+/* }}} */
/*
* Local variables:
diff --git a/main/user_streams.c b/main/user_streams.c
index 898ad5e099..ab90e1cd3b 100644
--- a/main/user_streams.c
+++ b/main/user_streams.c
@@ -115,7 +115,7 @@ static php_stream *user_wrapper_factory(char *filename, char *mode, int options,
zval **args[4];
int call_result;
php_stream *stream = NULL;
-
+
us = emalloc(sizeof(*us));
us->wrapper = uwrap;