home *** CD-ROM | disk | FTP | other *** search
/ NetNews Usenet Archive 1992 #27 / NN_1992_27.iso / spool / comp / std / c / 3064 < prev    next >
Encoding:
Text File  |  1992-11-24  |  4.9 KB  |  138 lines

  1. Path: sparky!uunet!munnari.oz.au!goanna!ok
  2. From: ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe)
  3. Newsgroups: comp.std.c
  4. Subject: Re: fwrite+fread of pointer
  5. Message-ID: <16053@goanna.cs.rmit.oz.au>
  6. Date: 24 Nov 92 02:23:23 GMT
  7. References: <15935@goanna.cs.rmit.oz.au> <1992Nov13.184421.11065@taumet.com> <1992Nov18.104542.8499@thunder.mcrcim.mcgill.edu>
  8. Organization: Comp Sci, RMIT, Melbourne, Australia
  9. Lines: 127
  10.  
  11. In article <1992Nov18.104542.8499@thunder.mcrcim.mcgill.edu>, mouse@thunder.mcrcim.mcgill.edu (der Mouse) writes:
  12. : In article <15977@goanna.cs.rmit.oz.au>, ok@goanna.cs.rmit.oz.au (Richard A. O'Keefe) writes:
  13. : > In article <1992Nov13.184421.11065@taumet.com>, steve@taumet.com (Steve Clamage) writes:
  14. : >> "Data read in from a binary stream shall compare equal to the data
  15. : >> that were earlier written out to the stream, [...]."
  16. : > That is exactly the kind of answer I hoped for when I posted to
  17. : > comp.std.c.  Thank you.  There remains, alas, one fine point of
  18. : > detail.  What does it _mean_ to say "COMPARE EQUAL to the data ..."?
  19. : Let's see if I can bring this into sharper relief by eliminating the
  20. : file.
  21.  
  22. That actually changes the question in a significant way.
  23. Suppose you have a C interpreter (or compiler + library) which tries to
  24. detect memory leaks by doing garbage collection.  There are garbage
  25. collectors for C. One doesn't need to know for certain that something
  26. _is_ a pointer, only that it _might_ be.  If one finds that there is an
  27. unfreed allocated block to which are there no pointers, not even
  28. possible pointers, then that is certainly a leak.
  29.  
  30. Now consider
  31.     char *p = malloc(1);
  32.  
  33.     file = fopen("foo", "wb");
  34.     fwrite(&p, sizeof p, 1, file);
  35.     fclose(file);
  36.     p = NULL;
  37.     /* The garbage collector runs at this point */
  38.     file = fopen("foo", "rb");
  39.     fread(&p, sizeof p, 1, file);
  40.     fclose(file);
  41.  
  42. The significant thing about the file here is that the reference is now
  43. out in the file system, with no obvious link between the file and the
  44. process.
  45.  
  46. This example of a garbage collector being used to report memory leaks is
  47. not hypothetical.  See
  48.     Boehm, H., and M. Weiser,
  49.     "Garbage Collection in an Uncooperative Environment",
  50.     Software Practice & Experience, September 1988, pp. 807-820.
  51. The parts of that software which are available over the net do not include
  52. the storage leak detector.  The README file refers to a similar kit written
  53. by Doug McIlroy.
  54.  
  55. It now appears that if an object which might contain a pointer is written
  56. to a file, this leak detection method won't quite work; it can _warn_ that
  57. a block _may_ be lost, but it mayn't reclaim it.
  58.  
  59. As long as there _is_ a pointer _in the process_ for the new copy to
  60. "compare equal to", then there isn't a garbage collection problem (only
  61. a compacting problem).
  62.  
  63. : Since I think we now agree that a block of bytes written out and
  64. : read back must produce a block of bytes with identical bits in them....
  65.  
  66. Yes.  There is an interesting variant on der Mouse's example.
  67.  
  68. Consider:
  69.     char *p;
  70.     char buf[1 + sizeof p];
  71.  
  72.     p = malloc(1);
  73.     memcpy(buf, &p, sizeof p);
  74.     p = NULL;
  75.  
  76. Now there is a bit-for-bit copy of p in buf, but nowhere else.
  77. If buf happens to be suitably aligned, then a conservative garbage
  78. collector will notice that "possible pointer", and a following
  79.  
  80.     memcpy(&p, buf, sizeof p);
  81.     *p = 1;
  82.     free(p);
  83.  
  84. will work.  But now suppose we do
  85.  
  86.     p = malloc(1);
  87.     memcpy(buf+1, &p, sizeof p);
  88.     p = NULL;
  89.     /* The leak detector runs here */
  90.     memcpy(&p, buf+1, sizeof p);
  91.     *p = 1;
  92.     free(p);
  93.  
  94. A garbage collector cum leak detector is still possible, but must consider
  95. all possible alignments, not just the natural alignment for a pointer.
  96.  
  97. Now suppose we do
  98.  
  99.     p = malloc(1);
  100.     memcpy(buf, &p, sizeof p);
  101.     buf[0] ^= 0x34;
  102.     buf[sizeof p - 1] ^= 0x67;
  103.     p = NULL;
  104.     /* The leak detector runs here */
  105.     buf[sizeof p - 1] ^= 0x67;
  106.     buf[0] ^= 0x34;
  107.     memcpy(&p, buf, sizeof p);
  108.     *p = 1;
  109.     free(p);
  110.  
  111. This disguises the pointer so thoroughly that it is not reasonable
  112. to expect a leak detector to notice it.
  113.  
  114. C's pointer arithmetic is not a problem, because a legal pointer value
  115. that refers to (part of) a dynamically allocated object must point within
  116. or just past that block.
  117.  
  118. Casts aren't a problem, because there is no guaranteed way of getting a
  119. valid pointer _back_ from a cast:  if I do
  120.     char *p = malloc(1);
  121.     unsigned long v = (unsigned long)(p) ^ 0x12345678;
  122.     char *q = (char *)(w ^ 0x12345678);
  123. there is no guarantee that q == p, so a portable program cannot expect
  124. to hide pointers like this anyway.
  125.  
  126. But memcpy and fwrite+fread _are_ a problem, because they _do_ appear to
  127. give a guaranteed way whereby a pointer can be mangled in any reversible
  128. way and recovered.
  129.  
  130. For myself, I regard leak detectors as far more valuable than the ability
  131. to mangle pointers.  If it turns out that leak detectors can't be used with
  132. code that uses fwrite+fread on objects that contain pointers (anyone have
  133. any trouble with that phrasing) or with memcpy to unaligned blocks, then
  134. I'll just have to take that much more care not to use those constructs.
  135.  
  136.