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
39 changes: 26 additions & 13 deletions Zend/zend_string.h
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,20 @@ static zend_always_inline zend_string *ZSTR_KNOWN(size_t idx) {
#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1))
#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD)

/* Returns n * m + l, or SIZE_MAX on fallible overflow. Rejects lengths above
* ZSTR_MAX_LEN so the aligned allocation size of the string can not wrap. */
static zend_always_inline size_t zend_string_safe_len(size_t n, size_t m, size_t l, bool fallible)
{
bool overflow;
size_t len = zend_safe_address(n, m, l, &overflow);

if (UNEXPECTED(overflow || len > ZSTR_MAX_LEN)) {
zend_mm_delayed_error_or_panic(fallible, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", n, m, l);
return SIZE_MAX;
}
return len;
}

#define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \
(str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \
GC_SET_REFCOUNT(str, 1); \
Expand Down Expand Up @@ -209,16 +223,11 @@ static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persis
/* Fallible variant of zend_string_safe_alloc */
static zend_always_inline zend_string *zend_string_safe_falloc(size_t n, size_t m, size_t l, bool persistent, bool fallible)
{
zend_string *ret = (zend_string *)safe_fpemalloc(n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent, fallible);
if (ZEND_CONST_COND(fallible, true) && UNEXPECTED(ret == NULL)) {
return ret;
size_t len = zend_string_safe_len(n, m, l, fallible && !persistent);
if (UNEXPECTED(len == SIZE_MAX)) {
return NULL;
}

GC_SET_REFCOUNT(ret, 1);
GC_TYPE_INFO(ret) = GC_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << GC_FLAGS_SHIFT);
ZSTR_H(ret) = 0;
ZSTR_LEN(ret) = (n * m) + l;
return ret;
return zend_string_falloc(len, persistent, fallible);
}

static zend_always_inline zend_string *zend_string_safe_alloc(size_t n, size_t m, size_t l, bool persistent)
Expand Down Expand Up @@ -391,23 +400,27 @@ static zend_always_inline zend_string *zend_string_truncate(zend_string *s, size
static zend_always_inline zend_string *zend_string_safe_frealloc(zend_string *s, size_t n, size_t m, size_t l, bool persistent, bool fallible)
{
zend_string *ret;
size_t len = zend_string_safe_len(n, m, l, fallible && !persistent);
if (UNEXPECTED(len == SIZE_MAX)) {
return NULL;
}

if (!ZSTR_IS_INTERNED(s)) {
if (GC_REFCOUNT(s) == 1) {
ret = (zend_string *)safe_fperealloc(s, n, m, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(l)), persistent, fallible);
ret = (zend_string *)fperealloc(s, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(len)), persistent, fallible);
if (ZEND_CONST_COND(fallible, true) && !ret) {
return NULL;
}
ZSTR_LEN(ret) = (n * m) + l;
ZSTR_LEN(ret) = len;
zend_string_forget_hash_val(ret);
return ret;
}
}
ret = zend_string_safe_falloc(n, m, l, persistent, fallible);
ret = zend_string_falloc(len, persistent, fallible);
if (ZEND_CONST_COND(fallible, true) && !ret) {
return NULL;
}
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1);
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN(len, ZSTR_LEN(s)) + 1);
if (!ZSTR_IS_INTERNED(s)) {
GC_DELREF(s);
}
Expand Down
9 changes: 6 additions & 3 deletions ext/mbstring/libmbfl/mbfl/mbfl_encoding.h
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ typedef zend_string* (*mb_cut_fn)(unsigned char *str, size_t from, size_t len, u
static inline void mb_convert_buf_init(mb_convert_buf *buf, size_t initsize, uint32_t repl_char, unsigned int err_mode)
{
buf->state = buf->errors = 0;
buf->str = emalloc(_ZSTR_STRUCT_SIZE(initsize));
buf->str = emalloc(ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(initsize)));
buf->out = (unsigned char*)ZSTR_VAL(buf->str);
buf->limit = buf->out + initsize;
buf->replacement_char = repl_char;
Expand All @@ -167,8 +167,11 @@ static inline zend_result mb_convert_buf_ensure(mb_convert_buf *buf, unsigned ch
ZEND_ASSERT(*out <= *limit);
if ((size_t)(*limit - *out) < needed) {
size_t oldsize = *limit - (unsigned char*)ZSTR_VAL((buf)->str);
size_t newsize = oldsize + MAX(oldsize >> 1, needed);
zend_string *newstr = safe_ferealloc((buf)->str, 1, newsize, _ZSTR_STRUCT_SIZE(0), /* fallible */ true);
size_t newsize = zend_string_safe_len(1, oldsize, MAX(oldsize >> 1, needed), /* fallible */ true);
if (UNEXPECTED(newsize == SIZE_MAX)) {
return FAILURE;
}
zend_string *newstr = ferealloc((buf)->str, ZEND_MM_ALIGNED_SIZE(_ZSTR_STRUCT_SIZE(newsize)), /* fallible */ true);
if (!newstr) {
return FAILURE;
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ var_dump(chunk_split($a,$b,$c));
--EXPECTF--
*** Testing chunk_split() : unexpected large 'end' string argument variation 2 ***

Fatal error: Possible integer overflow in memory allocation (65537 * 65537 + %r65556|65560%r) in %s on line %d
Fatal error: Possible integer overflow in memory allocation (65537 * 65537 + 65537) in %s on line %d
Loading