]> granicus.if.org Git - php/commitdiff
Back memory stream by a zend_string
authorNikita Popov <nikita.ppv@gmail.com>
Fri, 18 Dec 2020 16:07:07 +0000 (17:07 +0100)
committerNikita Popov <nikita.ppv@gmail.com>
Fri, 18 Dec 2020 16:07:07 +0000 (17:07 +0100)
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.

ext/pdo/pdo_stmt.c
ext/pdo_pgsql/pgsql_statement.c
ext/standard/image.c
main/php_memory_streams.h
main/streams/memory.c

index bab869eaf848a9e3a7eb42f4013729498c42e572..e9103425822159c9dd92946804d407fb950d2a43 100644 (file)
@@ -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 {
index 89513fe9ccafa8f97cc43158ef6a462f3e2d40e1..bf07af59a58b2aff578a07862e64c517c2c376df 100644 (file)
@@ -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 {
index f34f14a7aa57caacb5666d3728828e902c71ef80..fc22ed3f754bab72f878983c640b61c8fe3091c4 100644 (file)
@@ -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);
 }
 /* }}} */
index 5d0b978aadac236bb098553e22d5947610631b05..030784e6f646a90258305e2c18f9d042f6e206a2 100644 (file)
@@ -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);
index bc8f7b9983715cf04423c09cf9d4d03997225468..36515b85436ba68b85ece99d338bcf3794696f3b 100644 (file)
@@ -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);