2

I'm learning how to write PHP extensions and have come across a problem I haven't been able to find an answer to on the Interwebs. I'm trying to use C++ classes from my PHP extension, and although it seems to be working from the CLI, valgrind reports problems.

My globals are as follows:

ZEND_BEGIN_MODULE_GLOBALS(myext)
  MyClass *myClass;
ZEND_END_MODULE_GLOBALS(myext)

This class is instantiated as an extension global follows:

static void myext_init_globals(zend_myext_globals *myext_globals TSRMLS_DC)
{  
  myext_globals->myClass = (MyClass*)pemalloc(sizeof(MyClass), 0);
  MyClass *myClass = new (myext_globals->myClass) MyClass();
}

and it is freed using:

static void myext_destroy_globals(zend_myext_globals *myext_globals TSRMLS_DC)
{
  pefree(myext_globals->myClass, 0);
}

MyClass.h:

class MyClass
{
  private:
    std::string strSomeText;

  public:
    MyClass();
    ~MyClass();
};

MyClass.cpp:

MyClass::MyClass()
{
  strSomeText = "ABC"; // <-- this causes valgrind errors!
}

I have found that if I may strSomeText a static member variable, then valgrind reports no errors.

Also, if I try to allocate memory in the MyClass constructor and then delete or free it in the MyClass destructor, valgrind again reports leaks.

Ideally, I'd like to be able to grab "any ol' class" and just use it without having to make significant changes to it just to get it working as a PHP extension global.

UPDATE: My question is, how do you use a "generic" C++ class that uses things like std::string, or that allocates/de-allocated memory (either in the constructor/destructor, or a member method)? I have found that if I include php.h in MyClass and then allocate memory using emalloc/pemalloc and then de-allocate memory with efree and pefree, then things work and there are no memory leaks reported by valgrind. However, this is not ideal. There must be a way to use a "generic" C++ class (i.e. one that you don't have to refactor to be PHP extension friendly) as a PHP extension global (as in my example above).

  • What is your question? – Irrational Person Feb 17 '15 at 21:44
  • If your instance is freed manually,don't you have to call the destructor by hand as well? See http://stackoverflow.com/questions/8918791/how-to-properly-free-the-memory-allocated-by-placement-new – didierc Feb 17 '15 at 21:56
  • @IrrationalPerson - My question is: how do you use std::string in a PHP extension global without leaking memory? I have tried several things, nothing seems to work except for (in the example above) making strSomeText a static. Another (probably related) question is how to you allocate and deallocate memory in an object that is used as a PHP extension global. I understand is has something to do with the way PHP handles memory, I just know there must be a way to use a simple C++ class from within a PHP extension as a global. – Mike Dalton Feb 17 '15 at 21:56
  • @didierc - I do not believe this is necessary. I have tested this by including a printf in the destructor, and sure enough, the destructor is called. I have also tried explicitly calling delete in myext_destroy_globals, like: delete myext_globals->myClass, but I still get the valgrind memory leak error. My question is in the context of PHP extensions, where memory management is pretty complex and confusing (when using PHP extensions, it's emalloc, and pemalloc, and efree, and pefree etc...). – Mike Dalton Feb 17 '15 at 21:59

1 Answers1

0

Why would you use pemalloc/pefree? I don't see how destructor of myClass is ever going to be called? Try this, without ZEND_END_MODULE_GLOBALS:

std::unique_ptr<MyClass> myClass;


PHP_MINIT_FUNCTION(myext)
{  
  myClass = std::unique_ptr<MyClass> (new MyClass);
}

PHP_MSHUTDOWN_FUNCTION(myext)
{
  myClass.reset();
}

It is really tricky to use C++ in PHP module. PHP function calls could never return in case of error or HTTP request interruption. That breaks exceptions and destructor calling. So it's best to separate C++ code completely from PHP function calls. PHP_MINIT_FUNCTION and PHP_MSHUTDOWN_FUNCTION are guaranteed to be called on startup and exit of module. However, PHP as an Apache module could create one dummy version of the module and only after that the real ones. PHP_MINIT_FUNCTION and PHP_MSHUTDOWN_FUNCTION are called for dummy version also so you should avoid allocationg huge objects here and/or doing stuff with a lot of disk reads/writes, etc..

BJovke
  • 1,737
  • 15
  • 18