mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Fixed bug #73989 (PHP 7.1 Segfaults within Symfony test suite)
This commit is contained in:
parent
eb1373e509
commit
3917350531
4 changed files with 114 additions and 52 deletions
2
NEWS
2
NEWS
|
@ -3,6 +3,8 @@ PHP NEWS
|
||||||
?? ??? 2017 PHP 7.0.17
|
?? ??? 2017 PHP 7.0.17
|
||||||
|
|
||||||
- Core:
|
- Core:
|
||||||
|
. Fixed bug #73989 (PHP 7.1 Segfaults within Symfony test suite).
|
||||||
|
(Dmitry, Laruence)
|
||||||
. Fixed bug #74084 (Out of bound read - zend_mm_alloc_small). (Laruence)
|
. Fixed bug #74084 (Out of bound read - zend_mm_alloc_small). (Laruence)
|
||||||
. Fixed bug #73807 (Performance problem with processing large post request).
|
. Fixed bug #73807 (Performance problem with processing large post request).
|
||||||
(Nikita)
|
(Nikita)
|
||||||
|
|
28
Zend/tests/bug73989.phpt
Normal file
28
Zend/tests/bug73989.phpt
Normal file
|
@ -0,0 +1,28 @@
|
||||||
|
--TEST--
|
||||||
|
Bug #73989 (PHP 7.1 Segfaults within Symfony test suite)
|
||||||
|
--FILE--
|
||||||
|
<?php
|
||||||
|
class Cycle
|
||||||
|
{
|
||||||
|
private $thing;
|
||||||
|
|
||||||
|
public function __construct()
|
||||||
|
{
|
||||||
|
$obj = $this;
|
||||||
|
$this->thing = function() use($obj) {};
|
||||||
|
}
|
||||||
|
|
||||||
|
public function __destruct()
|
||||||
|
{
|
||||||
|
($this->thing)();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
for ($i = 0; $i < 10000; ++$i) {
|
||||||
|
$obj = new Cycle();
|
||||||
|
}
|
||||||
|
echo "OK\n";
|
||||||
|
?>
|
||||||
|
--EXPECT--
|
||||||
|
OK
|
121
Zend/zend_gc.c
121
Zend/zend_gc.c
|
@ -25,26 +25,12 @@
|
||||||
/* one (0) is reserved */
|
/* one (0) is reserved */
|
||||||
#define GC_ROOT_BUFFER_MAX_ENTRIES 10001
|
#define GC_ROOT_BUFFER_MAX_ENTRIES 10001
|
||||||
|
|
||||||
#define GC_FAKE_BUFFER_FLAG 0x80
|
|
||||||
#define GC_TYPE_MASK 0x7f
|
|
||||||
|
|
||||||
#define GC_HAS_DESTRUCTORS (1<<0)
|
#define GC_HAS_DESTRUCTORS (1<<0)
|
||||||
|
|
||||||
#ifndef ZEND_GC_DEBUG
|
#ifndef ZEND_GC_DEBUG
|
||||||
# define ZEND_GC_DEBUG 0
|
# define ZEND_GC_DEBUG 0
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define GC_NUM_ADDITIONAL_ENTRIES \
|
|
||||||
((4096 - ZEND_MM_OVERHEAD - sizeof(void*) * 2) / sizeof(gc_root_buffer))
|
|
||||||
|
|
||||||
typedef struct _gc_additional_bufer gc_additional_buffer;
|
|
||||||
|
|
||||||
struct _gc_additional_bufer {
|
|
||||||
uint32_t used;
|
|
||||||
gc_additional_buffer *next;
|
|
||||||
gc_root_buffer buf[GC_NUM_ADDITIONAL_ENTRIES];
|
|
||||||
};
|
|
||||||
|
|
||||||
#ifdef ZTS
|
#ifdef ZTS
|
||||||
ZEND_API int gc_globals_id;
|
ZEND_API int gc_globals_id;
|
||||||
#else
|
#else
|
||||||
|
@ -53,9 +39,6 @@ ZEND_API zend_gc_globals gc_globals;
|
||||||
|
|
||||||
ZEND_API int (*gc_collect_cycles)(void);
|
ZEND_API int (*gc_collect_cycles)(void);
|
||||||
|
|
||||||
#define GC_REMOVE_FROM_ROOTS(current) \
|
|
||||||
gc_remove_from_roots((current))
|
|
||||||
|
|
||||||
#if ZEND_GC_DEBUG > 1
|
#if ZEND_GC_DEBUG > 1
|
||||||
# define GC_TRACE(format, ...) fprintf(stderr, format "\n", ##__VA_ARGS__);
|
# define GC_TRACE(format, ...) fprintf(stderr, format "\n", ##__VA_ARGS__);
|
||||||
# define GC_TRACE_REF(ref, format, ...) \
|
# define GC_TRACE_REF(ref, format, ...) \
|
||||||
|
@ -123,6 +106,12 @@ static zend_always_inline void gc_remove_from_roots(gc_root_buffer *root)
|
||||||
GC_BENCH_DEC(root_buf_length);
|
GC_BENCH_DEC(root_buf_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static zend_always_inline void gc_remove_from_additional_roots(gc_root_buffer *root)
|
||||||
|
{
|
||||||
|
root->next->prev = root->prev;
|
||||||
|
root->prev->next = root->next;
|
||||||
|
}
|
||||||
|
|
||||||
static void root_buffer_dtor(zend_gc_globals *gc_globals)
|
static void root_buffer_dtor(zend_gc_globals *gc_globals)
|
||||||
{
|
{
|
||||||
if (gc_globals->buf) {
|
if (gc_globals->buf) {
|
||||||
|
@ -149,6 +138,8 @@ static void gc_globals_ctor_ex(zend_gc_globals *gc_globals)
|
||||||
gc_globals->gc_runs = 0;
|
gc_globals->gc_runs = 0;
|
||||||
gc_globals->collected = 0;
|
gc_globals->collected = 0;
|
||||||
|
|
||||||
|
gc_globals->additional_buffer = NULL;
|
||||||
|
|
||||||
#if GC_BENCH
|
#if GC_BENCH
|
||||||
gc_globals->root_buf_length = 0;
|
gc_globals->root_buf_length = 0;
|
||||||
gc_globals->root_buf_peak = 0;
|
gc_globals->root_buf_peak = 0;
|
||||||
|
@ -204,6 +195,8 @@ ZEND_API void gc_reset(void)
|
||||||
GC_G(first_unused) = NULL;
|
GC_G(first_unused) = NULL;
|
||||||
GC_G(last_unused) = NULL;
|
GC_G(last_unused) = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
GC_G(additional_buffer) = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ZEND_API void gc_init(void)
|
ZEND_API void gc_init(void)
|
||||||
|
@ -276,21 +269,42 @@ ZEND_API void ZEND_FASTCALL gc_possible_root(zend_refcounted *ref)
|
||||||
GC_BENCH_PEAK(root_buf_peak, root_buf_length);
|
GC_BENCH_PEAK(root_buf_peak, root_buf_length);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static zend_always_inline gc_root_buffer* gc_find_additional_buffer(zend_refcounted *ref)
|
||||||
|
{
|
||||||
|
gc_additional_buffer *additional_buffer = GC_G(additional_buffer);
|
||||||
|
|
||||||
|
/* We have to check each additional_buffer to find which one holds the ref */
|
||||||
|
while (additional_buffer) {
|
||||||
|
gc_root_buffer *root = additional_buffer->buf + (GC_ADDRESS(GC_INFO(ref)) - GC_ROOT_BUFFER_MAX_ENTRIES);
|
||||||
|
if (root->ref == ref) {
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
additional_buffer = additional_buffer->next;
|
||||||
|
}
|
||||||
|
|
||||||
|
ZEND_ASSERT(0);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref)
|
ZEND_API void ZEND_FASTCALL gc_remove_from_buffer(zend_refcounted *ref)
|
||||||
{
|
{
|
||||||
gc_root_buffer *root;
|
gc_root_buffer *root;
|
||||||
|
|
||||||
ZEND_ASSERT(GC_ADDRESS(GC_INFO(ref)));
|
ZEND_ASSERT(GC_ADDRESS(GC_INFO(ref)));
|
||||||
ZEND_ASSERT(GC_ADDRESS(GC_INFO(ref)) < GC_ROOT_BUFFER_MAX_ENTRIES);
|
|
||||||
|
|
||||||
GC_BENCH_INC(zval_remove_from_buffer);
|
GC_BENCH_INC(zval_remove_from_buffer);
|
||||||
|
|
||||||
|
if (EXPECTED(GC_ADDRESS(GC_INFO(ref)) < GC_ROOT_BUFFER_MAX_ENTRIES)) {
|
||||||
root = GC_G(buf) + GC_ADDRESS(GC_INFO(ref));
|
root = GC_G(buf) + GC_ADDRESS(GC_INFO(ref));
|
||||||
|
gc_remove_from_roots(root);
|
||||||
|
} else {
|
||||||
|
root = gc_find_additional_buffer(ref);
|
||||||
|
gc_remove_from_additional_roots(root);
|
||||||
|
}
|
||||||
if (GC_REF_GET_COLOR(ref) != GC_BLACK) {
|
if (GC_REF_GET_COLOR(ref) != GC_BLACK) {
|
||||||
GC_TRACE_SET_COLOR(ref, GC_PURPLE);
|
GC_TRACE_SET_COLOR(ref, GC_PURPLE);
|
||||||
}
|
}
|
||||||
GC_INFO(ref) = 0;
|
GC_INFO(ref) = 0;
|
||||||
GC_REMOVE_FROM_ROOTS(root);
|
|
||||||
|
|
||||||
/* updete next root that is going to be freed */
|
/* updete next root that is going to be freed */
|
||||||
if (GC_G(next_to_free) == root) {
|
if (GC_G(next_to_free) == root) {
|
||||||
|
@ -641,7 +655,7 @@ static void gc_scan_roots(void)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static void gc_add_garbage(zend_refcounted *ref, gc_additional_buffer **additional_buffer)
|
static void gc_add_garbage(zend_refcounted *ref)
|
||||||
{
|
{
|
||||||
gc_root_buffer *buf = GC_G(unused);
|
gc_root_buffer *buf = GC_G(unused);
|
||||||
|
|
||||||
|
@ -664,25 +678,23 @@ static void gc_add_garbage(zend_refcounted *ref, gc_additional_buffer **addition
|
||||||
#endif
|
#endif
|
||||||
} else {
|
} else {
|
||||||
/* If we don't have free slots in the buffer, allocate a new one and
|
/* If we don't have free slots in the buffer, allocate a new one and
|
||||||
* set it's address to GC_ROOT_BUFFER_MAX_ENTRIES that have special
|
* set it's address above GC_ROOT_BUFFER_MAX_ENTRIES that have special
|
||||||
* meaning.
|
* meaning.
|
||||||
*/
|
*/
|
||||||
if (!*additional_buffer || (*additional_buffer)->used == GC_NUM_ADDITIONAL_ENTRIES) {
|
if (!GC_G(additional_buffer) || GC_G(additional_buffer)->used == GC_NUM_ADDITIONAL_ENTRIES) {
|
||||||
gc_additional_buffer *new_buffer = emalloc(sizeof(gc_additional_buffer));
|
gc_additional_buffer *new_buffer = emalloc(sizeof(gc_additional_buffer));
|
||||||
new_buffer->used = 0;
|
new_buffer->used = 0;
|
||||||
new_buffer->next = *additional_buffer;
|
new_buffer->next = GC_G(additional_buffer);
|
||||||
*additional_buffer = new_buffer;
|
GC_G(additional_buffer) = new_buffer;
|
||||||
}
|
}
|
||||||
buf = (*additional_buffer)->buf + (*additional_buffer)->used;
|
buf = GC_G(additional_buffer)->buf + GC_G(additional_buffer)->used;
|
||||||
(*additional_buffer)->used++;
|
|
||||||
#if 1
|
#if 1
|
||||||
/* optimization: color is already GC_BLACK (0) */
|
/* optimization: color is already GC_BLACK (0) */
|
||||||
GC_INFO(ref) = GC_ROOT_BUFFER_MAX_ENTRIES;
|
GC_INFO(ref) = GC_ROOT_BUFFER_MAX_ENTRIES + GC_G(additional_buffer)->used;
|
||||||
#else
|
#else
|
||||||
GC_REF_SET_ADDRESS(ref, GC_ROOT_BUFFER_MAX_ENTRIES);
|
GC_REF_SET_ADDRESS(ref, GC_ROOT_BUFFER_MAX_ENTRIES) + GC_G(additional_buffer)->used;
|
||||||
#endif
|
#endif
|
||||||
/* modify type to prevent indirect destruction */
|
GC_G(additional_buffer)->used++;
|
||||||
GC_TYPE(ref) |= GC_FAKE_BUFFER_FLAG;
|
|
||||||
}
|
}
|
||||||
if (buf) {
|
if (buf) {
|
||||||
GC_REFCOUNT(ref)++;
|
GC_REFCOUNT(ref)++;
|
||||||
|
@ -694,7 +706,7 @@ static void gc_add_garbage(zend_refcounted *ref, gc_additional_buffer **addition
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gc_collect_white(zend_refcounted *ref, uint32_t *flags, gc_additional_buffer **additional_buffer)
|
static int gc_collect_white(zend_refcounted *ref, uint32_t *flags)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
HashTable *ht;
|
HashTable *ht;
|
||||||
|
@ -727,7 +739,7 @@ tail_call:
|
||||||
#else
|
#else
|
||||||
if (!GC_ADDRESS(GC_INFO(ref))) {
|
if (!GC_ADDRESS(GC_INFO(ref))) {
|
||||||
#endif
|
#endif
|
||||||
gc_add_garbage(ref, additional_buffer);
|
gc_add_garbage(ref);
|
||||||
}
|
}
|
||||||
if (obj->handlers->dtor_obj &&
|
if (obj->handlers->dtor_obj &&
|
||||||
((obj->handlers->dtor_obj != zend_objects_destroy_object) ||
|
((obj->handlers->dtor_obj != zend_objects_destroy_object) ||
|
||||||
|
@ -751,7 +763,7 @@ tail_call:
|
||||||
if (Z_REFCOUNTED_P(zv)) {
|
if (Z_REFCOUNTED_P(zv)) {
|
||||||
ref = Z_COUNTED_P(zv);
|
ref = Z_COUNTED_P(zv);
|
||||||
GC_REFCOUNT(ref)++;
|
GC_REFCOUNT(ref)++;
|
||||||
count += gc_collect_white(ref, flags, additional_buffer);
|
count += gc_collect_white(ref, flags);
|
||||||
/* count non-refcounted for compatibility ??? */
|
/* count non-refcounted for compatibility ??? */
|
||||||
} else if (Z_TYPE_P(zv) != IS_UNDEF) {
|
} else if (Z_TYPE_P(zv) != IS_UNDEF) {
|
||||||
count++;
|
count++;
|
||||||
|
@ -773,7 +785,7 @@ tail_call:
|
||||||
#else
|
#else
|
||||||
if (!GC_ADDRESS(GC_INFO(ref))) {
|
if (!GC_ADDRESS(GC_INFO(ref))) {
|
||||||
#endif
|
#endif
|
||||||
gc_add_garbage(ref, additional_buffer);
|
gc_add_garbage(ref);
|
||||||
}
|
}
|
||||||
ht = (zend_array*)ref;
|
ht = (zend_array*)ref;
|
||||||
} else if (GC_TYPE(ref) == IS_REFERENCE) {
|
} else if (GC_TYPE(ref) == IS_REFERENCE) {
|
||||||
|
@ -813,7 +825,7 @@ tail_call:
|
||||||
if (Z_REFCOUNTED_P(zv)) {
|
if (Z_REFCOUNTED_P(zv)) {
|
||||||
ref = Z_COUNTED_P(zv);
|
ref = Z_COUNTED_P(zv);
|
||||||
GC_REFCOUNT(ref)++;
|
GC_REFCOUNT(ref)++;
|
||||||
count += gc_collect_white(ref, flags, additional_buffer);
|
count += gc_collect_white(ref, flags);
|
||||||
/* count non-refcounted for compatibility ??? */
|
/* count non-refcounted for compatibility ??? */
|
||||||
} else if (Z_TYPE_P(zv) != IS_UNDEF) {
|
} else if (Z_TYPE_P(zv) != IS_UNDEF) {
|
||||||
count++;
|
count++;
|
||||||
|
@ -831,7 +843,7 @@ tail_call:
|
||||||
return count;
|
return count;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int gc_collect_roots(uint32_t *flags, gc_additional_buffer **additional_buffer)
|
static int gc_collect_roots(uint32_t *flags)
|
||||||
{
|
{
|
||||||
int count = 0;
|
int count = 0;
|
||||||
gc_root_buffer *current = GC_G(roots).next;
|
gc_root_buffer *current = GC_G(roots).next;
|
||||||
|
@ -840,8 +852,12 @@ static int gc_collect_roots(uint32_t *flags, gc_additional_buffer **additional_b
|
||||||
while (current != &GC_G(roots)) {
|
while (current != &GC_G(roots)) {
|
||||||
gc_root_buffer *next = current->next;
|
gc_root_buffer *next = current->next;
|
||||||
if (GC_REF_GET_COLOR(current->ref) == GC_BLACK) {
|
if (GC_REF_GET_COLOR(current->ref) == GC_BLACK) {
|
||||||
|
if (EXPECTED(GC_ADDRESS(GC_INFO(current->ref)) < GC_ROOT_BUFFER_MAX_ENTRIES)) {
|
||||||
|
gc_remove_from_roots(current);
|
||||||
|
} else {
|
||||||
|
gc_remove_from_additional_roots(current);
|
||||||
|
}
|
||||||
GC_INFO(current->ref) = 0; /* reset GC_ADDRESS() and keep GC_BLACK */
|
GC_INFO(current->ref) = 0; /* reset GC_ADDRESS() and keep GC_BLACK */
|
||||||
GC_REMOVE_FROM_ROOTS(current);
|
|
||||||
}
|
}
|
||||||
current = next;
|
current = next;
|
||||||
}
|
}
|
||||||
|
@ -850,7 +866,7 @@ static int gc_collect_roots(uint32_t *flags, gc_additional_buffer **additional_b
|
||||||
while (current != &GC_G(roots)) {
|
while (current != &GC_G(roots)) {
|
||||||
GC_REFCOUNT(current->ref)++;
|
GC_REFCOUNT(current->ref)++;
|
||||||
if (GC_REF_GET_COLOR(current->ref) == GC_WHITE) {
|
if (GC_REF_GET_COLOR(current->ref) == GC_WHITE) {
|
||||||
count += gc_collect_white(current->ref, flags, additional_buffer);
|
count += gc_collect_white(current->ref, flags);
|
||||||
}
|
}
|
||||||
current = current->next;
|
current = current->next;
|
||||||
}
|
}
|
||||||
|
@ -886,13 +902,16 @@ static void gc_remove_nested_data_from_buffer(zend_refcounted *ref, gc_root_buff
|
||||||
tail_call:
|
tail_call:
|
||||||
if (root ||
|
if (root ||
|
||||||
(GC_ADDRESS(GC_INFO(ref)) != 0 &&
|
(GC_ADDRESS(GC_INFO(ref)) != 0 &&
|
||||||
GC_REF_GET_COLOR(ref) == GC_BLACK &&
|
GC_REF_GET_COLOR(ref) == GC_BLACK)) {
|
||||||
GC_ADDRESS(GC_INFO(ref)) != GC_ROOT_BUFFER_MAX_ENTRIES)) {
|
|
||||||
GC_TRACE_REF(ref, "removing from buffer");
|
GC_TRACE_REF(ref, "removing from buffer");
|
||||||
GC_REFCOUNT(ref)--;
|
GC_REFCOUNT(ref)--;
|
||||||
if (root) {
|
if (root) {
|
||||||
|
if (EXPECTED(GC_ADDRESS(GC_INFO(root->ref)) < GC_ROOT_BUFFER_MAX_ENTRIES)) {
|
||||||
|
gc_remove_from_roots(root);
|
||||||
|
} else {
|
||||||
|
gc_remove_from_additional_roots(root);
|
||||||
|
}
|
||||||
GC_INFO(ref) = 0;
|
GC_INFO(ref) = 0;
|
||||||
GC_REMOVE_FROM_ROOTS(root);
|
|
||||||
root = NULL;
|
root = NULL;
|
||||||
} else {
|
} else {
|
||||||
GC_REMOVE_FROM_BUFFER(ref);
|
GC_REMOVE_FROM_BUFFER(ref);
|
||||||
|
@ -986,7 +1005,7 @@ ZEND_API int zend_gc_collect_cycles(void)
|
||||||
zend_refcounted *p;
|
zend_refcounted *p;
|
||||||
gc_root_buffer to_free;
|
gc_root_buffer to_free;
|
||||||
uint32_t gc_flags = 0;
|
uint32_t gc_flags = 0;
|
||||||
gc_additional_buffer *additional_buffer;
|
gc_additional_buffer *additional_buffer_snapshot;
|
||||||
#if ZEND_GC_DEBUG
|
#if ZEND_GC_DEBUG
|
||||||
zend_bool orig_gc_full;
|
zend_bool orig_gc_full;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1010,8 +1029,8 @@ ZEND_API int zend_gc_collect_cycles(void)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
GC_TRACE("Collecting roots");
|
GC_TRACE("Collecting roots");
|
||||||
additional_buffer = NULL;
|
additional_buffer_snapshot = GC_G(additional_buffer);
|
||||||
count = gc_collect_roots(&gc_flags, &additional_buffer);
|
count = gc_collect_roots(&gc_flags);
|
||||||
#if ZEND_GC_DEBUG
|
#if ZEND_GC_DEBUG
|
||||||
GC_G(gc_full) = orig_gc_full;
|
GC_G(gc_full) = orig_gc_full;
|
||||||
#endif
|
#endif
|
||||||
|
@ -1055,7 +1074,7 @@ ZEND_API int zend_gc_collect_cycles(void)
|
||||||
while (current != &to_free) {
|
while (current != &to_free) {
|
||||||
p = current->ref;
|
p = current->ref;
|
||||||
GC_G(next_to_free) = current->next;
|
GC_G(next_to_free) = current->next;
|
||||||
if ((GC_TYPE(p) & GC_TYPE_MASK) == IS_OBJECT) {
|
if (GC_TYPE(p) == IS_OBJECT) {
|
||||||
zend_object *obj = (zend_object*)p;
|
zend_object *obj = (zend_object*)p;
|
||||||
|
|
||||||
if (IS_OBJ_VALID(EG(objects_store).object_buckets[obj->handle]) &&
|
if (IS_OBJ_VALID(EG(objects_store).object_buckets[obj->handle]) &&
|
||||||
|
@ -1092,7 +1111,7 @@ ZEND_API int zend_gc_collect_cycles(void)
|
||||||
p = current->ref;
|
p = current->ref;
|
||||||
GC_G(next_to_free) = current->next;
|
GC_G(next_to_free) = current->next;
|
||||||
GC_TRACE_REF(p, "destroying");
|
GC_TRACE_REF(p, "destroying");
|
||||||
if ((GC_TYPE(p) & GC_TYPE_MASK) == IS_OBJECT) {
|
if (GC_TYPE(p) == IS_OBJECT) {
|
||||||
zend_object *obj = (zend_object*)p;
|
zend_object *obj = (zend_object*)p;
|
||||||
|
|
||||||
if (EG(objects_store).object_buckets &&
|
if (EG(objects_store).object_buckets &&
|
||||||
|
@ -1111,7 +1130,7 @@ ZEND_API int zend_gc_collect_cycles(void)
|
||||||
EG(objects_store).free_list_head = obj->handle;
|
EG(objects_store).free_list_head = obj->handle;
|
||||||
p = current->ref = (zend_refcounted*)(((char*)obj) - obj->handlers->offset);
|
p = current->ref = (zend_refcounted*)(((char*)obj) - obj->handlers->offset);
|
||||||
}
|
}
|
||||||
} else if ((GC_TYPE(p) & GC_TYPE_MASK) == IS_ARRAY) {
|
} else if (GC_TYPE(p) == IS_ARRAY) {
|
||||||
zend_array *arr = (zend_array*)p;
|
zend_array *arr = (zend_array*)p;
|
||||||
|
|
||||||
GC_TYPE(arr) = IS_NULL;
|
GC_TYPE(arr) = IS_NULL;
|
||||||
|
@ -1133,10 +1152,10 @@ ZEND_API int zend_gc_collect_cycles(void)
|
||||||
current = next;
|
current = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
while (additional_buffer != NULL) {
|
while (GC_G(additional_buffer) != additional_buffer_snapshot) {
|
||||||
gc_additional_buffer *next = additional_buffer->next;
|
gc_additional_buffer *next = GC_G(additional_buffer)->next;
|
||||||
efree(additional_buffer);
|
efree(GC_G(additional_buffer));
|
||||||
additional_buffer = next;
|
GC_G(additional_buffer) = next;
|
||||||
}
|
}
|
||||||
|
|
||||||
GC_TRACE("Collection finished");
|
GC_TRACE("Collection finished");
|
||||||
|
|
|
@ -67,6 +67,17 @@ typedef struct _gc_root_buffer {
|
||||||
uint32_t refcount;
|
uint32_t refcount;
|
||||||
} gc_root_buffer;
|
} gc_root_buffer;
|
||||||
|
|
||||||
|
#define GC_NUM_ADDITIONAL_ENTRIES \
|
||||||
|
((4096 - ZEND_MM_OVERHEAD - sizeof(void*) * 2) / sizeof(gc_root_buffer))
|
||||||
|
|
||||||
|
typedef struct _gc_additional_bufer gc_additional_buffer;
|
||||||
|
|
||||||
|
struct _gc_additional_bufer {
|
||||||
|
uint32_t used;
|
||||||
|
gc_additional_buffer *next;
|
||||||
|
gc_root_buffer buf[GC_NUM_ADDITIONAL_ENTRIES];
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct _zend_gc_globals {
|
typedef struct _zend_gc_globals {
|
||||||
zend_bool gc_enabled;
|
zend_bool gc_enabled;
|
||||||
zend_bool gc_active;
|
zend_bool gc_active;
|
||||||
|
@ -93,6 +104,8 @@ typedef struct _zend_gc_globals {
|
||||||
uint32_t zval_marked_grey;
|
uint32_t zval_marked_grey;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
gc_additional_buffer *additional_buffer;
|
||||||
|
|
||||||
} zend_gc_globals;
|
} zend_gc_globals;
|
||||||
|
|
||||||
#ifdef ZTS
|
#ifdef ZTS
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue