home *** CD-ROM | disk | FTP | other *** search
/ ftp.uni-stuttgart.de/pub/systems/acorn/ / Acorn.tar / Acorn / riscos / problems / malloc < prev    next >
Text File  |  1992-04-13  |  5KB  |  147 lines

  1. qArticle 312 of comp.sys.acorn:
  2. Xref: rusmv1 comp.sys.acorn:312 eunet.micro.acorn:133
  3. Path: rusmv1!ira.uka.de!fauern!unido!mcsun!ukc!acorn!john
  4. From: john@acorn.co.uk (John Bowler)
  5. Newsgroups: comp.sys.acorn,eunet.micro.acorn
  6. Subject: Re: Any got a malloc function with debugging facilities?
  7. Summary: No, but this may help
  8. Keywords: malloc
  9. Message-ID: <4938@acorn.co.uk>
  10. Date: 1 Feb 91 20:14:56 GMT
  11. References: <3430@gos.ukc.ac.uk>
  12. Organization: Acorn Computers Ltd, Cambridge, UK
  13. Lines: 130
  14.  
  15. In article <3430@gos.ukc.ac.uk> nms@ukc.ac.uk (N.M.Smith) writes:
  16. >Has anyone got a malloc functions that has debugging features?  The problem
  17. >I have is that there is a large piece of C code that does _a lot_ of mallocing
  18. >of complex structures.  The memory usage is so high that it doesn't run a 440.
  19. >I know that a least some of the structures are freed after use but I need to 
  20. >know if there is any other memory that the structure pointed to that is not
  21. >freed.
  22.  
  23. Debugging malloc's probably won't help very much unless RISC OS specific.
  24. You need to know what store is in use *and* who allocated it (although
  25. brave users of debuggers have been seen attempting to deduce who allocated
  26. heap space by exmaining the contents :-)).  Finding out what store is
  27. in use and who allocated it is frequently useful anyway, even if the
  28. programs storage use isn't apparently excessive.  The RISC OS malloc
  29. makes it impossible to even find out what store is in use - you can work
  30. out which regions of memory are in use, but not (necessarily) where individual
  31. allocations within those regions start or end.
  32.  
  33. The approach I have used in the past (on RISC iX, but the problems are
  34. similar) involves code along the following lines (it is obviously RISCOS
  35. specific...)  No guarantees this code is correct, I write it each time
  36. I need it.
  37.  
  38. #include <stdlib.h>
  39.  
  40. #define RND(x) (((x)+sizeof (int)-1)/sizeof (int))
  41. #define CHECK1 0x12345678    /* Or anything you like */
  42. #define CHECK2 0x9abcdef0    /* Or anything you like */
  43.  
  44. static int *list;
  45.  
  46. void *MALLOC(size_t size) {
  47.     int *ptr = malloc(size+20);
  48.  
  49.     if (ptr == NULL) return ptr;
  50.     ptr[0] = CHECK1;
  51.     ptr[1] = caller_pc();    /* Identifies caller of MALLOC */
  52.     ptr[2] = size;
  53.     ptr[3] = (int)list;    /* SIC */
  54.     list = ptr;
  55.     ptr[1+RND(size)] = CHECK2;
  56.     return ptr+4;
  57. }
  58.  
  59. /* Make the following as complicated as you like */
  60. static void check(int *pi) {
  61.     if (pi[0] != CHECK1 || pi[1+RND(pi[2])] != CHECK2)
  62.         /* Store overwritten */;
  63. }
  64.  
  65. static int *remove(int *pi) {
  66.     int **lp = &list;
  67.     while (*lp) {
  68.         /* Checks every allocated item on each free() */
  69.         check(*lp);
  70.         if (*lp == pi) {
  71.             *lp = (int *)pi[3];
  72.             /* pi now removed from list */
  73.             return pi;
  74.         }
  75.         /* Point to next list pointer */
  76.         lp = (int **)&((*lp)[3]);
  77.     }
  78.     /* *lp == NULL, pi not in list */
  79.     /* ERROR - invalid pointer to free */
  80.     return NULL;
  81. }
  82.     
  83. void FREE(void *ptr) {
  84.     int *p = remove(ptr);
  85.  
  86.     if (p) free(p-4);
  87. }
  88.  
  89. The implementation of REALLOC should be fairly obvious.   This
  90. code is proof against bogus pointers being passed to free()
  91. (in particular, it is proof against multiple freeing).  Also each
  92. storage unit contains the result of the caller_pc() function;
  93. if this function returns the pc of the caller of malloc (and similarly
  94. for realloc) it is possible to use these and the list static variable
  95. to find the pc of each call to malloc which is not matched by a
  96. free.
  97.  
  98. To ensure the code gets called you need to convert every malloc
  99. call to a MALLOC call, and so on.  Do this using #define's in the
  100. code or command line options:-
  101.  
  102.     -Dmalloc=MALLOC -Dfree=FREE -Drealloc=REALLOC
  103.  
  104. The only problem is that this does *not* get the malloc calls in
  105. RISCOS_Lib - I can see no easy way of catching these, as RISCOS_Lib
  106. has already been compiled.  (You can do it in RISC iX 1.2 by renaming
  107. the symbols and using a non-shared libc library.)
  108.  
  109. To write caller_pc you need to resort to objasm and the APCS 
  110. documentation.  The simplest implementation is:-
  111.  
  112. |_caller_pc|    LDR    A1, [FP, #-4]
  113.         MOVS    PC, LR
  114.  
  115. Then the result is the address of the instruction immediately
  116. after the (original) call to MALLOC (etc).  Actually the following
  117. bit of C will do the same (possibly only at the revision and release
  118. of the compiler which I have on RISC iX).
  119.  
  120. static int dummy(void) { return 22; }
  121.  
  122. void *caller_pc(void) {
  123.     int    a = dummy();
  124.     int    *fp = (int *)((&a)[1]);    /* Revolting */
  125.     return (void *)fp[-1];
  126. }
  127.  
  128. Sometimes on RISC OS you will get an address in MALLOC itself,
  129. because of stack overflow, caller_pc() could be made to work round this,
  130. but it hardly seems worth it.
  131.  
  132. The only problem with this approach is that the addition of 20 bytes
  133. to each allocation distorts heap use enormously, however this should
  134. not cause problems when trying to track down failures to free things.
  135. There are a lot of potential approaches to detecting free failures.
  136. One is to simply find out which malloc caller allocated the greatest
  137. number of outstanding storage units.  Another is to note a position
  138. in the list using a debugging function (make a call to MALLOC and
  139. read the value of the ``list'' static) then, some time later, examine
  140. the list down to this point in another function - that will avoid
  141. the large numbers of (effectively) static allocations which occur
  142. during program startup.
  143.  
  144. John Bowler (jbowler@acorn.co.uk)
  145.  
  146.  
  147.