effect of free()
Charles Marslett
chasm at attctc.Dallas.TX.US
Sat Sep 9 12:51:11 AEST 1989
In article <19474 at mimsy.UUCP>, chris at mimsy.UUCP (Chris Torek) writes:
:: In article <2054 at munnari.oz.au> ok at cs.mu.oz.au (Richard O'Keefe) writes:
:: >It is perfectly true that loading a (formerly valid, now invalid) address
:: >into an address register might cause a trap. BUT there is no reason why
:: >a compiler has to translate "if (ptr == 0)" by loading ptr into an
:: >address register.
::
:: True enough. (Indeed, all `if (ptr0 <compare> ptr1)' operations could
:: be done without loading either pointer into an address register, on all
:: machines of which I have ever heard.) The problem is that the proposed
:: ANSI standard does not force compiler writers to do this.
It appears from an earlier posting that only certain very baroque architectures
could have this idiosyncracy (sp?). . . Because one special invalid pointer
has to be acceptable in all expressions except dereferencing (NULL, that is),
the processor would have to have built-in NULL pointer detection, as well
as the normal protection mechanisms. This is likely to have serious performance
penalties.
:: Since everyone seems to want an example of a system on which
::
:: ptr = malloc(size);
:: if (ptr != NULL) {
:: free(ptr);
:: if (ptr == NULL) ... never gets here ...
:: else ... never gets here either! ...
:: }
::
:: might be the case, perhaps we should think for a moment and construct
:: one (an example, not a system).
::
:: First, we need a relatively common architecture that traps when
:: loading an invalid address into an address register. How about the
:: 80286? It has `address' registers called CS, DS, ES, and SS, and
:: these trap when a bad segment is loaded and the processor is in
:: protected mode.
Except for the magic segment numbers 0x0000-0x0007, which can be loaded
into any segment register (maybe not CS?) and will not generate a trap.
:: Now we need a way to have an invalid address happen. So:
::
:: void *malloc(size_t size) {
:: segment_t seg = __syscall(_GET_SEGMENT);
:: if (seg == _NO_SEGMENT) return NULL;
:: return _SEG_TO_ADDR(seg);
:: }
::
:: void free(void *p) {
:: if (__syscall(_RELEASE_SEGMENT(_ADDR_TO_SEG(p))))
:: __runtime_abort("bad argument to free(): %lx",
:: (long)p);
:: }
::
:: Now all we need is a sufficiently stupid compiler. That is not
:: hard to write. We construct one that, for every pointer construct,
:: compiles to something like this:
::
:: ; do something with a pointer
:: xor ax,ax ; check for segment 0 => nil
:: or ax,[bp + stackoff + 2]
:: jz Lptr_was_nil ; it was nil, so do not load it
:: mov es,[bp + stackoff + 2] ; not nil, load it.
:: mov di,[bp + stackoff]
:: ; what are we doing? `ptr == nil'? Oh, we already did that.
:: jump Lptr_was_not_nil
:: Lptr_was_nil:
:: ; code...
::
:: (Please ignore any assembly syntax errors above; I have never used an
:: 80x86 for any value of x, except perhaps as embedded controllers, where
:: I have never had to program them. My only experience with 8086
:: assembly comes from looking over the operating systems class
:: assignments back when they were using IBM PCs. [Now they are using
:: PS-halves, er, PS/2s, for that class.] But I will say that I think the
:: 8085 was nicer, and the Z80 had more reasonable opcodes. [Both of
:: these were also descendents of the 4004.])
::
:: The only question the proposed ANSI standard can answer about the above
:: is whether this is a conforming implementation, as far as the specification
:: goes. That is, is it conforming even though it does in fact generate
:: a trap on
::
:: ptr = malloc(size); free(ptr); if (ptr == (char *)0)
::
:: even though we are not looking at *ptr?
::
:: The only *answer* the proposed standard gives is silence. That is,
:: it does not say that this implementation is non-conformant (i.e., wrong).
:: Thus we must conclude that it does conform, and that the trap is
:: legal according to the proposed standard.
And it shows just how baroque the microcode in the 80286 really must be!
(Since all this code is really part of loading a segment register when
running in protected mode!)
:: Standards (proposed or otherwise) generally do not say anything about
:: implementation quality, but I would have to agree that the implementation
:: described above is horrible. It is not, however, outright illegal.
:: --
:: In-Real-Life: Chris Torek, Univ of MD Comp Sci Dept (+1 301 454 7163)
:: Domain: chris at mimsy.umd.edu Path: uunet!mimsy!chris
I would have to say it is rather unlikely as well (or I would have said so
before I ran into Intel CPUs ;^).
Why don't we just say is it lousy looking code that does this sort of thing --
so don't do it (even though it will work 99999 times out of 10000, or whatever
the fraction really is.
BTW, I find the example code to be a good argument that referencing invalid
pointers ought to be legal (since without that ability, a "safe" malloc like
the one above, with reasonable error messages, becomes non-portable).
===========================================================================
Charles Marslett
STB Systems, Inc. <== Apply all standard disclaimers
Wordmark Systems <== No disclaimers required -- that's just me
chasm at attctc.dallas.tx.us
More information about the Comp.lang.c
mailing list