Hi,
today, I stumbled on this piece of code in zend_persist.c:
zend_ast_ref *old_ref = Z_AST_P(z);
Z_AST_P(z) = zend_shared_memdup_put(Z_AST_P(z), sizeof(zend_ast_ref));
This is the definition of zend_ast_ref
from zend_types.h:
struct _zend_ast_ref {
zend_refcounted_h gc;
/*zend_ast ast; zend_ast follows the zend_ast_ref structure */
};
The memdup() call confuses me. It looks broken.
It appears that code which allocates zend_ast_ref
reserves some
space after that for one or more zend_ast
instances, see
zend_ast_copy() and create_enum_case_ast().
But what happens if I memdup() only the raw zend_ast_ref
, which
consists of only the zend_refcounted_h
?
What confuses me even more is that zend_persist.c then calls
zend_persist_ast() to copy one zend_ast
that follows after the
zend_ast_ref
object, but discards the newly allocated value.
Not only does this look like a memory leak, but also the
zend_ast_ref
is incomplete, and dereferencing the following
zend_ast
should be an out-of-bounds access.
Does this piece of code rely on the next zend_shared_memdup() call to
place the next allocation right after the zend_ast_ref
?
(This sounds pretty fragile. What happens if padding happens to get
inserted by the allocator?)
Max