Skip to content

Commit a9b9158

Browse files
committed
Fix write to locked SHM memory
1 parent a76fd1b commit a9b9158

File tree

1 file changed

+73
-36
lines changed

1 file changed

+73
-36
lines changed

Zend/zend_inheritance.c

Lines changed: 73 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1898,18 +1898,45 @@ static zend_class_entry *fixup_trait_scope(const zend_function *fn, zend_class_e
18981898
return fn->common.scope->ce_flags & ZEND_ACC_TRAIT ? ce : fn->common.scope;
18991899
}
19001900

1901-
static void zend_resolve_trait_relative_class_types(zend_type *type, /* const */ zend_class_entry *ce)
1901+
/* We cannot modify the type in-place (e.g. via a pointer) as it is written to SHM */
1902+
static zend_type zend_resolve_single_type(zend_type type, const zend_class_entry *const ce)
19021903
{
1903-
/* Only built-in types */
1904-
if (!ZEND_TYPE_IS_COMPLEX(*type)) {
1905-
return;
1904+
/* Only built-in types + static */
1905+
if (!ZEND_TYPE_IS_COMPLEX(type)) {
1906+
return type;
19061907
}
1907-
/* We are adding trait methods to another trait, delay resolution */
1908-
if (ce->ce_flags & ZEND_ACC_TRAIT) {
1909-
return;
1908+
1909+
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(type) || (ZEND_TYPE_HAS_LIST(type)));
1910+
if (ZEND_TYPE_HAS_NAME(type)) {
1911+
if (ZEND_TYPE_IS_RELATIVE_SELF(type)) {
1912+
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1913+
return resolved_type;
1914+
} else if (ZEND_TYPE_IS_RELATIVE_PARENT(type)) {
1915+
if (!ce->parent) {
1916+
zend_error_noreturn(E_COMPILE_ERROR,
1917+
"Cannot use trait which has \"parent\" as a type when current class scope has no parent");
1918+
return (zend_type) ZEND_TYPE_INIT_NONE(0);
1919+
}
1920+
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->parent->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(type));
1921+
return resolved_type;
1922+
} else {
1923+
return type;
1924+
}
1925+
}
1926+
1927+
/* Intersection types cannot have relative class_types */
1928+
if (ZEND_TYPE_IS_INTERSECTION(type)) {
1929+
return type;
19101930
}
1931+
1932+
const zend_type_list *union_type_list = ZEND_TYPE_LIST(type);
19111933
zend_type *single_type;
1912-
ZEND_TYPE_FOREACH(*type, single_type) {
1934+
1935+
/* TODO Only do allocation if need to resolve types, as type is stored in SHM */
1936+
zend_type_list *new_union_type_list = zend_arena_alloc(&CG(arena), ZEND_TYPE_LIST_SIZE(union_type_list->num_types));
1937+
memcpy(new_union_type_list, union_type_list, ZEND_TYPE_LIST_SIZE(union_type_list->num_types));
1938+
1939+
ZEND_TYPE_LIST_FOREACH(new_union_type_list, single_type) {
19131940
ZEND_ASSERT(ZEND_TYPE_HAS_NAME(*single_type) || (ZEND_TYPE_IS_INTERSECTION(*single_type)));
19141941

19151942
/* Intersections types cannot have self or parent */
@@ -1918,20 +1945,52 @@ static void zend_resolve_trait_relative_class_types(zend_type *type, /* const */
19181945
}
19191946
if (ZEND_TYPE_IS_RELATIVE_SELF(*single_type)) {
19201947
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(*single_type));
1921-
/* Cannot use memcpy as we violate the restrict constraint of src and dest */
19221948
memmove(single_type, &resolved_type, sizeof(zend_type));
19231949
}
19241950
if (ZEND_TYPE_IS_RELATIVE_PARENT(*single_type)) {
19251951
if (!ce->parent) {
19261952
zend_error_noreturn(E_COMPILE_ERROR,
19271953
"Cannot use trait which has \"parent\" as a type when current class scope has no parent");
1928-
return;
1954+
return (zend_type) ZEND_TYPE_INIT_NONE(0);
19291955
}
19301956
zend_type resolved_type = (zend_type) ZEND_TYPE_INIT_CLASS(zend_string_copy(ce->parent->name), /* allows_null */ false, /* extra_flags */ ZEND_TYPE_FULL_MASK(*single_type));
1931-
/* Cannot use memcpy as we violate the restrict constraint of src and dest */
19321957
memmove(single_type, &resolved_type, sizeof(zend_type));
19331958
}
1934-
} ZEND_TYPE_FOREACH_END();
1959+
} ZEND_TYPE_LIST_FOREACH_END();
1960+
1961+
zend_type new_type = (zend_type) ZEND_TYPE_INIT_NONE(0);
1962+
ZEND_TYPE_SET_LIST(new_type, new_union_type_list);
1963+
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_ARENA_BIT;
1964+
/* Inform that the type list is a union type */
1965+
ZEND_TYPE_FULL_MASK(new_type) |= _ZEND_TYPE_UNION_BIT;
1966+
return new_type;
1967+
}
1968+
1969+
static void zend_resolve_trait_relative_class_types(zend_function *const fn, const zend_class_entry *const ce)
1970+
{
1971+
/* We are adding trait methods to another trait, delay resolution */
1972+
if (ce->ce_flags & ZEND_ACC_TRAIT) {
1973+
return;
1974+
}
1975+
/* No type info */
1976+
if (!fn->common.arg_info) {
1977+
return;
1978+
}
1979+
1980+
bool has_return_type = fn->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE;
1981+
uint32_t num_args = fn->common.num_args;
1982+
/* TODO Only do allocation if need to resolve types, as arg_info is stored in SHM */
1983+
size_t allocated_size = sizeof(zend_arg_info) * (has_return_type + num_args);
1984+
1985+
zend_arg_info *new_arg_infos = zend_arena_alloc(&CG(arena), allocated_size);
1986+
memcpy(new_arg_infos, fn->common.arg_info - has_return_type, allocated_size);
1987+
fn->common.arg_info = new_arg_infos + has_return_type;
1988+
1989+
for (uint32_t i = 0; i < num_args + has_return_type; i++) {
1990+
// TODO Handle variadic parameter types?
1991+
zend_type type = new_arg_infos[i].type;
1992+
new_arg_infos[i].type = zend_resolve_single_type(type, ce);
1993+
}
19351994
}
19361995

19371996
static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_string *key, zend_function *fn) /* {{{ */
@@ -1983,34 +2042,12 @@ static void zend_add_trait_method(zend_class_entry *ce, zend_string *name, zend_
19832042
if (UNEXPECTED(fn->type == ZEND_INTERNAL_FUNCTION)) {
19842043
new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_internal_function));
19852044
memcpy(new_fn, fn, sizeof(zend_internal_function));
1986-
if (new_fn->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
1987-
zend_type *return_type = &new_fn->common.arg_info[-1].type;
1988-
zend_resolve_trait_relative_class_types(return_type, ce);
1989-
}
1990-
1991-
uint32_t num_args = new_fn->common.num_args;
1992-
for (uint32_t i = 0; i < num_args; i++) {
1993-
// TODO Handle variadic parameter types?
1994-
zend_arg_info *arg_info = &new_fn->common.arg_info[i];
1995-
zend_type *type = &arg_info->type;
1996-
zend_resolve_trait_relative_class_types(type, ce);
1997-
}
2045+
zend_resolve_trait_relative_class_types(new_fn, ce);
19982046
new_fn->common.fn_flags |= ZEND_ACC_ARENA_ALLOCATED;
19992047
} else {
20002048
new_fn = zend_arena_alloc(&CG(arena), sizeof(zend_op_array));
20012049
memcpy(new_fn, fn, sizeof(zend_op_array));
2002-
if (new_fn->common.fn_flags & ZEND_ACC_HAS_RETURN_TYPE) {
2003-
zend_type *return_type = &new_fn->common.arg_info[-1].type;
2004-
zend_resolve_trait_relative_class_types(return_type, ce);
2005-
}
2006-
2007-
uint32_t num_args = new_fn->common.num_args;
2008-
for (uint32_t i = 0; i < num_args; i++) {
2009-
// TODO Handle variadic parameter types?
2010-
zend_arg_info *arg_info = &new_fn->common.arg_info[i];
2011-
zend_type *type = &arg_info->type;
2012-
zend_resolve_trait_relative_class_types(type, ce);
2013-
}
2050+
zend_resolve_trait_relative_class_types(new_fn, ce);
20142051
new_fn->op_array.fn_flags |= ZEND_ACC_TRAIT_CLONE;
20152052
new_fn->op_array.fn_flags &= ~ZEND_ACC_IMMUTABLE;
20162053
}

0 commit comments

Comments
 (0)