diff options
author | Gustavo André dos Santos Lopes <cataphract@php.net> | 2010-11-15 03:05:32 +0000 |
---|---|---|
committer | Gustavo André dos Santos Lopes <cataphract@php.net> | 2010-11-15 03:05:32 +0000 |
commit | 3a02cfb675da68e81c40226135ac4121e72f1378 (patch) | |
tree | 5b12179631cac1861db37b75fd3ff75e00671661 /main/streams | |
parent | 24636a7e1c54015d916fff82b2c55074f74238fc (diff) | |
download | php-git-3a02cfb675da68e81c40226135ac4121e72f1378.tar.gz |
- Added leak_variable() function.
- Added mechanism to force outer streams to be closed before their inner ones.
- Fixed temp:// streams only handling correctly (through an ad hoc mechanism) reverse closing order
when the inner stream is of type memory.
Diffstat (limited to 'main/streams')
-rw-r--r-- | main/streams/memory.c | 18 | ||||
-rwxr-xr-x | main/streams/streams.c | 79 |
2 files changed, 82 insertions, 15 deletions
diff --git a/main/streams/memory.c b/main/streams/memory.c index b22d0f2193..e2a2a334c6 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -42,7 +42,6 @@ typedef struct { size_t fsize; size_t smax; int mode; - php_stream **owner_ptr; } php_stream_memory_data; @@ -112,9 +111,6 @@ static int php_stream_memory_close(php_stream *stream, int close_handle TSRMLS_D if (ms->data && close_handle && ms->mode != TEMP_STREAM_READONLY) { efree(ms->data); } - if (ms->owner_ptr) { - *ms->owner_ptr = NULL; - } efree(ms); return 0; } @@ -301,7 +297,6 @@ PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC TSRMLS_DC) self->fsize = 0; self->smax = ~0u; self->mode = mode; - self->owner_ptr = NULL; stream = php_stream_alloc_rel(&php_stream_memory_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b"); stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; @@ -376,8 +371,9 @@ static size_t php_stream_temp_write(php_stream *stream, const char *buf, size_t if (memsize + count >= ts->smax) { php_stream *file = php_stream_fopen_tmpfile(); php_stream_write(file, membuf, memsize); - php_stream_close(ts->innerstream); + php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE); ts->innerstream = file; + php_stream_encloses(stream, ts->innerstream); } } return php_stream_write(ts->innerstream, buf, count); @@ -415,7 +411,7 @@ static int php_stream_temp_close(php_stream *stream, int close_handle TSRMLS_DC) assert(ts != NULL); if (ts->innerstream) { - ret = php_stream_free(ts->innerstream, PHP_STREAM_FREE_CLOSE | (close_handle ? 0 : PHP_STREAM_FREE_PRESERVE_HANDLE)); + ret = php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE | (close_handle ? 0 : PHP_STREAM_FREE_PRESERVE_HANDLE)); } else { ret = 0; } @@ -499,9 +495,10 @@ static int php_stream_temp_cast(php_stream *stream, int castas, void **ret TSRML file = php_stream_fopen_tmpfile(); php_stream_write(file, membuf, memsize); pos = php_stream_tell(ts->innerstream); - - php_stream_close(ts->innerstream); + + php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE); ts->innerstream = file; + php_stream_encloses(stream, ts->innerstream); php_stream_seek(ts->innerstream, pos, SEEK_SET); return php_stream_cast(ts->innerstream, castas, ret, 1); @@ -563,8 +560,7 @@ PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STR stream = php_stream_alloc_rel(&php_stream_temp_ops, self, 0, mode & TEMP_STREAM_READONLY ? "rb" : "w+b"); stream->flags |= PHP_STREAM_FLAG_NO_BUFFER; self->innerstream = php_stream_memory_create_rel(mode); - php_stream_auto_cleanup(self->innerstream); /* do not warn if innerstream is GC'ed before stream */ - ((php_stream_memory_data*)self->innerstream->abstract)->owner_ptr = &self->innerstream; + php_stream_encloses(stream, self->innerstream); return stream; } diff --git a/main/streams/streams.c b/main/streams/streams.c index 54ea92d9a1..b3f40422c3 100755 --- a/main/streams/streams.c +++ b/main/streams/streams.c @@ -105,6 +105,15 @@ PHP_RSHUTDOWN_FUNCTION(streams) return SUCCESS; } +PHPAPI php_stream *php_stream_encloses(php_stream *enclosing, php_stream *enclosed) +{ + php_stream *orig = enclosed->enclosing_stream; + + php_stream_auto_cleanup(enclosed); + enclosed->enclosing_stream = enclosing; + return orig; +} + PHPAPI int php_stream_from_persistent_id(const char *persistent_id, php_stream **stream TSRMLS_DC) { zend_rsrc_list_entry *le; @@ -272,15 +281,53 @@ fprintf(stderr, "stream_alloc: %s:%p persistent=%s\n", ops->label, ret, persiste ret->rsrc_id = ZEND_REGISTER_RESOURCE(NULL, ret, persistent_id ? le_pstream : le_stream); strlcpy(ret->mode, mode, sizeof(ret->mode)); + ret->wrapper = NULL; + ret->wrapperthis = NULL; + ret->wrapperdata = NULL; + ret->stdiocast = NULL; + ret->orig_path = NULL; + ret->context = NULL; + ret->readbuf = NULL; + ret->enclosing_stream = NULL; + return ret; } /* }}} */ +PHPAPI int _php_stream_free_enclosed(php_stream *stream_enclosed, int close_options TSRMLS_DC) /* {{{ */ +{ + return _php_stream_free(stream_enclosed, + close_options | PHP_STREAM_FREE_IGNORE_ENCLOSING TSRMLS_CC); +} +/* }}} */ + +#if STREAM_DEBUG +static const char *_php_stream_pretty_free_options(int close_options, char *out) +{ + if (close_options & PHP_STREAM_FREE_CALL_DTOR) + strcat(out, "CALL_DTOR, "); + if (close_options & PHP_STREAM_FREE_RELEASE_STREAM) + strcat(out, "RELEASE_STREAM, "); + if (close_options & PHP_STREAM_FREE_PRESERVE_HANDLE) + strcat(out, "PREVERSE_HANDLE, "); + if (close_options & PHP_STREAM_FREE_RSRC_DTOR) + strcat(out, "RSRC_DTOR, "); + if (close_options & PHP_STREAM_FREE_PERSISTENT) + strcat(out, "PERSISTENT, "); + if (close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING) + strcat(out, "IGNORE_ENCLOSING, "); + if (out[0] != '\0') + out[strlen(out) - 2] = '\0'; + return out; +} +#endif + static int _php_stream_free_persistent(zend_rsrc_list_entry *le, void *pStream TSRMLS_DC) { return le->ptr == pStream; } + PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* {{{ */ { int ret = 1; @@ -294,16 +341,40 @@ PHPAPI int _php_stream_free(php_stream *stream, int close_options TSRMLS_DC) /* } #if STREAM_DEBUG -fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%08x\n", stream->ops->label, stream, stream->orig_path, stream->in_free, close_options); + { + char out[200] = ""; + fprintf(stderr, "stream_free: %s:%p[%s] in_free=%d opts=%s\n", + stream->ops->label, stream, stream->orig_path, stream->in_free, _php_stream_pretty_free_options(close_options, out)); + } + #endif - /* recursion protection */ if (stream->in_free) { - return 1; + /* hopefully called recursively from the enclosing stream; the pointer was NULLed below */ + if ((stream->in_free == 1) && (close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING) && (stream->enclosing_stream == NULL)) { + close_options |= PHP_STREAM_FREE_RSRC_DTOR; /* restore flag */ + } else { + return 1; /* recursion protection */ + } } stream->in_free++; + /* force correct order on enclosing/enclosed stream destruction (only from resource + * destructor as in when reverse destroying the resource list) */ + if ((close_options & PHP_STREAM_FREE_RSRC_DTOR) && + !(close_options & PHP_STREAM_FREE_IGNORE_ENCLOSING) && + (close_options & (PHP_STREAM_FREE_CALL_DTOR | PHP_STREAM_FREE_RELEASE_STREAM)) && /* always? */ + (stream->enclosing_stream != NULL)) { + php_stream *enclosing_stream = stream->enclosing_stream; + stream->enclosing_stream = NULL; + /* we force PHP_STREAM_CALL_DTOR because that's from where the + * enclosing stream can free this stream. We remove rsrc_dtor because + * we want the enclosing stream to be deleted from the resource list */ + return _php_stream_free(enclosing_stream, + (close_options | PHP_STREAM_FREE_CALL_DTOR) & ~PHP_STREAM_FREE_RSRC_DTOR TSRMLS_CC); + } + /* if we are releasing the stream only (and preserving the underlying handle), * we need to do things a little differently. * We are only ever called like this when the stream is cast to a FILE* @@ -404,7 +475,7 @@ fprintf(stderr, "stream_free: %s:%p[%s] preserve_handle=%d release_cast=%d remov stream->orig_path = NULL; } -# if defined(PHP_WIN32) +# if defined(PHP_WIN32_) OutputDebugString(leakinfo); # else fprintf(stderr, "%s", leakinfo); |