malloc/free mismatches in tradspool.c

Russ Allbery rra at stanford.edu
Sun Dec 19 04:40:29 UTC 2004


WATANABE Katsuhiro <katsu at watanabe.name> writes:

> [1] Referring free-ed memory contents.

> In tradspool_next(), you can find following code:

>    1059         priv = *(PRIV_TRADSPOOL *) article->private;
>    1060         free(article->private);
>    1061         free((void*)article);
>    1062         if (priv.artbase != NULL) {
>    1063             if (priv.mmapped)
>    1064                 munmap(priv.artbase, priv.artlen);
>    1065             else
>    1066                 free(priv.artbase);
>    1067         }

> But at line 1062, structure priv(= article->private) has been
> free-ed already (at 1060). So theoretically speaking, it can
> happen to have garbage memory contents when its member is
> referred.

priv is not article->private, but rather a *copy* of the struct that
article->private had pointed to.  C doesn't make this particularly
obvious, unfortunately.  (Otherwise, the rest of the routine would also be
problematic, since it uses priv.)

> [2] Free-ing not allocated memory.

> You can find many code ideoms in tradspool.c saying:
>         xrefs = CrackXref(...);
>         ...
>         for (i = 0 ; i < numxrefs; ++i) free(xrefs[i]);
>         free(xrefs);      
> But the array xrefs is allocated as just ONE memory
> chunk, not as an array of allocated memories in
> CrackXref(). So freeing xref's each elements does not
> make any sense.

No, xrefs is allocated as an array of pointers to elements, and each one
of those elements is initialized separately.  See CrackXref; there's an
xmalloc at the top and then an xstrndup inside the loop.

> Also, in case CrackXref() returns NULL or 0-element array, there are
> some differences in the way the code handles the irregular case. Like:

> (A) Just free xrefs.
>     581     if ((xrefs = CrackXref(xrefhdr, &numxrefs)) == NULL || numxrefs == 0) {
>     584         if (xrefs != NULL)
>     585             free(xrefs);

> (B) Do nothing.
>     959     if ((xrefs = CrackXref(xrefhdr, &numxrefs)) == NULL || numxrefs == 0) {
>     960         free(path);
>     961         tradspool_freearticle(article);
>     962         SMseterror(SMERR_UNDEFINED, NULL);
>     963         return false;

> (C) Free xrefs and free its elements also.
>    1136             if ((xrefs = CrackXref(xrefhdr, &numxrefs)) == NULL || numxr
> efs == 0) {
>    1137                 art->len = 0;

>    /* Then falling through the if clause and it is handled later ... */

>    1157             for (i = 0 ; i < numxrefs ; ++i) free(xrefs[i]);
>    1158             free(xrefs);

(B) here is a bug (a minor memory leak).  I've fixed this in CVS.  The
other two cases are equivalent, since numxrefs will be zero.

-- 
Russ Allbery (rra at stanford.edu)             <http://www.eyrie.org/~eagle/>



More information about the inn-bugs mailing list