Newsgroups: php.internals Path: news.php.net Xref: news.php.net php.internals:119609 Return-Path: Delivered-To: mailing list internals@lists.php.net Received: (qmail 40167 invoked from network); 27 Feb 2023 20:36:18 -0000 Received: from unknown (HELO php-smtp4.php.net) (45.112.84.5) by pb1.pair.com with SMTP; 27 Feb 2023 20:36:18 -0000 Received: from php-smtp4.php.net (localhost [127.0.0.1]) by php-smtp4.php.net (Postfix) with ESMTP id 79CFA180505 for ; Mon, 27 Feb 2023 12:36:17 -0800 (PST) X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on php-smtp4.php.net X-Spam-Level: X-Spam-Status: No, score=0.8 required=5.0 tests=BAYES_50,SPF_HELO_NONE, SPF_PASS,T_SCC_BODY_TEXT_LINE autolearn=no autolearn_force=no version=3.4.2 X-Spam-ASN: AS24940 138.201.0.0/16 X-Spam-Virus: No X-Envelope-From: Received: from swift.blarg.de (swift.blarg.de [138.201.185.127]) by php-smtp4.php.net (Postfix) with ESMTP for ; Mon, 27 Feb 2023 12:36:16 -0800 (PST) Received: from swift.blarg.de (swift.blarg.de [IPv6:2a01:4f8:c17:52a8::2]) (Authenticated sender: max) by swift.blarg.de (Postfix) with ESMTPSA id B436E40FEF for ; Mon, 27 Feb 2023 21:36:15 +0100 (CET) Date: Mon, 27 Feb 2023 21:36:14 +0100 To: internals@lists.php.net Message-ID: MIME-Version: 1.0 Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Subject: memdup(zend_ast_ref) From: max+php@blarg.de (Max Kellermann) 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