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
12 changes: 7 additions & 5 deletions Zend/Optimizer/zend_inference.c
Original file line number Diff line number Diff line change
Expand Up @@ -760,12 +760,14 @@ static inline zend_long safe_shift_left(zend_long n, zend_long s) {
}

static inline bool shift_left_overflows(zend_long n, zend_long s) {
/* This considers shifts that shift in the sign bit to be overflowing as well */
if (n >= 0) {
return s >= SIZEOF_ZEND_LONG * 8 - 1 || safe_shift_left(n, s) < n;
} else {
return s >= SIZEOF_ZEND_LONG * 8 || safe_shift_left(n, s) > n;
if (UNEXPECTED((zend_ulong)s >= SIZEOF_ZEND_LONG * 8)) {
return true;
}
if (UNEXPECTED(s == SIZEOF_ZEND_LONG * 8 - 1)) {
return n != 0 && n != -1;
}
zend_long shifted = (zend_long)((zend_ulong)n << (zend_ulong)s);
return (shifted >> s) != n;
}

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please submit this as a separate PR on the PHP-8.4 branch with a test:

--TEST--
Too narrow range inferred for SL when the shift wraps
--SKIPIF--
<?php if (PHP_INT_SIZE != 8) die("skip 64-bit only"); ?>
--FILE--
<?php
/* $i is inferred as RANGE[1..5]. Shifting it by 62 wraps for every $i >= 2,
 * so the result range may not be derived from the two endpoints: both of them
 * happen to yield 1 << 62, while the values in between do not. */
function shift_positive(): array {
    $out = [];
    for ($i = 1; $i <= 5; $i++) {
        $out[] = $i << 62;
    }
    return $out;
}

/* Likewise for RANGE[-3..-1] shifted by 63: both endpoints yield LONG_MIN,
 * but -2 << 63 is 0. */
function shift_negative(): array {
    $out = [];
    for ($i = -1; $i >= -3; $i--) {
        $out[] = $i << 63;
    }
    return $out;
}

var_dump(shift_positive());
var_dump(shift_negative());
?>
--EXPECT--
array(5) {
  [0]=>
  int(4611686018427387904)
  [1]=>
  int(-9223372036854775808)
  [2]=>
  int(-4611686018427387904)
  [3]=>
  int(0)
  [4]=>
  int(4611686018427387904)
}
array(3) {
  [0]=>
  int(-9223372036854775808)
  [1]=>
  int(0)
  [2]=>
  int(-9223372036854775808)
}


/* If b does not divide a exactly, return the two adjacent values between which the real result
Expand Down
14 changes: 8 additions & 6 deletions Zend/zend_alloc.c
Original file line number Diff line number Diff line change
Expand Up @@ -1034,19 +1034,21 @@ static zend_always_inline void zend_mm_chunk_init(zend_mm_heap *heap, zend_mm_ch
static zend_always_inline zend_mm_chunk *zend_mm_encode_cached_chunk(const zend_mm_heap *heap, const void *holder, const zend_mm_chunk *next)
{
#ifdef WORDS_BIGENDIAN
return (zend_mm_chunk*)((uintptr_t)next ^ heap->shadow_key ^ (uintptr_t)holder);
uintptr_t p = (uintptr_t)next;
#else
return (zend_mm_chunk*)(BSWAPPTR((uintptr_t)next) ^ heap->shadow_key ^ (uintptr_t)holder);
uintptr_t p = BSWAPPTR((uintptr_t)next);
#endif
/* ARX (Addition-XOR) non-linear mixing prevents linear algebraic shadow_key recovery */
return (zend_mm_chunk*)((p + heap->shadow_key) ^ (uintptr_t)holder);
Comment on lines +1041 to +1042

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain this change?

}

static zend_always_inline zend_mm_chunk *zend_mm_decode_cached_chunk_key(uintptr_t key, const void *holder, const zend_mm_chunk *encoded)
{
#ifdef WORDS_BIGENDIAN
zend_mm_chunk *next = (zend_mm_chunk*)((uintptr_t)encoded ^ key ^ (uintptr_t)holder);
#else
zend_mm_chunk *next = (zend_mm_chunk*)(BSWAPPTR((uintptr_t)encoded ^ key ^ (uintptr_t)holder));
uintptr_t p = ((uintptr_t)encoded ^ (uintptr_t)holder) - key;
#ifndef WORDS_BIGENDIAN
p = BSWAPPTR(p);
#endif
zend_mm_chunk *next = (zend_mm_chunk*)p;

ZEND_MM_CHECK(ZEND_MM_ALIGNED_OFFSET(next, ZEND_MM_CHUNK_SIZE) == 0, "zend_mm_heap corrupted");
return next;
Expand Down
5 changes: 4 additions & 1 deletion Zend/zend_gc.c
Original file line number Diff line number Diff line change
Expand Up @@ -421,7 +421,10 @@ static zend_always_inline gc_root_buffer* gc_decompress(zend_refcounted *ref, ui

while (1) {
idx += GC_MAX_UNCOMPRESSED;
ZEND_ASSERT(idx < GC_G(first_unused));
if (UNEXPECTED(idx >= GC_G(first_unused))) {
zend_error_noreturn(E_CORE_ERROR, "GC root buffer corruption detected: unable to resolve compressed address");
return NULL;
}
Comment on lines +424 to +427

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Could you explain when this happens?

root = GC_IDX2PTR(idx);
if (GC_GET_PTR(root->ref) == ref) {
return root;
Expand Down
24 changes: 18 additions & 6 deletions main/streams/memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -52,8 +52,12 @@ static ssize_t php_stream_memory_write(php_stream *stream, const char *buf, size
if (ms->mode & TEMP_STREAM_APPEND) {
ms->fpos = data_len;
}
if (ms->fpos + count > data_len) {
zend_string *grown = zend_string_frealloc(ms->data, ms->fpos + count, 0, /* fallible */ true);
if (UNEXPECTED(count > SIZE_MAX - ms->fpos)) {
return (ssize_t) -1;
}
size_t new_pos = ms->fpos + count;
if (new_pos > data_len) {
zend_string *grown = zend_string_frealloc(ms->data, new_pos, 0, /* fallible */ true);
if (UNEXPECTED(!grown)) {
return (ssize_t) -1;
}
Expand All @@ -69,7 +73,7 @@ static ssize_t php_stream_memory_write(php_stream *stream, const char *buf, size
ZEND_ASSERT(buf != NULL);
memcpy(ZSTR_VAL(ms->data) + ms->fpos, (char*) buf, count);
ZSTR_VAL(ms->data)[ZSTR_LEN(ms->data)] = '\0';
ms->fpos += count;
ms->fpos = new_pos;
}
return count;
}
Expand Down Expand Up @@ -142,9 +146,13 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe
return 0;
}
} else {
if (UNEXPECTED((size_t)offset > SIZE_MAX - ms->fpos)) {
*newoffs = -1;
return -1;
}
stream->eof = 0;
stream->fatal_error = 0;
ms->fpos = ms->fpos + offset;
ms->fpos += (size_t)offset;
*newoffs = ms->fpos;
return 0;
}
Expand All @@ -154,15 +162,19 @@ static int php_stream_memory_seek(php_stream *stream, zend_off_t offset, int whe
*newoffs = -1;
return -1;
} else {
ms->fpos = offset;
ms->fpos = (size_t)offset;
*newoffs = ms->fpos;
stream->eof = 0;
stream->fatal_error = 0;
return 0;
}
case SEEK_END:
if (offset > 0) {
ms->fpos = ZSTR_LEN(ms->data) + offset;
if (UNEXPECTED((size_t)offset > SIZE_MAX - ZSTR_LEN(ms->data))) {
*newoffs = -1;
return -1;
}
ms->fpos = ZSTR_LEN(ms->data) + (size_t)offset;
*newoffs = ms->fpos;
stream->eof = 0;
stream->fatal_error = 0;
Expand Down
3 changes: 3 additions & 0 deletions main/streams/userspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -612,6 +612,9 @@ static ssize_t php_userstreamop_write(php_stream *stream, const char *buf, size_
} else {
convert_to_long(&retval);
didwrite = Z_LVAL(retval);
if (didwrite < 0) {
didwrite = -1;
Comment on lines +615 to +616

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please submit this as a separate PR on the PHP-8.4 branch with a test

}
}

/* don't allow strange buffer overruns due to bogus return */
Expand Down
Loading