summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNikita Popov <nikita.ppv@gmail.com>2019-07-15 12:00:30 +0200
committerNikita Popov <nikita.ppv@gmail.com>2019-07-15 12:00:30 +0200
commit193f28c7d557df887c4456d072113cc2478e1c3e (patch)
treea6d232760aa2f39cfe469440d9b7f5ca710006bf
parent3eb057c4a73212e4ae25a228c1b610d317c6be4b (diff)
downloadphp-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.phpt32
-rw-r--r--Zend/zend_gc.c7
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)