Re: Fwd: zend_std_get_method : Address 0xffffffff is not stack'd, malloc'd or (recently) free'd
On Mon, 2014-03-31 at 14:09 +0200, Kajetan Dolinar wrote:
> Johaness, thank you for your attention ...
>
> >> The reason most probably lies within my code, but I don't have enough
> >> PHP Zend engine
> >> hacking experience to get to it by myself - it's my first PHP
> >> extension. Much obliged
> >> for intuitions from experienced for what could bring about such kind
> >> of fault.
> >
> > Reduce you ode till it works or share more details ..
> Yes, that may now be the only possible way to procede.
Well, you could also provide the PHP version number you are using ...
maybe an experienced developer might then point you in the right
direction. I simply have no clue which exact line
zend_object_handlers.c:847 is. So which structure is being read. Maybe
it also helps to use --db-attach=yes for valgrind to inspect the
state ... the only information the given valgrind output gives is that
something weird is happening while trying to call a method on an object.
Best, of course, would be to show code.
(Mind: It is legal to have an open source extension on top a closed
library if you don't want to share some library ... benefit then is that
it might be put in PECL, eventually you get windows builds and bugfixes
from PHP maintainers aside from improved visibility to potential
users ...)
> > Depends on what you want to use that memory for and what you optimize
> > for. i.e. if you want to stick data in PHP data structures it should be
> > emalloc'd with one block per item so PHP an free it.
>
> I would like to see from the address value itself whether that address
> was produced by e{m|re}alloc() so that I have to efree() it, or by
> pe{m|re}alloc() that I have to pefree(), or whether it falls within
> some other data segment such as static data which I should not
> free() in any way. For example:
>
> struct record {
> int id;
> char * name;
> . . .
> };
>
> . . .
>
> struct record * a = emalloc(sizeof(struct record));
> a->id = 1; a->name = estrdup("name1");
>
> struct record * b = emalloc(sizeof(struct record));
> b->id = 2; b->name = "name2";
>
> Clearly, there should be efree(a->name) as well as efree(a). However,
> in case of b, only efree(b) is appropriate whereas efree(b->name)
> would produce an error.
> How can I find out whether an address belongs to efree() or to
> pefree() or to none of that?
The typical pattern we use is either to add a flag to the structure,
something like
struct record {
int id;
zend_bool need_free; /* zend_bool is a uint */
char * name;
. . .
};
this obviously increases memory usage by sizeof(zend_bool) [+alignment]
for ach element and requires more care when creating/copying these
structures.
Some prefer doing this with
struct record {
int id;
void * to_free; /* equal to name if needs to be free'd, else NULL */
char * name;
. . .
};
The other approach is to enforce ownership inside the structure, thus
requiring more copies but it ensures that ownership is fully clear and
prevents double frees which might occur with your approach if a record
is copied but one doesn't copy the name. This trades some CPU and memory
for safety which in most cases is preferred.
johannes
Thread (8 messages)