As part of the version object code I have been working on for 5.9.0, I have a replacement UNIVERSAL::VERSION that I use instead of the built-in version in earlier Perl's. The original U::V only handles PV's and NV/IV's, so I must replace it with one that understands version objects.

However, Adrien Enache noticed that I was leaking memory all over the place:

http://rt.perl.org/rt3/Ticket/Display.html?id=24624

I fixed everything I could find and released a new package to CPAN:

http://search.cpan.org/~jpeacock/version-0.34/

but I find that I am still leaking memory in the replacement UNIVERSAL::VERSION code, and I am stymied as to where.

If I comment out the two instances of upg_version() in the replacement U::V XS code, as well as the call to vcmp(), I see no leakage. However, just uncommenting a single call to upg_version() leaks immediately. I have been unable to see any leakage when just directly calling version->new() which in essence calls exactly the same code.

upg_version() creates a temporary string copy (Safefree()'d) of the incoming SV and then calls scan_version(), which in turn does this (where rv is the incoming SV which will ultimately be returned to the top level caller):

    SV* sv = newSVrv(rv, "version"); /* create an SV and upgrade the RV */
    (void)sv_upgrade(sv, SVt_PVAV); /* needs to be an AV type */

...no allocation of memory here...

            /* Append revision */
            av_push((AV *)sv, newSViv(rev));

After this code has run, the rv contains a reference to an AV, containing 2 or more IV elements. Everything has only 1 reference up the line.

The top level code (in UNIVERSAL_VERSION) has done this:

        SV *nsv = sv_newmortal();
        sv_setsv(nsv, sv);
        sv = nsv;
        if ( !sv_derived_from(sv, "version"))
            upg_version(sv);

and sv has, in fact, been mortalized (I've checked using sv_dump).

If the refcount on the mortalized sv (which now contains a reference to the AV) is 1, the AV also has a refcount of 1, and the refcount of each element of the AV is 1, then the next FREETMPS should delete everything, right?

This doesn't leak:

perl -Mversion -e 'eval "$v = version->new(1.0)" while 1'

but this does:

perl -Mversion -e 'eval "use module 1.0" while 1'

for even the most trivial module.

TIA

John

p.s. rather than attaching the source code here; the current version module can be retrieved from CPAN



Reply via email to