|
php.net | support | documentation | report a bug | advanced search | search howto | statistics | random bug | login |
PatchesPull RequestsHistoryAllCommentsChangesGit/SVN commits
[2017-05-09 02:50 UTC] laruence@php.net
[2017-05-14 19:31 UTC] andrew dot nester dot de at gmail dot com
[2017-06-23 15:46 UTC] nikic@php.net
-Status: Open
+Status: Not a bug
[2017-06-23 15:46 UTC] nikic@php.net
|
|||||||||||||||||||||||||||
Copyright © 2001-2025 The PHP GroupAll rights reserved. |
Last updated: Thu Oct 30 09:00:02 2025 UTC |
Description: ------------ I'd like to report a potential double-free (a special case of use-after-free) bug as follows. Step 1, function _zend_shared_memdup (defined in lines 349-365 in ext/opcache/zend_shared_alloc.c) frees "source" in line 362. Step 2, function _zend_shared_memdup returns to its call site in function zend_persist_ast (defined in lines 247-278 in ext/opcache/zend_persist.c) in line 253/258/267. Step 3, "ast" is freed in line 267 (ext/opcache/zend_persist.c). Note that "ast" and "source" are pointer aliases due to parameter passing at line 253/258/267. Below is code snippet. /*--- ext/opcache/zend_shared_alloc.c ---*/ 349: void *_zend_shared_memdup(void *source, size_t size, zend_bool free_source) 350: { 351: void *old_p, *retval; 352: 353: if ((old_p = zend_hash_index_find_ptr(&ZCG(xlat_table), (zend_ulong)source)) != NULL) { 354: /* we already duplicated this pointer */ 355: return old_p; 356: } 357: retval = ZCG(mem); 358: ZCG(mem) = (void*)(((char*)ZCG(mem)) + ZEND_ALIGNED_SIZE(size)); 359: memcpy(retval, source, size); 360: zend_shared_alloc_register_xlat_entry(source, retval); 361: if (free_source) { 362: efree(source); //////FREE the first time 363: } 364: return retval; 365: } /*--- ext/opcache/zend_persist.c ---*/ 247: static zend_ast *zend_persist_ast(zend_ast *ast) 248: { 249: uint32_t i; 250: zend_ast *node; 251: 252: if (ast->kind == ZEND_AST_ZVAL) { 253: zend_ast_zval *copy = zend_accel_memdup(ast, sizeof(zend_ast_zval)); 254: zend_persist_zval(©->val); 255: node = (zend_ast *) copy; 256: } else if (zend_ast_is_list(ast)) { 257: zend_ast_list *list = zend_ast_get_list(ast); 258: zend_ast_list *copy = zend_accel_memdup(ast, 259: sizeof(zend_ast_list) - sizeof(zend_ast *) + sizeof(zend_ast *) * list->children); 260: for (i = 0; i < list->children; i++) { 261: if (copy->child[i]) { 262: copy->child[i] = zend_persist_ast(copy->child[i]); 263: } 264: } 265: node = (zend_ast *) copy; 266: } else { 267: uint32_t children = zend_ast_get_num_children(ast); 268: node = zend_accel_memdup(ast, sizeof(zend_ast) - sizeof(zend_ast *) + sizeof(zend_ast *) * children); 269: for (i = 0; i < children; i++) { 270: if (node->child[i]) { 271: node->child[i] = zend_persist_ast(node->child[i]); 272: } 273: } 274: } 275: 276: efree(ast); //////FREE AGAIN 277: return node; 278: }