Path: utzoo!utgpu!jarvis.csri.toronto.edu!mailrus!purdue!tut.cis.ohio-state.edu!bloom-beacon!hstbme.mit.edu!scs From: scs@hstbme.mit.edu (Steve Summit) Newsgroups: comp.lang.c Subject: Healthy skepticism towards documentation (was: effect of free) Message-ID: <14176@bloom-beacon.MIT.EDU> Date: 9 Sep 89 06:19:31 GMT References: <10817@riks.csl.sony.co.jp> <10990@smoke.BRL.MIL> Sender: daemon@bloom-beacon.MIT.EDU Reply-To: scs@adam.pika.mit.edu (Steve Summit) Lines: 88 In article <10817@riks.csl.sony.co.jp> diamond@riks. (Norman Diamond) writes: >Well, because a freed pointer is still valid in a call to realloc >(as long as there are no intervening *alloc calls), ... In article <10990@smoke.BRL.MIL> gwyn@brl.arpa (Doug Gwyn) writes: >Nope. That guarantee that you've read in some MALLOC(3) UNIX manual >page, was documenting an arguably useful feature of a particular >implementation. Important though it is (and some documentation is certainly better than no documentation at all) it's often a good idea to take documentation with a grain of salt. The first time I read The argument to free is a pointer to a block previously allocated by malloc; this space is made available for further allocation, but its contents are left undisturbed. on the malloc(3) page, I said to myself "what in the world are they guaranteeing something like that for?" It's a patently dangerous assertion, bound to disappear in the future. I've never depended on it. (I've written versions of free which deliberately scribble on the freed region to catch programs which accidentally depend on it.) There's another useless guarantee on many old malloc(3) pages: realloc also works if ptr points to a block freed since the last call of malloc, realloc or calloc; sequences of free, malloc and realloc can exploit the search strategy of malloc to do storage compaction. Someone noticed this quirk in an early malloc implementation; the practice of implementing storage compaction in this way became so widespread that later implementations have had to bend way over backwards to "support" the contorted usage. "But," you say, "storage compaction is important, especially on those old systems with limited memory. How else were we supposed to do it?" Easy. Write a routine called storagecompact(), containing whatever contorted code it takes to compact storage (if it's some fortuitous combination of calls to free, malloc, and realloc, so be it) and document _that_ as the way to do storage compaction, if you need to. Unfortunately, sometimes our friend the FM is actually F'ed. Other examples: Countless unsuspecting programmers have seen execl(name, arg0, arg1, ..., argn, 0) on the EXEC(2) man page and have decided that, arguments on comp.lang.c to the contrary notwithstanding, they can pass uncast null pointers with impunity and it should work. (The last argument should of course be (char *)0 .) The man page for dup and dup2 used to warn that dup2 was not portable to non-Unix systems, so people tend to simulate dup2 with even less portable usages of dup. For some reason Berkeley likes to deprecate its backwards- compatibility stubs. CREAT(2) says, in big bold letters, This interface is made obsolete by open(2). This sort of thing only encourages people to write code which won't compile anywhere else. (Of course, a three- argument open is common now, and Posix condones it, but Posix also supports creat, which is likely to hang around for quite a while because, obsolete or not, there's a lot of working code out there which uses it and which shouldn't need to be rewritten.) Similar cautions appear on the man pages for alarm, signal, and time. Of course, the next question is, if you can't trust the documentation, what can you trust? (It used to be the source code, but fewer people have access to it in these days of restrictive licensing.) There's no answer, of course; all you can do is keep your head on straight and don't be afraid to question something that doesn't look right. The BUGS line on learn(1) is appropriate: Occasionally lessons are incorrect. Such lessons may be skipped with the `skip' command, but it takes some sophistication to recognize the situation. Steve Summit