Streams are all tracked as resources now.

Add some logic that will help track down leaks
when debug is enabled.
This commit is contained in:
Wez Furlong 2002-03-20 14:21:30 +00:00
parent 14d62c7b62
commit 659a071e3d
10 changed files with 83 additions and 37 deletions

View file

@ -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;

View file

@ -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;
}

View file

@ -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))) {

View file

@ -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);
}

View file

@ -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);
}
/* }}} */

View file

@ -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) {

View file

@ -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);
}

View file

@ -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)

View file

@ -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:

View file

@ -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;