Search code examples
phpcpointersphp-extension

Allocating memory in a php extension


I'm not good with pointers in C)

Having trouble with memory allocation in my PHP extension. I'm trying to call a function that returns an array of floats.

I wrote a small test script in C, and it works.

Basically it's,

float *fld;
...
ier = c_fstluk(fld, key, &ni, &nj, &nk);
...
// Read the array as a 2d field
for (i=0; i<ni; i++) {
   for (j=0; j<nj; j++) {
      // Values come transposed..
      printf("%15.6E", *(fld+(ni*j)+i));
      if (j<nj-1) printf(", ");
   }
   printf("\n");
 }

(full code)

Here I don't have to malloc or free anything. (at least I don't think so. In the fortran version of this code and function, I need to allocate() fld first.)

In my PHP extension however, the same code returns a seg fault.

When I emalloc and efree (or just malloc and free) fld before calling c_fstluk, it works, but I get tonnes of memory errors.

[Wed Jan  9 15:34:33 2013]  Script:  '/Users/matt/aurams/trunk/web/php/php-src/ext/fstd/fstd.php'
/Users/matt/aurams/trunk/web/php/php-src/Zend/zend_API.c(1295) :  Freeing 0x10D953060 (72 bytes), script=/Users/matt/aurams/trunk/web/php/php-src/ext/fstd/fstd.php
/Users/matt/aurams/trunk/web/php/php-src/Zend/zend_hash.c(412) : Actual location (location was relayed)
Last leak repeated 779 times
[Wed Jan  9 15:34:33 2013]  Script:  '/Users/matt/aurams/trunk/web/php/php-src/ext/fstd/fstd.php'
/Users/matt/aurams/trunk/web/php/php-src/Zend/zend_API.c(1292) :  Freeing 0x10D9531A0 (32 bytes), script=/Users/matt/aurams/trunk/web/php/php-src/ext/fstd/fstd.php
Last leak repeated 779 times
[Wed Jan  9 15:34:33 2013]  Script:  '/Users/matt/aurams/trunk/web/php/php-src/ext/fstd/fstd.php'
ext/fstd/fstd.c(414) :  Freeing 0x10D9538D0 (72 bytes), script=/Users/matt/aurams/trunk/web/php/php-src/ext/fstd/fstd.php
/Users/matt/aurams/trunk/web/php/php-src/Zend/zend_API.c(982) : Actual location (location was relayed)
Last leak repeated 29 times
[Wed Jan  9 15:34:33 2013]  Script:  '/Users/matt/aurams/trunk/web/php/php-src/ext/fstd/fstd.php'
/Users/matt/aurams/trunk/web/php/php-src/Zend/zend_hash.c(450) :  Freeing 0x10D954C08 (256 bytes), script=/Users/matt/aurams/trunk/web/php/php-src/ext/fstd/fstd.php
Last leak repeated 29 times
=== Total 1620 memory leaks detected ===

(Full code with emalloc commented out, line ~398)

I bet I'm missing something simple here..

So to summarize, in stand alone C program, stuff works without any allocation. In PHP extension, it works when I allocate space, but throws memory errors, when I don't allocate space, it seg faults.

Help? Thanks!


Solution

  • According to this document, c_fstluk(buffer, key, &ni, &nj, &nk) reads data into buffer, therefore the buffer (fld) has to be allocated.

    In the C version, if should normally not work having fld unallocated. But depending on your system etc... or some luck, the fld * pointer may point to a random space that is not written-protected (works but, of course, this is extremely dangerous).

    Therefore the extension has also to allocate the memory (either permanent or PHP request-life only depending on your ext) and then release it - in your case it is a temporary allocation, and has to be released before leaving the *php_function*.

    What I can see in the code you provided, while commented out

    • the emalloc does the allocation
    • then you force the module to return 0 since you want to test this part (and not the PHP vars creation etc...)
    • then you efree fld
    • thus fld is not released and creates memory leaks

    So it is probably a simple mistake, the efree should be moved just before the return of the function.

    fld = emalloc(ni*nj*sizeof(float*)); /* sizeof(float)  INSTEAD? */
    
    // Read the field pointed by the given key
    ier = c_fstluk(fld, key, &ni, &nj, &nk);
    
    /* ... */
    
    php_printf("\nDone.\n");
    
    efree(fld);
    
    RETURN_LONG(0);
    

    edit based on comments

    • (float *) allocation changed to (float)
    • ALLOC_INIT_ZVAL(arow) to be done for all iterations (source bottom)