Fix memory leak of function attribute hash table#8070
Fix memory leak of function attribute hash table#8070TimWolla wants to merge 4 commits intophp:masterfrom
Conversation
cmb69
left a comment
There was a problem hiding this comment.
Thank you! Could you please add a regression test?
|
Also, shouldn't this target PHP-8.1? |
How would I write a test that checks for the absence of memory leaks? |
Probably PHP 8.0, as that's where attributes were introduced. Shall I cherry-pick the commit onto 8.0, force push and then change the target branch in GH's interface? |
Just write a test that triggers the code path; we run nightly builds with MSan/ASan enabled, which should catch this.
I usually rebase the local branch onto the new target branch (PHP-8.0, right), force-push, and then change the target branch in the GH UI. Otherwise, some CI get's confused (AppVeyor, and maybe some others). |
This is impossible to trigger as of right now, as there are no native functions with attributes (neither function-level, nor parameter level attributes). As mentioned in my initial message this was found during development of #7921 (which is currently in voting). |
|
Ah, right. Then it is okay without a test. :) |
Then just the rebase? Or shall this remain on |
|
Good point! I'm not sure whether there are any (PECL) extensions which use attributes; that memory leak might be relevant to them. Maybe @beberlei knows? |
https://github.com/php/php-src/blob/master/ext/zend_test/test.stub.php The |
|
looks correct to me |
|
@TysonAndre Thank you for the review and the hint regarding zend_test. @cmb69 Is this PR looking good to you, or would you like me to make changes? Which target branch should this use? I can integrate zend_test, if you think that would be good. |
|
@TimWolla, yes that looks good to me. Maybe it's best to target "master" for now; we can still back-port if actually relevant. Do you want to add a test right away? |
7289ce6 to
d15e9f7
Compare
|
@cmb69 I've rebased onto the current |
|
Okay, so Cirrus is happy, but Travis is unhappy about this. Probably good that I added a test. However I'm afraid that fixing this double free is above my pay grade. I can't do more than |
|
Okay, I was hoping that using I'm at my wits end here and frankly I can't spend any more time on this, because this is pure guesswork on my end. Someone more experienced than me will need to take this across the finish line. |
|
Ah, this is only reproducible with ZTS: |
I'm only moderately familiar with this code and have gotten stuck and frustrated a lot, especially with opcache. Someone more familiar than me will probably have to take a look. Leaving more context for people looking at this later: https://github.com/php/php-src/tree/master/ext/opcache/jit#running-tests-of-the-jit running locally with
Some of these may help, in combination with
# Run PHPs run-tests.php
script:
- ./travis/test.sh -d opcache.jit_buffer_size=16M -d opcache.jit=tracing
- if [[ "$ARM64" == 1 ]]; then ./travis/test.sh -d opcache.jit_buffer_size=16M -d opcache.jit=function; fi
- if [[ "$ARM64" == 1 ]]; then ./travis/test.sh -d opcache.jit_buffer_size=16M -d opcache.jit=tracing --repeat 2; fi
- sapi/cli/php -d extension_dir=`pwd`/modules -r 'dl("zend_test");' |
|
@TysonAndre Thank you for taking the time to assist me, I appreciate it and the information are helpful. However I believe I figured it out: There was a second bug lurking in the code, there was a missing call to |
b52ed3c to
db10b91
Compare
|
Additional tests may help detect if this is properly finished, e.g.
It seems like this should use the GC_TRY_ADDREF instead of GC_ADDREF macro because attributes can be an immutable array after adding it to opcache's shared memory (for methods, maybe copying from opcache?), not GC_ADDREF. static HashTable *zend_persist_attributes(HashTable *attributes)
{
// ...
HashTable *ptr = zend_shared_memdup_put_free(attributes, sizeof(HashTable));
GC_SET_REFCOUNT(ptr, 2);
GC_TYPE_INFO(ptr) = GC_ARRAY | ((IS_ARRAY_IMMUTABLE|GC_NOT_COLLECTABLE) << GC_FLAGS_SHIFT);static zend_always_inline uint32_t zend_gc_addref(zend_refcounted_h *p) {
ZEND_RC_MOD_CHECK(p);
return ++(p->refcount);
}
static zend_always_inline void zend_gc_try_addref(zend_refcounted_h *p) {
if (!(p->u.type_info & GC_IMMUTABLE)) {
ZEND_RC_MOD_CHECK(p);
++p->refcount;
}
} |
57e5436 to
a9e18d1
Compare
@TysonAndre You are correct: The code was not yet correct for class inheritance. I've now (hopefully) fixed those as well. |
|
Okay:
So I believe this is ready to go 😃 |
|
Tests look right and my previous review comments were addressed. ext/opcache/tests/jit/assign_dim_op_007.phpt for travis has nothing to do with attributes, and it's a new test. I don't see anything wrong with it but would (personally) like someone more familiar with opcache to take a look at this before merging it. |
a9e18d1 to
c8edd9c
Compare
|
Rebased onto the latest master to trigger the new GitHub Actions builds. PTAL 😃 |
c8edd9c to
bbfdc17
Compare
==109253== 280 (56 direct, 224 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==109253== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==109253== by 0x6D9FA2: __zend_malloc (zend_alloc.c:3068)
==109253== by 0x745138: zend_add_attribute (zend_attributes.c:226)
==109253== by 0x6680D1: zend_add_parameter_attribute (zend_attributes.h:102)
==109253== by 0x66B787: zm_startup_zend_test (test.c:478)
==109253== by 0x7224CD: zend_startup_module_ex (zend_API.c:2202)
==109253== by 0x72252C: zend_startup_module_zval (zend_API.c:2217)
==109253== by 0x734288: zend_hash_apply (zend_hash.c:2011)
==109253== by 0x722C30: zend_startup_modules (zend_API.c:2328)
==109253== by 0x67409B: php_module_startup (main.c:2256)
==109253== by 0x88EDDE: php_cli_startup (php_cli.c:409)
==109253== by 0x890F61: main (php_cli.c:1334)
These tests verify the correct workings of the previous fixes: - Parameter attributes for native functions should not leak memory. - Parameter attributes for native functions should behave as expected.
dbb619d to
fb7b2cf
Compare
|
@bwoebi Thanks for your assistance. As the CI was green I've rebased all the trial and error commits into a clean commit history. |
==109253== 280 (56 direct, 224 indirect) bytes in 1 blocks are definitely lost in loss record 4 of 4
==109253== at 0x483B7F3: malloc (in /usr/lib/x86_64-linux-gnu/valgrind/vgpreload_memcheck-amd64-linux.so)
==109253== by 0x6D9FA2: __zend_malloc (zend_alloc.c:3068)
==109253== by 0x745138: zend_add_attribute (zend_attributes.c:226)
==109253== by 0x6680D1: zend_add_parameter_attribute (zend_attributes.h:102)
==109253== by 0x66B787: zm_startup_zend_test (test.c:478)
==109253== by 0x7224CD: zend_startup_module_ex (zend_API.c:2202)
==109253== by 0x72252C: zend_startup_module_zval (zend_API.c:2217)
==109253== by 0x734288: zend_hash_apply (zend_hash.c:2011)
==109253== by 0x722C30: zend_startup_modules (zend_API.c:2328)
==109253== by 0x67409B: php_module_startup (main.c:2256)
==109253== by 0x88EDDE: php_cli_startup (php_cli.c:409)
==109253== by 0x890F61: main (php_cli.c:1334)
Whoops. I wanted to remove the attributes from the stub file anyway, because they don't do anything. Apparently I missed see also: #7921 (comment) |
Found while implementing #7921: