title: Memory leak from SWIG-generated extension
body: <p>I'm having a memory leak problem wrapping a C++ library in PHP using SWIG. It seems to happen when callbacks from C++ containing complex types are sent to PHP while directors are enabled. Here is a standalone example to reproduce the leak:</p>
  
  <p>Client.hpp:</p>
  
  <pre><code>#ifndef CLIENT_HPP_
  #define CLIENT_HPP_
  
  #include &lt;vector&gt;
  #include "ProcedureCallback.hpp"
  
  class Client {
  public:
      void invoke(ProcedureCallback *callback) {
          callback-&gt;callback(std::vector&lt;int&gt;(0));
      }
  };
  
  #endif /* CLIENT_HPP_ */
  </code></pre>
  
  <p>ProcedureCallback.hpp:</p>
  
  <pre><code>#ifndef PROCEDURECALLBACK_HPP_
  #define PROCEDURECALLBACK_HPP_
  
  #include &lt;vector&gt;
  
  class ProcedureCallback {
  public:
      virtual void callback(std::vector&lt;int&gt;) = 0;
  };
  
  #endif /* PROCEDURECALLBACK_HPP_ */
  </code></pre>
  
  <p>So to use this, you create a <code>Client</code>, pass a subclassed <code>ProcedureCallback</code> to Client's <code>invoke</code> method, and Client then goes and calls the <code>callback</code> method of what you gave it, and passes an empty int vector.</p>
  
  <p>This is the SWIG interface file:</p>
  
  <pre><code>%module(directors="1") debugasync
  %feature("director");
  
  %{
  #include "Client.hpp"
  #include "ProcedureCallback.hpp"
  %}
  
  %include "Client.hpp"
  %include "ProcedureCallback.hpp"
  </code></pre>
  
  <p>Its output is very large, so I put it on pastebin instead: <a href="http://pastebin.com/ApQ7zGGb" rel="nofollow noreferrer">debugasync_wrap.cpp</a>. Of interest in this file is probably SwigDirector_ProcedureCallback::callback (line 1319):</p>
  
  <pre><code>void SwigDirector_ProcedureCallback::callback(std::vector&lt; int &gt; arg0) {
    zval *args[1];
    zval *result, funcname;
    MAKE_STD_ZVAL(result);
    ZVAL_STRING(&amp;funcname, (char *)"callback", 0);
    if (!swig_self) {
      SWIG_PHP_Error(E_ERROR, "this pointer is NULL");
    }
  
    zval obj0;
    args[0] = &amp;obj0;
    {
      SWIG_SetPointerZval(&amp;obj0, SWIG_as_voidptr(&amp;arg0), SWIGTYPE_p_std__vectorT_int_t, 2);
    }
    call_user_function(EG(function_table), (zval**)&amp;swig_self, &amp;funcname,
      result, 1, args TSRMLS_CC);
    FREE_ZVAL(result);
    return;
  fail:
    zend_error(SWIG_ErrorCode(),"%s",SWIG_ErrorMsg());
  }
  </code></pre>
  
  <p>This may also be of interest (line 827):</p>
  
  <pre><code>static void
  SWIG_ZTS_SetPointerZval(zval *z, void *ptr, swig_type_info *type, int newobject TSRMLS_DC) {
    swig_object_wrapper *value=NULL;
    /*
     * First test for Null pointers.  Return those as PHP native NULL
     */
    if (!ptr ) {
      ZVAL_NULL(z);
      return;
    }
    if (type-&gt;clientdata) {
      if (! (*(int *)(type-&gt;clientdata)))
        zend_error(E_ERROR, "Type: %s failed to register with zend",type-&gt;name);
      value=(swig_object_wrapper *)emalloc(sizeof(swig_object_wrapper));
      value-&gt;ptr=ptr;
      value-&gt;newobject=newobject;
      if (newobject &lt;= 1) {
        /* Just register the pointer as a resource. */
        ZEND_REGISTER_RESOURCE(z, value, *(int *)(type-&gt;clientdata));
      } else {
        /*
         * Wrap the resource in an object, the resource will be accessible
         * via the "_cPtr" member. This is currently only used by
         * directorin typemaps.
         */
        value-&gt;newobject = 0;
        zval *resource;
        MAKE_STD_ZVAL(resource);
        ZEND_REGISTER_RESOURCE(resource, value, *(int *)(type-&gt;clientdata));
        zend_class_entry **ce = NULL;
        zval *classname;
        MAKE_STD_ZVAL(classname);
        /* _p_Foo -&gt; Foo */
        ZVAL_STRING(classname, (char*)type-&gt;name+3, 1);
        /* class names are stored in lowercase */
        php_strtolower(Z_STRVAL_PP(&amp;classname), Z_STRLEN_PP(&amp;classname));
        if (zend_lookup_class(Z_STRVAL_P(classname), Z_STRLEN_P(classname), &amp;ce TSRMLS_CC) != SUCCESS) {
          /* class does not exist */
          object_init(z);
        } else {
          object_init_ex(z, *ce);
        }
        Z_SET_REFCOUNT_P(z, 1);
        Z_SET_ISREF_P(z);
        zend_hash_update(HASH_OF(z), (char*)"_cPtr", sizeof("_cPtr"), (void*)&amp;resource, sizeof(zval), NULL);
        FREE_ZVAL(classname);
      }
      return;
    }
    zend_error(E_ERROR, "Type: %s not registered with zend",type-&gt;name);
  }
  </code></pre>
  
  <p>And to demonstrate the memory leak in PHP (<a href="http://pastebin.com/NVpssSJS" rel="nofollow noreferrer">debugasync.php</a> is a set of proxy classes generated by SWIG which I have also uploaded to pastebin):</p>
  
  <pre><code>&lt;?php
  
  require('debugasync.php');
  
  class MyCallback extends ProcedureCallback {
      public function callback($intVector) {}
  }
  
  $client = new Client();
  $callback = new MyCallback();
  
  while (true) {
      print(number_format(memory_get_usage()) . "\n");
      for ($j = 0; $j &lt; 1000; $j++) {
          $client-&gt;invoke($callback);
      }
  }
  </code></pre>
  
  <p>This prints memory usage, does 1k invocations, and repeats. Running it shows a quickly-growing memory space:</p>
  
  <pre><code>$ php test.php 
  692,664
  1,605,488
  2,583,232
  3,634,776
  4,538,784
  5,737,760
  6,641,768
  7,545,816
  ^C
  </code></pre>
  
  <p>Also of note is that if the C++ callback passes a primitive (i.e. <code>int</code>) instead of a complex type (i.e. <code>std::vector&lt;int&gt;</code>), there is no memory leak.</p>
  
  <p>What is the cause of this memory leak?</p>
  
  <p>And more generally, what tools can I use to solve this? Valgrind's massif hasn't really been able to narrow down what's going on, even after building PHP with debugging symbols.</p>