diff options
author | Nikita Popov <nikita.ppv@gmail.com> | 2019-07-15 12:00:30 +0200 |
---|---|---|
committer | Nikita Popov <nikita.ppv@gmail.com> | 2019-07-15 12:00:30 +0200 |
commit | 193f28c7d557df887c4456d072113cc2478e1c3e (patch) | |
tree | a6d232760aa2f39cfe469440d9b7f5ca710006bf | |
parent | 3eb057c4a73212e4ae25a228c1b610d317c6be4b (diff) | |
download | php-git-193f28c7d557df887c4456d072113cc2478e1c3e.tar.gz |
Fixed bug #78010
Prevent the gc_info from becoming all zero for a registered root
by setting the top bit to one for compressed root addresses.
-rw-r--r-- | Zend/tests/bug78010.phpt | 32 | ||||
-rw-r--r-- | Zend/zend_gc.c | 7 |
2 files changed, 37 insertions, 2 deletions
diff --git a/Zend/tests/bug78010.phpt b/Zend/tests/bug78010.phpt new file mode 100644 index 0000000000..a9ebc37ef1 --- /dev/null +++ b/Zend/tests/bug78010.phpt @@ -0,0 +1,32 @@ +--TEST-- +Bug #78010: Segmentation fault during GC +--INI-- +memory_limit=2G +--FILE-- +<?php + +class foo +{ + public function __construct() + { + $this->x = $this; + + for ($i = 0; $i < 898; $i++) { //Will not trigger with <898 + $obj = [new stdClass, new stdClass]; //This must have at least 2 elements + $this->y[] = $obj; + } + } +} + +for ($i = 0; $i < 2; ++$i) { //This must run >=2 (increasing the number of elements in the array *2 will not do) + $x = []; //This must be reset + foreach (array_fill(0, 389, 'x') as &$params) { //Will not trigger <389 + $x[] = new foo; + } +} + +echo "Completed\n"; + +?> +--EXPECT-- +Completed diff --git a/Zend/zend_gc.c b/Zend/zend_gc.c index 5486452581..7280fdd20d 100644 --- a/Zend/zend_gc.c +++ b/Zend/zend_gc.c @@ -150,7 +150,7 @@ #define GC_DEFAULT_BUF_SIZE (16 * 1024) #define GC_BUF_GROW_STEP (128 * 1024) -#define GC_MAX_UNCOMPRESSED (1024 * 1024) +#define GC_MAX_UNCOMPRESSED (512 * 1024) #define GC_MAX_BUF_SIZE 0x40000000 #define GC_THRESHOLD_DEFAULT 10000 @@ -314,7 +314,10 @@ static void gc_stack_free(gc_stack *stack) static zend_always_inline uint32_t gc_compress(uint32_t idx) { - return idx % GC_MAX_UNCOMPRESSED; + if (EXPECTED(idx < GC_MAX_UNCOMPRESSED)) { + return idx; + } + return (idx % GC_MAX_UNCOMPRESSED) | GC_MAX_UNCOMPRESSED; } static zend_always_inline gc_root_buffer* gc_decompress(zend_refcounted *ref, uint32_t idx) |