From: Nikita Popov Date: Fri, 18 Dec 2020 16:07:07 +0000 (+0100) Subject: Back memory stream by a zend_string X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=7904a087ec4fc156c52e0f5e8e15d798808f7843;p=php Back memory stream by a zend_string This allows reusing an existing zend_string inside a memory stream without reallocating. For non-readonly streams, the string will only get separated on write. --- diff --git a/ext/pdo/pdo_stmt.c b/ext/pdo/pdo_stmt.c index bab869eaf8..e910342582 100644 --- a/ext/pdo/pdo_stmt.c +++ b/ext/pdo/pdo_stmt.c @@ -569,18 +569,8 @@ static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *typ } } else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) { /* they gave us a string, but LOBs are represented as streams in PDO */ - php_stream *stm; -#ifdef TEMP_STREAM_TAKE_BUFFER - if (caller_frees) { - stm = php_stream_memory_open(TEMP_STREAM_TAKE_BUFFER, value, value_len); - if (stm) { - caller_frees = 0; - } - } else -#endif - { - stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len); - } + php_stream *stm = php_stream_memory_open(TEMP_STREAM_READONLY, + zend_string_init(value, value_len, 0)); if (stm) { php_stream_to_zval(stm, dest); } else { diff --git a/ext/pdo_pgsql/pgsql_statement.c b/ext/pdo_pgsql/pgsql_statement.c index 89513fe9cc..bf07af59a5 100644 --- a/ext/pdo_pgsql/pgsql_statement.c +++ b/ext/pdo_pgsql/pgsql_statement.c @@ -579,7 +579,7 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *l } if (!tmp_len) { /* Empty string, return as empty stream */ - *ptr = (char *)php_stream_memory_open(TEMP_STREAM_READONLY, "", 0); + *ptr = (char *)php_stream_memory_create(TEMP_STREAM_READONLY); PQfreemem(tmp_ptr); *len = 0; } else { diff --git a/ext/standard/image.c b/ext/standard/image.c index f34f14a7aa..fc22ed3f75 100644 --- a/ext/standard/image.c +++ b/ext/standard/image.c @@ -1465,17 +1465,16 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval * static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) { /* {{{ */ zval *info = NULL; php_stream *stream = NULL; - char *input; - size_t input_len; + zend_string *input; const int argc = ZEND_NUM_ARGS(); ZEND_PARSE_PARAMETERS_START(1, 2) - Z_PARAM_STRING(input, input_len) + Z_PARAM_STR(input) Z_PARAM_OPTIONAL Z_PARAM_ZVAL(info) ZEND_PARSE_PARAMETERS_END(); - if (mode == FROM_PATH && CHECK_NULL_PATH(input, input_len)) { + if (mode == FROM_PATH && CHECK_NULL_PATH(ZSTR_VAL(input), ZSTR_LEN(input))) { zend_argument_value_error(1, "must not contain any null bytes"); RETURN_THROWS(); } @@ -1488,16 +1487,16 @@ static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) { } if (mode == FROM_PATH) { - stream = php_stream_open_wrapper(input, "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH, NULL); + stream = php_stream_open_wrapper(ZSTR_VAL(input), "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH, NULL); } else { - stream = php_stream_memory_open(TEMP_STREAM_READONLY, input, input_len); + stream = php_stream_memory_open(TEMP_STREAM_READONLY, input); } if (!stream) { RETURN_FALSE; } - php_getimagesize_from_stream(stream, input, info, INTERNAL_FUNCTION_PARAM_PASSTHRU); + php_getimagesize_from_stream(stream, ZSTR_VAL(input), info, INTERNAL_FUNCTION_PARAM_PASSTHRU); php_stream_close(stream); } /* }}} */ diff --git a/main/php_memory_streams.h b/main/php_memory_streams.h index 5d0b978aad..030784e6f6 100644 --- a/main/php_memory_streams.h +++ b/main/php_memory_streams.h @@ -28,8 +28,8 @@ #define php_stream_memory_create(mode) _php_stream_memory_create((mode) STREAMS_CC) #define php_stream_memory_create_rel(mode) _php_stream_memory_create((mode) STREAMS_REL_CC) -#define php_stream_memory_open(mode, buf, length) _php_stream_memory_open((mode), (buf), (length) STREAMS_CC) -#define php_stream_memory_get_buffer(stream, length) _php_stream_memory_get_buffer((stream), (length) STREAMS_CC) +#define php_stream_memory_open(mode, str) _php_stream_memory_open((mode), (str) STREAMS_CC) +#define php_stream_memory_get_buffer(stream) _php_stream_memory_get_buffer((stream) STREAMS_CC) #define php_stream_temp_new() php_stream_temp_create(TEMP_STREAM_DEFAULT, PHP_STREAM_MAX_MEM) #define php_stream_temp_create(mode, max_memory_usage) _php_stream_temp_create((mode), (max_memory_usage) STREAMS_CC) @@ -40,8 +40,8 @@ BEGIN_EXTERN_C() PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC); -PHPAPI php_stream *_php_stream_memory_open(int mode, const char *buf, size_t length STREAMS_DC); -PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length STREAMS_DC); +PHPAPI php_stream *_php_stream_memory_open(int mode, zend_string *buf STREAMS_DC); +PHPAPI zend_string *_php_stream_memory_get_buffer(php_stream *stream STREAMS_DC); PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STREAMS_DC); PHPAPI php_stream *_php_stream_temp_create_ex(int mode, size_t max_memory_usage, const char *tmpdir STREAMS_DC); diff --git a/main/streams/memory.c b/main/streams/memory.c index bc8f7b9983..36515b8543 100644 --- a/main/streams/memory.c +++ b/main/streams/memory.c @@ -33,9 +33,8 @@ PHPAPI size_t php_url_decode(char *str, size_t len); /* {{{ ------- MEMORY stream implementation -------*/ typedef struct { - char *data; + zend_string *data; size_t fpos; - size_t fsize; int mode; } php_stream_memory_data; @@ -49,23 +48,16 @@ static ssize_t php_stream_memory_write(php_stream *stream, const char *buf, size if (ms->mode & TEMP_STREAM_READONLY) { return (ssize_t) -1; } else if (ms->mode & TEMP_STREAM_APPEND) { - ms->fpos = ms->fsize; + ms->fpos = ZSTR_LEN(ms->data); } - if (ms->fpos + count > ms->fsize) { - char *tmp; - if (!ms->data) { - tmp = emalloc(ms->fpos + count); - } else { - tmp = erealloc(ms->data, ms->fpos + count); - } - ms->data = tmp; - ms->fsize = ms->fpos + count; + if (ms->fpos + count > ZSTR_LEN(ms->data)) { + ms->data = zend_string_realloc(ms->data, ms->fpos + count, 0); + } else { + ms->data = zend_string_separate(ms->data, 0); } - if (!ms->data) - count = 0; if (count) { - assert(buf!= NULL); - memcpy(ms->data+ms->fpos, (char*)buf, count); + ZEND_ASSERT(buf != NULL); + memcpy(ZSTR_VAL(ms->data) + ms->fpos, (char*) buf, count); ms->fpos += count; } return count; @@ -79,17 +71,16 @@ static ssize_t php_stream_memory_read(php_stream *stream, char *buf, size_t coun php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; assert(ms != NULL); - if (ms->fpos == ms->fsize) { + if (ms->fpos == ZSTR_LEN(ms->data)) { stream->eof = 1; count = 0; } else { - if (ms->fpos + count >= ms->fsize) { - count = ms->fsize - ms->fpos; + if (ms->fpos + count > ZSTR_LEN(ms->data)) { + count = ZSTR_LEN(ms->data) - ms->fpos; } if (count) { - assert(ms->data!= NULL); - assert(buf!= NULL); - memcpy(buf, ms->data+ms->fpos, count); + ZEND_ASSERT(buf != NULL); + memcpy(buf, ZSTR_VAL(ms->data) + ms->fpos, count); ms->fpos += count; } } @@ -102,11 +93,8 @@ static ssize_t php_stream_memory_read(php_stream *stream, char *buf, size_t coun static int php_stream_memory_close(php_stream *stream, int close_handle) { php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; - assert(ms != NULL); - - if (ms->data && close_handle && ms->mode != TEMP_STREAM_READONLY) { - efree(ms->data); - } + ZEND_ASSERT(ms != NULL); + zend_string_release(ms->data); efree(ms); return 0; } @@ -142,8 +130,8 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe return 0; } } else { - if (ms->fpos + (size_t)(offset) > ms->fsize) { - ms->fpos = ms->fsize; + if (ms->fpos + (size_t)(offset) > ZSTR_LEN(ms->data)) { + ms->fpos = ZSTR_LEN(ms->data); *newoffs = -1; return -1; } else { @@ -154,8 +142,8 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe } } case SEEK_SET: - if (ms->fsize < (size_t)(offset)) { - ms->fpos = ms->fsize; + if (ZSTR_LEN(ms->data) < (size_t)(offset)) { + ms->fpos = ZSTR_LEN(ms->data); *newoffs = -1; return -1; } else { @@ -166,15 +154,15 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe } case SEEK_END: if (offset > 0) { - ms->fpos = ms->fsize; + ms->fpos = ZSTR_LEN(ms->data); *newoffs = -1; return -1; - } else if (ms->fsize < (size_t)(-offset)) { + } else if (ZSTR_LEN(ms->data) < (size_t)(-offset)) { ms->fpos = 0; *newoffs = -1; return -1; } else { - ms->fpos = ms->fsize + offset; + ms->fpos = ZSTR_LEN(ms->data) + offset; *newoffs = ms->fpos; stream->eof = 0; return 0; @@ -204,7 +192,7 @@ static int php_stream_memory_stat(php_stream *stream, php_stream_statbuf *ssb) / ssb->sb.st_mode = ms->mode & TEMP_STREAM_READONLY ? 0444 : 0666; - ssb->sb.st_size = ms->fsize; + ssb->sb.st_size = ZSTR_LEN(ms->data); ssb->sb.st_mode |= S_IFREG; /* regular file */ ssb->sb.st_mtime = timestamp; ssb->sb.st_atime = timestamp; @@ -241,16 +229,16 @@ static int php_stream_memory_set_option(php_stream *stream, int option, int valu return PHP_STREAM_OPTION_RETURN_ERR; } newsize = *(size_t*)ptrparam; - if (newsize <= ms->fsize) { + if (newsize <= ZSTR_LEN(ms->data)) { + ms->data = zend_string_truncate(ms->data, newsize, 0); if (newsize < ms->fpos) { ms->fpos = newsize; } } else { - ms->data = erealloc(ms->data, newsize); - memset(ms->data+ms->fsize, 0, newsize - ms->fsize); - ms->fsize = newsize; + size_t old_size = ZSTR_LEN(ms->data); + ms->data = zend_string_realloc(ms->data, newsize, 0); + memset(ZSTR_VAL(ms->data) + old_size, 0, newsize - old_size); } - ms->fsize = newsize; return PHP_STREAM_OPTION_RETURN_OK; } } @@ -300,9 +288,8 @@ PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC) php_stream *stream; self = emalloc(sizeof(*self)); - self->data = NULL; + self->data = ZSTR_EMPTY_ALLOC(); self->fpos = 0; - self->fsize = 0; self->mode = mode; stream = php_stream_alloc_rel(&php_stream_memory_ops, self, 0, _php_stream_mode_to_str(mode)); @@ -313,24 +300,14 @@ PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC) /* {{{ */ -PHPAPI php_stream *_php_stream_memory_open(int mode, const char *buf, size_t length STREAMS_DC) +PHPAPI php_stream *_php_stream_memory_open(int mode, zend_string *buf STREAMS_DC) { php_stream *stream; php_stream_memory_data *ms; if ((stream = php_stream_memory_create_rel(mode)) != NULL) { ms = (php_stream_memory_data*)stream->abstract; - - if (mode == TEMP_STREAM_READONLY || mode == TEMP_STREAM_TAKE_BUFFER) { - /* use the buffer directly */ - ms->data = (char *) buf; - ms->fsize = length; - } else { - if (length) { - assert(buf != NULL); - php_stream_write(stream, buf, length); - } - } + ms->data = zend_string_copy(buf); } return stream; } @@ -338,14 +315,10 @@ PHPAPI php_stream *_php_stream_memory_open(int mode, const char *buf, size_t len /* {{{ */ -PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length STREAMS_DC) +PHPAPI zend_string *_php_stream_memory_get_buffer(php_stream *stream STREAMS_DC) { php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract; - - assert(ms != NULL); - assert(length != 0); - - *length = ms->fsize; + ZEND_ASSERT(ms != NULL); return ms->data; } /* }}} */ @@ -373,16 +346,15 @@ static ssize_t php_stream_temp_write(php_stream *stream, const char *buf, size_t return -1; } if (php_stream_is(ts->innerstream, PHP_STREAM_IS_MEMORY)) { - size_t memsize; - char *membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize); + zend_string *membuf = php_stream_memory_get_buffer(ts->innerstream); - if (memsize + count >= ts->smax) { + if (ZSTR_LEN(membuf) + count >= ts->smax) { php_stream *file = php_stream_fopen_temporary_file(ts->tmpdir, "php", NULL); if (file == NULL) { php_error_docref(NULL, E_WARNING, "Unable to create temporary file, Check permissions in temporary files directory."); return 0; } - php_stream_write(file, membuf, memsize); + php_stream_write(file, ZSTR_VAL(membuf), ZSTR_LEN(membuf)); php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE); ts->innerstream = file; php_stream_encloses(stream, ts->innerstream); @@ -477,8 +449,7 @@ static int php_stream_temp_cast(php_stream *stream, int castas, void **ret) { php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract; php_stream *file; - size_t memsize; - char *membuf; + zend_string *membuf; zend_off_t pos; assert(ts != NULL); @@ -511,8 +482,8 @@ static int php_stream_temp_cast(php_stream *stream, int castas, void **ret) } /* perform the conversion and then pass the request on to the innerstream */ - membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize); - php_stream_write(file, membuf, memsize); + membuf = php_stream_memory_get_buffer(ts->innerstream); + php_stream_write(file, ZSTR_VAL(membuf), ZSTR_LEN(membuf)); pos = php_stream_tell(ts->innerstream); php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);