mirror of
https://github.com/php/php-src.git
synced 2025-08-15 21:48:51 +02:00
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:
parent
14d62c7b62
commit
659a071e3d
10 changed files with 83 additions and 37 deletions
|
@ -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;
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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))) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
/* }}} */
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
|
|
|
@ -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:
|
||||
|
|
|
@ -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;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue