Skip to content

Commit 7904a08

Browse files
committed
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.
1 parent 9ec6392 commit 7904a08

File tree

5 files changed

+52
-92
lines changed

5 files changed

+52
-92
lines changed

ext/pdo/pdo_stmt.c

Lines changed: 2 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -569,18 +569,8 @@ static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *typ
569569
}
570570
} else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) {
571571
/* they gave us a string, but LOBs are represented as streams in PDO */
572-
php_stream *stm;
573-
#ifdef TEMP_STREAM_TAKE_BUFFER
574-
if (caller_frees) {
575-
stm = php_stream_memory_open(TEMP_STREAM_TAKE_BUFFER, value, value_len);
576-
if (stm) {
577-
caller_frees = 0;
578-
}
579-
} else
580-
#endif
581-
{
582-
stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len);
583-
}
572+
php_stream *stm = php_stream_memory_open(TEMP_STREAM_READONLY,
573+
zend_string_init(value, value_len, 0));
584574
if (stm) {
585575
php_stream_to_zval(stm, dest);
586576
} else {

ext/pdo_pgsql/pgsql_statement.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -579,7 +579,7 @@ static int pgsql_stmt_get_col(pdo_stmt_t *stmt, int colno, char **ptr, size_t *l
579579
}
580580
if (!tmp_len) {
581581
/* Empty string, return as empty stream */
582-
*ptr = (char *)php_stream_memory_open(TEMP_STREAM_READONLY, "", 0);
582+
*ptr = (char *)php_stream_memory_create(TEMP_STREAM_READONLY);
583583
PQfreemem(tmp_ptr);
584584
*len = 0;
585585
} else {

ext/standard/image.c

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1465,17 +1465,16 @@ static void php_getimagesize_from_stream(php_stream *stream, char *input, zval *
14651465
static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) { /* {{{ */
14661466
zval *info = NULL;
14671467
php_stream *stream = NULL;
1468-
char *input;
1469-
size_t input_len;
1468+
zend_string *input;
14701469
const int argc = ZEND_NUM_ARGS();
14711470

14721471
ZEND_PARSE_PARAMETERS_START(1, 2)
1473-
Z_PARAM_STRING(input, input_len)
1472+
Z_PARAM_STR(input)
14741473
Z_PARAM_OPTIONAL
14751474
Z_PARAM_ZVAL(info)
14761475
ZEND_PARSE_PARAMETERS_END();
14771476

1478-
if (mode == FROM_PATH && CHECK_NULL_PATH(input, input_len)) {
1477+
if (mode == FROM_PATH && CHECK_NULL_PATH(ZSTR_VAL(input), ZSTR_LEN(input))) {
14791478
zend_argument_value_error(1, "must not contain any null bytes");
14801479
RETURN_THROWS();
14811480
}
@@ -1488,16 +1487,16 @@ static void php_getimagesize_from_any(INTERNAL_FUNCTION_PARAMETERS, int mode) {
14881487
}
14891488

14901489
if (mode == FROM_PATH) {
1491-
stream = php_stream_open_wrapper(input, "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH, NULL);
1490+
stream = php_stream_open_wrapper(ZSTR_VAL(input), "rb", STREAM_MUST_SEEK|REPORT_ERRORS|IGNORE_PATH, NULL);
14921491
} else {
1493-
stream = php_stream_memory_open(TEMP_STREAM_READONLY, input, input_len);
1492+
stream = php_stream_memory_open(TEMP_STREAM_READONLY, input);
14941493
}
14951494

14961495
if (!stream) {
14971496
RETURN_FALSE;
14981497
}
14991498

1500-
php_getimagesize_from_stream(stream, input, info, INTERNAL_FUNCTION_PARAM_PASSTHRU);
1499+
php_getimagesize_from_stream(stream, ZSTR_VAL(input), info, INTERNAL_FUNCTION_PARAM_PASSTHRU);
15011500
php_stream_close(stream);
15021501
}
15031502
/* }}} */

main/php_memory_streams.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@
2828

2929
#define php_stream_memory_create(mode) _php_stream_memory_create((mode) STREAMS_CC)
3030
#define php_stream_memory_create_rel(mode) _php_stream_memory_create((mode) STREAMS_REL_CC)
31-
#define php_stream_memory_open(mode, buf, length) _php_stream_memory_open((mode), (buf), (length) STREAMS_CC)
32-
#define php_stream_memory_get_buffer(stream, length) _php_stream_memory_get_buffer((stream), (length) STREAMS_CC)
31+
#define php_stream_memory_open(mode, str) _php_stream_memory_open((mode), (str) STREAMS_CC)
32+
#define php_stream_memory_get_buffer(stream) _php_stream_memory_get_buffer((stream) STREAMS_CC)
3333

3434
#define php_stream_temp_new() php_stream_temp_create(TEMP_STREAM_DEFAULT, PHP_STREAM_MAX_MEM)
3535
#define php_stream_temp_create(mode, max_memory_usage) _php_stream_temp_create((mode), (max_memory_usage) STREAMS_CC)
@@ -40,8 +40,8 @@
4040
BEGIN_EXTERN_C()
4141

4242
PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC);
43-
PHPAPI php_stream *_php_stream_memory_open(int mode, const char *buf, size_t length STREAMS_DC);
44-
PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length STREAMS_DC);
43+
PHPAPI php_stream *_php_stream_memory_open(int mode, zend_string *buf STREAMS_DC);
44+
PHPAPI zend_string *_php_stream_memory_get_buffer(php_stream *stream STREAMS_DC);
4545

4646
PHPAPI php_stream *_php_stream_temp_create(int mode, size_t max_memory_usage STREAMS_DC);
4747
PHPAPI php_stream *_php_stream_temp_create_ex(int mode, size_t max_memory_usage, const char *tmpdir STREAMS_DC);

main/streams/memory.c

Lines changed: 39 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,8 @@ PHPAPI size_t php_url_decode(char *str, size_t len);
3333
/* {{{ ------- MEMORY stream implementation -------*/
3434

3535
typedef struct {
36-
char *data;
36+
zend_string *data;
3737
size_t fpos;
38-
size_t fsize;
3938
int mode;
4039
} php_stream_memory_data;
4140

@@ -49,23 +48,16 @@ static ssize_t php_stream_memory_write(php_stream *stream, const char *buf, size
4948
if (ms->mode & TEMP_STREAM_READONLY) {
5049
return (ssize_t) -1;
5150
} else if (ms->mode & TEMP_STREAM_APPEND) {
52-
ms->fpos = ms->fsize;
51+
ms->fpos = ZSTR_LEN(ms->data);
5352
}
54-
if (ms->fpos + count > ms->fsize) {
55-
char *tmp;
56-
if (!ms->data) {
57-
tmp = emalloc(ms->fpos + count);
58-
} else {
59-
tmp = erealloc(ms->data, ms->fpos + count);
60-
}
61-
ms->data = tmp;
62-
ms->fsize = ms->fpos + count;
53+
if (ms->fpos + count > ZSTR_LEN(ms->data)) {
54+
ms->data = zend_string_realloc(ms->data, ms->fpos + count, 0);
55+
} else {
56+
ms->data = zend_string_separate(ms->data, 0);
6357
}
64-
if (!ms->data)
65-
count = 0;
6658
if (count) {
67-
assert(buf!= NULL);
68-
memcpy(ms->data+ms->fpos, (char*)buf, count);
59+
ZEND_ASSERT(buf != NULL);
60+
memcpy(ZSTR_VAL(ms->data) + ms->fpos, (char*) buf, count);
6961
ms->fpos += count;
7062
}
7163
return count;
@@ -79,17 +71,16 @@ static ssize_t php_stream_memory_read(php_stream *stream, char *buf, size_t coun
7971
php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
8072
assert(ms != NULL);
8173

82-
if (ms->fpos == ms->fsize) {
74+
if (ms->fpos == ZSTR_LEN(ms->data)) {
8375
stream->eof = 1;
8476
count = 0;
8577
} else {
86-
if (ms->fpos + count >= ms->fsize) {
87-
count = ms->fsize - ms->fpos;
78+
if (ms->fpos + count > ZSTR_LEN(ms->data)) {
79+
count = ZSTR_LEN(ms->data) - ms->fpos;
8880
}
8981
if (count) {
90-
assert(ms->data!= NULL);
91-
assert(buf!= NULL);
92-
memcpy(buf, ms->data+ms->fpos, count);
82+
ZEND_ASSERT(buf != NULL);
83+
memcpy(buf, ZSTR_VAL(ms->data) + ms->fpos, count);
9384
ms->fpos += count;
9485
}
9586
}
@@ -102,11 +93,8 @@ static ssize_t php_stream_memory_read(php_stream *stream, char *buf, size_t coun
10293
static int php_stream_memory_close(php_stream *stream, int close_handle)
10394
{
10495
php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
105-
assert(ms != NULL);
106-
107-
if (ms->data && close_handle && ms->mode != TEMP_STREAM_READONLY) {
108-
efree(ms->data);
109-
}
96+
ZEND_ASSERT(ms != NULL);
97+
zend_string_release(ms->data);
11098
efree(ms);
11199
return 0;
112100
}
@@ -142,8 +130,8 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe
142130
return 0;
143131
}
144132
} else {
145-
if (ms->fpos + (size_t)(offset) > ms->fsize) {
146-
ms->fpos = ms->fsize;
133+
if (ms->fpos + (size_t)(offset) > ZSTR_LEN(ms->data)) {
134+
ms->fpos = ZSTR_LEN(ms->data);
147135
*newoffs = -1;
148136
return -1;
149137
} else {
@@ -154,8 +142,8 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe
154142
}
155143
}
156144
case SEEK_SET:
157-
if (ms->fsize < (size_t)(offset)) {
158-
ms->fpos = ms->fsize;
145+
if (ZSTR_LEN(ms->data) < (size_t)(offset)) {
146+
ms->fpos = ZSTR_LEN(ms->data);
159147
*newoffs = -1;
160148
return -1;
161149
} else {
@@ -166,15 +154,15 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe
166154
}
167155
case SEEK_END:
168156
if (offset > 0) {
169-
ms->fpos = ms->fsize;
157+
ms->fpos = ZSTR_LEN(ms->data);
170158
*newoffs = -1;
171159
return -1;
172-
} else if (ms->fsize < (size_t)(-offset)) {
160+
} else if (ZSTR_LEN(ms->data) < (size_t)(-offset)) {
173161
ms->fpos = 0;
174162
*newoffs = -1;
175163
return -1;
176164
} else {
177-
ms->fpos = ms->fsize + offset;
165+
ms->fpos = ZSTR_LEN(ms->data) + offset;
178166
*newoffs = ms->fpos;
179167
stream->eof = 0;
180168
return 0;
@@ -204,7 +192,7 @@ static int php_stream_memory_stat(php_stream *stream, php_stream_statbuf *ssb) /
204192

205193
ssb->sb.st_mode = ms->mode & TEMP_STREAM_READONLY ? 0444 : 0666;
206194

207-
ssb->sb.st_size = ms->fsize;
195+
ssb->sb.st_size = ZSTR_LEN(ms->data);
208196
ssb->sb.st_mode |= S_IFREG; /* regular file */
209197
ssb->sb.st_mtime = timestamp;
210198
ssb->sb.st_atime = timestamp;
@@ -241,16 +229,16 @@ static int php_stream_memory_set_option(php_stream *stream, int option, int valu
241229
return PHP_STREAM_OPTION_RETURN_ERR;
242230
}
243231
newsize = *(size_t*)ptrparam;
244-
if (newsize <= ms->fsize) {
232+
if (newsize <= ZSTR_LEN(ms->data)) {
233+
ms->data = zend_string_truncate(ms->data, newsize, 0);
245234
if (newsize < ms->fpos) {
246235
ms->fpos = newsize;
247236
}
248237
} else {
249-
ms->data = erealloc(ms->data, newsize);
250-
memset(ms->data+ms->fsize, 0, newsize - ms->fsize);
251-
ms->fsize = newsize;
238+
size_t old_size = ZSTR_LEN(ms->data);
239+
ms->data = zend_string_realloc(ms->data, newsize, 0);
240+
memset(ZSTR_VAL(ms->data) + old_size, 0, newsize - old_size);
252241
}
253-
ms->fsize = newsize;
254242
return PHP_STREAM_OPTION_RETURN_OK;
255243
}
256244
}
@@ -300,9 +288,8 @@ PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC)
300288
php_stream *stream;
301289

302290
self = emalloc(sizeof(*self));
303-
self->data = NULL;
291+
self->data = ZSTR_EMPTY_ALLOC();
304292
self->fpos = 0;
305-
self->fsize = 0;
306293
self->mode = mode;
307294

308295
stream = php_stream_alloc_rel(&php_stream_memory_ops, self, 0, _php_stream_mode_to_str(mode));
@@ -313,39 +300,25 @@ PHPAPI php_stream *_php_stream_memory_create(int mode STREAMS_DC)
313300

314301

315302
/* {{{ */
316-
PHPAPI php_stream *_php_stream_memory_open(int mode, const char *buf, size_t length STREAMS_DC)
303+
PHPAPI php_stream *_php_stream_memory_open(int mode, zend_string *buf STREAMS_DC)
317304
{
318305
php_stream *stream;
319306
php_stream_memory_data *ms;
320307

321308
if ((stream = php_stream_memory_create_rel(mode)) != NULL) {
322309
ms = (php_stream_memory_data*)stream->abstract;
323-
324-
if (mode == TEMP_STREAM_READONLY || mode == TEMP_STREAM_TAKE_BUFFER) {
325-
/* use the buffer directly */
326-
ms->data = (char *) buf;
327-
ms->fsize = length;
328-
} else {
329-
if (length) {
330-
assert(buf != NULL);
331-
php_stream_write(stream, buf, length);
332-
}
333-
}
310+
ms->data = zend_string_copy(buf);
334311
}
335312
return stream;
336313
}
337314
/* }}} */
338315

339316

340317
/* {{{ */
341-
PHPAPI char *_php_stream_memory_get_buffer(php_stream *stream, size_t *length STREAMS_DC)
318+
PHPAPI zend_string *_php_stream_memory_get_buffer(php_stream *stream STREAMS_DC)
342319
{
343320
php_stream_memory_data *ms = (php_stream_memory_data*)stream->abstract;
344-
345-
assert(ms != NULL);
346-
assert(length != 0);
347-
348-
*length = ms->fsize;
321+
ZEND_ASSERT(ms != NULL);
349322
return ms->data;
350323
}
351324
/* }}} */
@@ -373,16 +346,15 @@ static ssize_t php_stream_temp_write(php_stream *stream, const char *buf, size_t
373346
return -1;
374347
}
375348
if (php_stream_is(ts->innerstream, PHP_STREAM_IS_MEMORY)) {
376-
size_t memsize;
377-
char *membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize);
349+
zend_string *membuf = php_stream_memory_get_buffer(ts->innerstream);
378350

379-
if (memsize + count >= ts->smax) {
351+
if (ZSTR_LEN(membuf) + count >= ts->smax) {
380352
php_stream *file = php_stream_fopen_temporary_file(ts->tmpdir, "php", NULL);
381353
if (file == NULL) {
382354
php_error_docref(NULL, E_WARNING, "Unable to create temporary file, Check permissions in temporary files directory.");
383355
return 0;
384356
}
385-
php_stream_write(file, membuf, memsize);
357+
php_stream_write(file, ZSTR_VAL(membuf), ZSTR_LEN(membuf));
386358
php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);
387359
ts->innerstream = file;
388360
php_stream_encloses(stream, ts->innerstream);
@@ -477,8 +449,7 @@ static int php_stream_temp_cast(php_stream *stream, int castas, void **ret)
477449
{
478450
php_stream_temp_data *ts = (php_stream_temp_data*)stream->abstract;
479451
php_stream *file;
480-
size_t memsize;
481-
char *membuf;
452+
zend_string *membuf;
482453
zend_off_t pos;
483454

484455
assert(ts != NULL);
@@ -511,8 +482,8 @@ static int php_stream_temp_cast(php_stream *stream, int castas, void **ret)
511482
}
512483

513484
/* perform the conversion and then pass the request on to the innerstream */
514-
membuf = php_stream_memory_get_buffer(ts->innerstream, &memsize);
515-
php_stream_write(file, membuf, memsize);
485+
membuf = php_stream_memory_get_buffer(ts->innerstream);
486+
php_stream_write(file, ZSTR_VAL(membuf), ZSTR_LEN(membuf));
516487
pos = php_stream_tell(ts->innerstream);
517488

518489
php_stream_free_enclosed(ts->innerstream, PHP_STREAM_FREE_CLOSE);

0 commit comments

Comments
 (0)