Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 33 additions & 9 deletions Zend/zend_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1671,7 +1671,10 @@ static zend_never_inline void *zend_mm_realloc_huge(zend_mm_heap *heap, void *pt
return zend_mm_realloc_slow(heap, ptr, size, MIN(old_size, copy_size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}

static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size, bool use_copy_size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
#define EREALLOC_DEFAULT 0
#define EREALLOC_COPY 1
#define EREALLOC_NOSHRINK 2
static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *ptr, size_t size, int mode, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
size_t page_offset;
size_t old_size;
Expand All @@ -1686,6 +1689,12 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p
if (EXPECTED(ptr == NULL)) {
return _zend_mm_alloc(heap, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
} else {
if (mode == EREALLOC_NOSHRINK) {
old_size = zend_mm_get_huge_block_size(heap, ptr ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
if (EXPECTED(size <= old_size)) {
return ptr;
}
}
return zend_mm_realloc_huge(heap, ptr, size, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
} else {
Expand Down Expand Up @@ -1713,10 +1722,10 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p
/* Check if requested size fits into current bin */
if (size <= old_size) {
/* Check if truncation is necessary */
if (old_bin_num > 0 && size < bin_data_size[old_bin_num - 1]) {
if (mode != EREALLOC_NOSHRINK && old_bin_num > 0 && size < bin_data_size[old_bin_num - 1]) {
/* truncation */
ret = zend_mm_alloc_small(heap, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
copy_size = use_copy_size ? MIN(size, copy_size) : size;
copy_size = mode != EREALLOC_DEFAULT ? MIN(size, copy_size) : size;
memcpy(ret, ptr, copy_size);
zend_mm_free_small(heap, ptr, old_bin_num);
} else {
Expand All @@ -1731,7 +1740,7 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p
size_t orig_peak = heap->peak;
#endif
ret = zend_mm_alloc_small(heap, ZEND_MM_SMALL_SIZE_TO_BIN(size) ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
copy_size = use_copy_size ? MIN(old_size, copy_size) : old_size;
copy_size = mode != EREALLOC_DEFAULT ? MIN(old_size, copy_size) : old_size;
memcpy(ret, ptr, copy_size);
zend_mm_free_small(heap, ptr, old_bin_num);
#if ZEND_MM_STAT
Expand Down Expand Up @@ -1759,7 +1768,7 @@ static zend_always_inline void *zend_mm_realloc_heap(zend_mm_heap *heap, void *p
old_size = ZEND_MM_LRUN_PAGES(info) * ZEND_MM_PAGE_SIZE;
if (size > ZEND_MM_MAX_SMALL_SIZE && size <= ZEND_MM_MAX_LARGE_SIZE) {
new_size = ZEND_MM_ALIGNED_SIZE_EX(size, ZEND_MM_PAGE_SIZE);
if (new_size == old_size) {
if (mode == EREALLOC_NOSHRINK ? new_size <= old_size : (new_size == old_size)) {
#if ZEND_DEBUG
dbg = zend_mm_get_debug_info(heap, ptr);
dbg->size = real_size;
Expand Down Expand Up @@ -2579,12 +2588,17 @@ ZEND_API void ZEND_FASTCALL _zend_mm_free(zend_mm_heap *heap, void *ptr ZEND_FIL

void* ZEND_FASTCALL _zend_mm_realloc(zend_mm_heap *heap, void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
return zend_mm_realloc_heap(heap, ptr, size, 0, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
return zend_mm_realloc_heap(heap, ptr, size, EREALLOC_DEFAULT, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}

void* ZEND_FASTCALL _zend_mm_realloc2(zend_mm_heap *heap, void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
return zend_mm_realloc_heap(heap, ptr, size, 1, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
return zend_mm_realloc_heap(heap, ptr, size, EREALLOC_COPY, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}

void* ZEND_FASTCALL _zend_mm_realloc3(zend_mm_heap *heap, void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
return zend_mm_realloc_heap(heap, ptr, size, EREALLOC_NOSHRINK, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}

ZEND_API size_t ZEND_FASTCALL _zend_mm_block_size(zend_mm_heap *heap, void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
Expand Down Expand Up @@ -2801,7 +2815,7 @@ ZEND_API void* ZEND_FASTCALL _erealloc(void *ptr, size_t size ZEND_FILE_LINE_DC
return AG(mm_heap)->custom_heap._realloc(ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
#endif
return zend_mm_realloc_heap(AG(mm_heap), ptr, size, 0, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
return zend_mm_realloc_heap(AG(mm_heap), ptr, size, EREALLOC_DEFAULT, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}

ZEND_API void* ZEND_FASTCALL _erealloc2(void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
Expand All @@ -2811,7 +2825,17 @@ ZEND_API void* ZEND_FASTCALL _erealloc2(void *ptr, size_t size, size_t copy_size
return AG(mm_heap)->custom_heap._realloc(ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
#endif
return zend_mm_realloc_heap(AG(mm_heap), ptr, size, 1, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
return zend_mm_realloc_heap(AG(mm_heap), ptr, size, EREALLOC_COPY, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}

ZEND_API void* ZEND_FASTCALL _erealloc3(void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
{
#if ZEND_MM_CUSTOM
if (UNEXPECTED(AG(mm_heap)->use_custom_heap)) {
return AG(mm_heap)->custom_heap._realloc(ptr, size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}
#endif
return zend_mm_realloc_heap(AG(mm_heap), ptr, size, EREALLOC_NOSHRINK, copy_size ZEND_FILE_LINE_RELAY_CC ZEND_FILE_LINE_ORIG_RELAY_CC);
}

ZEND_API size_t ZEND_FASTCALL _zend_mem_block_size(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC)
Expand Down
3 changes: 3 additions & 0 deletions Zend/zend_alloc.h
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ ZEND_API void ZEND_FASTCALL _efree(void *ptr ZEND_FILE_LINE_DC ZEND_FILE_LINE_
ZEND_API ZEND_ATTRIBUTE_MALLOC void* ZEND_FASTCALL _ecalloc(size_t nmemb, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE2(1,2);
ZEND_API void* ZEND_FASTCALL _erealloc(void *ptr, size_t size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(2);
ZEND_API void* ZEND_FASTCALL _erealloc2(void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(2);
ZEND_API void* ZEND_FASTCALL _erealloc3(void *ptr, size_t size, size_t copy_size ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC) ZEND_ATTRIBUTE_ALLOC_SIZE(2);
ZEND_API void* ZEND_FASTCALL _safe_erealloc(void *ptr, size_t nmemb, size_t size, size_t offset ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
ZEND_API void* ZEND_FASTCALL _safe_realloc(void *ptr, size_t nmemb, size_t size, size_t offset);
ZEND_API ZEND_ATTRIBUTE_MALLOC char* ZEND_FASTCALL _estrdup(const char *s ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC);
Expand Down Expand Up @@ -158,6 +159,7 @@ ZEND_API void ZEND_FASTCALL _efree_huge(void *, size_t size);
#define ecalloc(nmemb, size) _ecalloc((nmemb), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define erealloc(ptr, size) _erealloc((ptr), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define erealloc2(ptr, size, copy_size) _erealloc2((ptr), (size), (copy_size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define erealloc3(ptr, size, copy_size) _erealloc3((ptr), (size), (copy_size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define safe_erealloc(ptr, nmemb, size, offset) _safe_erealloc((ptr), (nmemb), (size), (offset) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define erealloc_recoverable(ptr, size) _erealloc((ptr), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define erealloc2_recoverable(ptr, size, copy_size) _erealloc2((ptr), (size), (copy_size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
Expand Down Expand Up @@ -200,6 +202,7 @@ ZEND_API ZEND_ATTRIBUTE_MALLOC char * __zend_strdup(const char *s);
#define pecalloc(nmemb, size, persistent) ((persistent)?__zend_calloc((nmemb), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):ecalloc((nmemb), (size)))
#define perealloc(ptr, size, persistent) ((persistent)?__zend_realloc((ptr), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):erealloc((ptr), (size)))
#define perealloc2(ptr, size, copy_size, persistent) ((persistent)?__zend_realloc((ptr), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):erealloc2((ptr), (size), (copy_size)))
#define perealloc3(ptr, size, copy_size, persistent) ((persistent)?__zend_realloc((ptr), (size) ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC):erealloc3((ptr), (size), (copy_size)))
#define safe_perealloc(ptr, nmemb, size, offset, persistent) ((persistent)?_safe_realloc((ptr), (nmemb), (size), (offset)):safe_erealloc((ptr), (nmemb), (size), (offset)))
#define perealloc_recoverable(ptr, size, persistent) ((persistent)?realloc((ptr), (size)):erealloc_recoverable((ptr), (size)))
#define perealloc2_recoverable(ptr, size, persistent) ((persistent)?realloc((ptr), (size)):erealloc2_recoverable((ptr), (size), (copy_size)))
Expand Down
2 changes: 1 addition & 1 deletion Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -261,7 +261,7 @@ static zend_always_inline zend_string *zend_string_extend(zend_string *s, size_t
ZEND_ASSERT(len >= ZSTR_LEN(s));
if (!ZSTR_IS_INTERNED(s)) {
if (EXPECTED(GC_REFCOUNT(s) == 1)) {
ret = (zend_string *)perealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent);
ret = (zend_string *)perealloc3(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), _ZSTR_STRUCT_SIZE(ZSTR_LEN(s)), persistent);
ZSTR_LEN(ret) = len;
zend_string_forget_hash_val(ret);
return ret;
Expand Down
5 changes: 5 additions & 0 deletions ext/standard/basic_functions.stub.php
Original file line number Diff line number Diff line change
Expand Up @@ -2448,6 +2448,11 @@ function substr_replace(array|string $string, array|string $replace, array|int $
*/
function quotemeta(string $string): string {}

/**
* @compile-time-eval
*/
function str_extend(string $string, int $size): string {}

/** @compile-time-eval */
function ord(string $character): int {}

Expand Down
9 changes: 8 additions & 1 deletion ext/standard/basic_functions_arginfo.h

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

22 changes: 22 additions & 0 deletions ext/standard/string.c
Original file line number Diff line number Diff line change
Expand Up @@ -2643,6 +2643,28 @@ PHP_FUNCTION(quotemeta)
}
/* }}} */

PHP_FUNCTION(str_extend)
{
zend_string *str;
zend_long size;

ZEND_PARSE_PARAMETERS_START(2, 2)
Z_PARAM_STR(str)
Z_PARAM_LONG(size)
ZEND_PARSE_PARAMETERS_END();

size_t len = ZSTR_LEN(str);
if (len > size) {
zend_argument_value_error(2, "must not be smaller than the input string");
RETURN_THROWS();
}

ZVAL_UNDEF(ZEND_CALL_ARG(execute_data, 0)); // avoid copies, so that we may benefit from the RC=1 optimization
RETVAL_STR(zend_string_extend(str, size, 0));
Z_STRLEN_P(return_value) = len;
}
/* }}} */

/* {{{ Returns ASCII value of character
Warning: This function is special-cased by zend_compile.c and so is bypassed for constant string argument */
PHP_FUNCTION(ord)
Expand Down
18 changes: 18 additions & 0 deletions ext/standard/tests/strings/str_extend.phpt
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
--TEST--
Append to string allocated with str_extend()
--FILE--
<?php

$str = str_extend("a", 1 << 22);
for ($i = 0; $i < 1 << 21; ++$i) {
$str .= "a";
}

var_dump(array_filter(count_chars($str)));

?>
--EXPECT--
array(1) {
[97]=>
int(2097153)
}
Loading