Skip to content

Commit c391a93

Browse files
fix overflow
1 parent dbb82fc commit c391a93

2 files changed

Lines changed: 16 additions & 30 deletions

File tree

‎Zend/zend_string.h‎

Lines changed: 15 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -127,15 +127,22 @@ static zend_always_inline zend_string *ZSTR_KNOWN(size_t idx) {
127127

128128
#define _ZSTR_STRUCT_SIZE(len) (_ZSTR_HEADER_SIZE + len + 1)
129129

130-
/* ALIGN(n * m + header + l + 1). The "+ ALIGNMENT - 1" of the rounding is
131-
* done inside the overflow check, so the final "& MASK" can only shrink
132-
* the value and can not wrap. */
133-
#define _ZSTR_SAFE_STRUCT_SIZE(n, m, l) \
134-
(zend_safe_address_guarded(n, m, _ZSTR_STRUCT_SIZE(l) + ZEND_MM_ALIGNMENT - 1) & ZEND_MM_ALIGNMENT_MASK)
135-
136130
#define ZSTR_MAX_OVERHEAD (ZEND_MM_ALIGNED_SIZE(_ZSTR_HEADER_SIZE + 1))
137131
#define ZSTR_MAX_LEN (SIZE_MAX - ZSTR_MAX_OVERHEAD)
138132

133+
/* Returns n * m + l. Errors if that overflows or is above ZSTR_MAX_LEN, so
134+
* the aligned allocation size of the string can not wrap. */
135+
static zend_always_inline size_t zend_string_safe_len(size_t n, size_t m, size_t l)
136+
{
137+
bool overflow;
138+
size_t len = zend_safe_address(n, m, l, &overflow);
139+
140+
if (UNEXPECTED(overflow || len > ZSTR_MAX_LEN)) {
141+
zend_error_noreturn(E_ERROR, "Possible integer overflow in memory allocation (%zu * %zu + %zu)", n, m, l);
142+
}
143+
return len;
144+
}
145+
139146
#define ZSTR_ALLOCA_ALLOC(str, _len, use_heap) do { \
140147
(str) = (zend_string *)do_alloca(ZEND_MM_ALIGNED_SIZE_EX(_ZSTR_STRUCT_SIZE(_len), 8), (use_heap)); \
141148
GC_SET_REFCOUNT(str, 1); \
@@ -204,13 +211,7 @@ static zend_always_inline zend_string *zend_string_alloc(size_t len, bool persis
204211

205212
static zend_always_inline zend_string *zend_string_safe_alloc(size_t n, size_t m, size_t l, bool persistent)
206213
{
207-
zend_string *ret = (zend_string *)pemalloc(_ZSTR_SAFE_STRUCT_SIZE(n, m, l), persistent);
208-
209-
GC_SET_REFCOUNT(ret, 1);
210-
GC_TYPE_INFO(ret) = GC_STRING | ((persistent ? IS_STR_PERSISTENT : 0) << GC_FLAGS_SHIFT);
211-
ZSTR_H(ret) = 0;
212-
ZSTR_LEN(ret) = (n * m) + l;
213-
return ret;
214+
return zend_string_alloc(zend_string_safe_len(n, m, l), persistent);
214215
}
215216

216217
static zend_always_inline zend_string *zend_string_init(const char *str, size_t len, bool persistent)
@@ -327,22 +328,7 @@ static zend_always_inline zend_string *zend_string_truncate(zend_string *s, size
327328

328329
static zend_always_inline zend_string *zend_string_safe_realloc(zend_string *s, size_t n, size_t m, size_t l, bool persistent)
329330
{
330-
zend_string *ret;
331-
332-
if (!ZSTR_IS_INTERNED(s)) {
333-
if (GC_REFCOUNT(s) == 1) {
334-
ret = (zend_string *)perealloc(s, _ZSTR_SAFE_STRUCT_SIZE(n, m, l), persistent);
335-
ZSTR_LEN(ret) = (n * m) + l;
336-
zend_string_forget_hash_val(ret);
337-
return ret;
338-
}
339-
}
340-
ret = zend_string_safe_alloc(n, m, l, persistent);
341-
memcpy(ZSTR_VAL(ret), ZSTR_VAL(s), MIN((n * m) + l, ZSTR_LEN(s)) + 1);
342-
if (!ZSTR_IS_INTERNED(s)) {
343-
GC_DELREF(s);
344-
}
345-
return ret;
331+
return zend_string_realloc(s, zend_string_safe_len(n, m, l), persistent);
346332
}
347333

348334
static zend_always_inline char *zend_cstr_append_char(const char *str, size_t len, char c) {

‎ext/standard/tests/strings/chunk_split_variation2_32bit.phpt‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,4 +16,4 @@ var_dump(chunk_split($a,$b,$c));
1616
--EXPECTF--
1717
*** Testing chunk_split() : unexpected large 'end' string argument variation 2 ***
1818

19-
Fatal error: Possible integer overflow in memory allocation (65537 * 65537 + %r65557|65561%r) in %s on line %d
19+
Fatal error: Possible integer overflow in memory allocation (65537 * 65537 + 65537) in %s on line %d

0 commit comments

Comments
 (0)