[Python-Dev] pymalloc killer

Tim Peters tim.one@comcast.net
Sat, 30 Mar 2002 15:01:05 -0500


[Guido]
> How about if the PyMem_Free guy saved the address of the vector before
> using it, and checked that it was still the same afterwards, *and* if
> the PyMem_Malloc guy didn't use realloc to resize the vector but
> copied it to a newly malloc'ed vector, stored the new vector's
> address, and then freed the old vector?

It already does the latter (it deliberately avoided realloc all along -- an
even stronger reason to avoid realloc is that if the realloc failed, we'd
lose the original vector of base addresses entirely and so would have to
kill the program; as is, it can continue gracefully).

> (I guess this is the same as what Martin suggested.

He suggested letting the old vector *leak*, which is the same idea God gave
me in my sleep <wink>.

> His point that the global holding the vector address should be declared
> volatile is a good one.)

I see no point to that.  If someone can explain *why* it's a good idea,
sure, but I don't see it.

Let's simplify things enormously:  p is a pointer to "something".  Thread A
contains

    *p

Thread B contains

    free(p)

Without a lock, they're screwed period.  Thread A has to first read up p,
and then dereference it, and all the volatiles in the universe can't stop
free(p) from happening *between* thread A's two machine instructions.  It
doesn't matter either if Thread B does

    oldp = p;
    p = newp;
    free(oldp);

because thread A can still pick up "p" before the "p = newp" line.  Indeed,
the current obmalloc code is exactly like that, and it's not safe (although
I bet if I left it alone, the hole wouldn't be hit in my lifetime!).

Neither would it do any real good for Thread A to do

    if (p == p && p == p && p == p && wink)
        ... *p ...

any number of times, volatile or not.  Nothing short of a pair of critical
sections is a genuine cure for a genuine race.

Letting the old vector leak is fine; in most programs, it won't lose more
than about 1KB of memory total.  Note that there are obscure reasons for why
it's OK to reference a stale vector in the cases where a race is possible
(this is already explained in obmalloc.c comments, so I won't repeat that
here).