Skip to content

Commit

Permalink
Streams are all tracked as resources now.
Browse files Browse the repository at this point in the history
Add some logic that will help track down leaks
when debug is enabled.
  • Loading branch information
wez committed Mar 20, 2002
1 parent 14d62c7 commit 659a071
Show file tree
Hide file tree
Showing 10 changed files with 83 additions and 37 deletions.
5 changes: 1 addition & 4 deletions ext/exif/exif.c
Expand Up @@ -3254,7 +3254,6 @@ PHP_FUNCTION(exif_imagetype)
{
zval **arg1;
php_stream * stream;
int rsrc_id;
int itype = 0;

if (ZEND_NUM_ARGS() != 1)
Expand All @@ -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;
Expand Down
2 changes: 1 addition & 1 deletion ext/pgsql/pgsql.c
Expand Up @@ -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;
}
Expand Down
6 changes: 1 addition & 5 deletions ext/standard/exec.c
Expand Up @@ -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
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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))) {
Expand Down
12 changes: 7 additions & 5 deletions ext/standard/file.c
Expand Up @@ -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)
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
}
/* }}} */
Expand Down Expand Up @@ -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);
}
Expand Down
4 changes: 2 additions & 2 deletions ext/standard/fsock.c
Expand Up @@ -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;
}

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

/* }}} */
Expand Down
5 changes: 1 addition & 4 deletions ext/standard/image.c
Expand Up @@ -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;
Expand Down Expand Up @@ -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:
Expand Down Expand Up @@ -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) {
Expand Down
10 changes: 2 additions & 8 deletions ext/zlib/zlib.c
Expand Up @@ -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);
}
Expand Down
20 changes: 20 additions & 0 deletions main/php_streams.h
Expand Up @@ -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
Expand All @@ -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)
Expand Down
54 changes: 47 additions & 7 deletions main/streams.c
Expand Up @@ -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>
Expand All @@ -35,6 +36,7 @@
#endif

#define CHUNK_SIZE 8192
#define PHP_STREAM_MAX_MEM 2 * 1024 * 1024

#ifdef PHP_WIN32
#define EWOULDBLOCK WSAEWOULDBLOCK
Expand Down Expand Up @@ -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;
Expand All @@ -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
Expand All @@ -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);
}

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

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -902,8 +933,10 @@ PHPAPI int _php_stream_cast(php_stream *stream, int castas, void **ret, int show

return SUCCESS;

} /* }}} */
}
/* }}} */

/* {{{ wrapper init and registration */
int php_init_stream_wrappers(TSRMLS_D)
{
if (PG(allow_url_fopen)) {
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -1034,13 +1071,15 @@ PHPAPI php_stream *_php_stream_open_wrapper(char *path, char *mode, int options,
}
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;
Expand All @@ -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);
Expand Down Expand Up @@ -1090,6 +1129,7 @@ PHPAPI int _php_stream_make_seekable(php_stream *origstream, php_stream **newstr

return PHP_STREAM_RELEASED;
}
/* }}} */

/*
* Local variables:
Expand Down
2 changes: 1 addition & 1 deletion main/user_streams.c
Expand Up @@ -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;

Expand Down

0 comments on commit 659a071

Please sign in to comment.