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

-- 
PHP Internals - PHP Runtime Development Mailing List
To unsubscribe, visit: https://www.php.net/unsub.php

Reply via email to