pecl-gearman memleak troubleshooting in PHP7 port

From: Date: Fri, 06 May 2016 20:35:37 +0000
Subject: pecl-gearman memleak troubleshooting in PHP7 port
Groups: php.pecl.dev 
Request: Send a blank email to pecl-dev+get-13735@lists.php.net to get a copy of this message
Hey All, *tl;dr* - if you have an example of storing a callback that is a method call and destroying it at the object's destruction, could you share? Specifically one that works with a user defined object method call as the callback. I've been working on the port for pecl-gearman to PHP 7 for the last year or so, which is in a relatively stable state now. There's one last memleak I'm trying to iron out. I'll leave replication details at the bottom to avoid clutter. Part of the extension is a callback for processing jobs, saving the added functions in an object that's included in a hash. This works for most cases. The only issue I have is when setting an object method call as the callback. My guess is I'm not destroying that zval correctly, but I'm a little stumped to find a corresponding extension or php core code that holds onto a callback and destroys later. Apologies for the poor searching skills, I'm sure it exists, but couldn't find it through sleuthing around lxr.php.net. Anyways, my thinking is at the script's end, the WorkerWrapper (see gists below) instance is cleaned up, it cleans up the GearmanWorker member of said class, which then attempts to destroy the hash consisting of gearman_worker_cb objects (each object having a zval called 'zcall' referencing the callback). It destroys the zcall but is leaving some lingering refcount on the WorkerWrapper object which is part of it, which then fails to destroy the GearmanWorker member. Mumble mumble hand-wavy talk here a bit. I guess I'm lacking context on any special work involved in either storing or destroying a callback when you pass in as a callback something like: [$this, "method"] This differs from 5.x and below as the callback was stored using zend_object_store_get_object, so had to change how that could be referenced and deallocated. *Environment/testing notes:* I've been developing on Rasmus' vagrant image ( https://atlas.hashicorp.com/rasmus/boxes/php7dev) but it should be platform agnostic. PHP version is PHP 7.1.0-dev, but any stable PHP 7 release should reproduce. Running valgrind with the default suppressions file points at an object created and with some sigtraps and running through gdb it looks like it is indeed the GearmanWorker object created that is referenced in the memory leak. The memleak is present without doing the "work", as in processing the job. Creating a GearmanWorker instance and adding a function where the callback is an object method is sufficient. Passing in a string or an anonymous function referenced otherwise doesn't produce the memleak. Link to repo ("issue_19" is the latest branch I'm developing this fix, though it's not for prod use yet): https://github.com/wcgallego/pecl-gearman Gist of a client (to queue up jobs for worker to process): https://gist.github.com/wcgallego/ab88ae50a7a886ec79509b9c93fb2539 GIst of worker (where the memleak occurs, processing the above job): https://gist.github.com/wcgallego/2c331fa9154c98fbf0a29da1153a4696 and if you're looking to compile and run locally, you'll need gearman installed (https://launchpad.net/gearmand) with gearmand running (/usr/local/sbin/gearmand -d). I'm also a lurker in #php.pecl on Efnet to get in contact. Thanks for reading!

« previous php.pecl.dev (#13735) next »