Pristine Ack-5.5
[Ack-5.5.git] / lang / cem / libcc.ansi / stdlib / malloc / check.c
1 /* $Id: check.c,v 1.4 1994/06/24 11:55:12 ceriel Exp $ */
2 /*
3  * (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
4  * See the copyright notice in the ACK home directory, in the file "Copyright".
5  */
6 #include        <stdio.h>
7
8 #ifdef  CHECK                   /* otherwise this whole file is skipped */
9
10 /* ??? check these later */
11 private acquire_malout(void), check_ml_last(const char *s);
12 private dump_all_mallinks(void), dump_free_list(int i);
13 private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml);
14 private working_on(mallink *ml);
15 private size_type checksum(mallink *ml);
16 static FILE *malout;
17
18 private mallink *free_list_entry(int i);
19
20 #define for_free_list(i,p) \
21         for (p = free_list_entry(i); p; p = log_next_of(p))
22
23 #define for_all_mallinks(ml)    /* backwards! */ \
24         for (ml = ml_last; ml; \
25                 ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml))
26
27 /* Maldump */
28
29 static int pr_cnt = 0;
30
31 maldump(int n)  {
32         /*      Dump pertinent info in pseudo-readable format;
33                 abort afterwards if n != 0.
34         */
35         static int dumping = 0;
36         int i;
37         
38         if (dumping)
39                 return;
40         dumping++;
41         acquire_malout();
42         fprintf(malout,
43                 ">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<");
44         fprintf(malout, "    ml_last = %p\n", ml_last);
45         if (++pr_cnt == 100) pr_cnt = 0;
46         dump_all_mallinks();
47         fprintf(malout,
48                 ">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n");
49         if (++pr_cnt == 100) pr_cnt = 0;
50         for (i = 0; i < MAX_FLIST; i++)
51                 dump_free_list(i);
52         fprintf(malout,
53                 ">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n");
54         fclose(malout);
55         dumping--;
56         if (n)
57                 abort();
58 }
59
60 private
61 acquire_malout(void)    {
62         static char buf[BUFSIZ];
63         
64         if (!malout)    {
65                 malout = freopen("mal.out", "w", stderr);       
66                 setbuf(malout, buf);
67         }
68 }
69
70 private
71 dump_all_mallinks(void) {
72         mallink *ml;
73         
74         for_all_mallinks (ml)   {
75                 if (print_loop(ml))
76                         return;
77                 dump_mallink((char *)0, ml);
78         }
79 }
80
81 private
82 dump_free_list(int i)   {
83         mallink *ml = free_list_entry(i);
84         
85         if (!ml)
86                 return;
87         fprintf(malout, "%2d: ", i);
88         for_free_list(i, ml)    {
89                 if (print_loop(ml))
90                         return;
91                 fprintf(malout, "%p ", ml);
92         }
93         fprintf(malout, "<\n");
94 }
95
96 private int
97 print_loop(mallink *ml) {
98         if (print_of(ml) == pr_cnt)     {
99                 fprintf(malout, "... PRINT LOOP\n");
100                 return 1;
101         }
102         set_print(ml, pr_cnt);
103         return 0;
104 }
105
106 private
107 dump_mallink(const char *s, mallink *ml)        {
108         acquire_malout();
109         if (s)
110                 fprintf(malout, "%s: ", s);
111         fprintf(malout, "@: %p;", ml);
112         if (ml && checksum_of(ml) != checksum(ml))
113                 fprintf(malout, ">>>> CORRUPTED <<<<");
114         if (!ml)        {
115                 fprintf(malout, "\n");
116                 return;
117         }       
118         if (free_of(ml))        {
119                 fprintf(malout, " l_p: %p;", _log_prev_of(ml));
120                 fprintf(malout, " l_n: %p;", _log_next_of(ml));
121         }
122         fprintf(malout, " p_s: %p;", prev_size_of(ml));
123         fprintf(malout, " t_s: %p;", _this_size_of(ml));
124         fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml));
125         fprintf(malout, " fr: %d;", free_of(ml));
126         fprintf(malout, "\n");
127 }
128
129 /*      Check_mallinks() checks the total data structure as accessible
130         through free_list[] and ml_last.  All check_sums should be OK,
131         except those held in the small array off_colour.  This is a
132         trick to allow to continue checking even when a few mallinks
133         are temporarily out of order.
134         Check_mallinks() tests for a lot of internal consistency.
135 */
136
137 /* Some arbitrary constants */
138 #define IN_ML_LAST      93
139 #define IN_FREE_LIST    57              /* and in ml_last */
140 #define CLEAR           21
141
142 #define VRIJ            1
143 #define BEZET           2
144
145 private
146 check_mallinks(const char *s)   {
147         mallink *ml;
148         size_type size;
149         int i;
150         char stat;
151         
152         check_ml_last(s);
153         stat = BEZET;
154         for_all_mallinks(ml)    {
155                 if (checksum_of(ml) != checksum(ml))
156                         Error("mallink info at %p corrupted", s, ml);
157                 if (working_on(ml))     {
158                         stat = BEZET;
159                         continue;
160                 }
161                 if (    !last_mallink(ml) &&
162                         phys_prev_of(phys_next_of(ml)) != ml
163                 )
164                         Error("upward chain bad at %p", s, ml);
165                 if (    !first_mallink(ml) &&
166                         phys_next_of(phys_prev_of(ml)) != ml
167                 )
168                         Error("downward chain bad at %p", s, ml);
169                 if (free_of(ml))        {
170                         if (stat == VRIJ)
171                                 Error("free mallink at %p follows free mallink",
172                                                                 s, ml);
173                         stat = VRIJ;
174                 }
175                 else
176                         stat = BEZET;
177                 set_mark(ml, IN_ML_LAST);
178         }
179         
180         for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2)     {
181                 for_free_list(i, ml)    {
182                         if (working_on(ml))
183                                 continue;
184                         if (!free_of(ml))
185                                 Error("occupied mallink %p occurs in free_list", s, ml);
186                         switch (mark_of(ml))    {
187                         case IN_ML_LAST:
188                                 set_mark(ml, IN_FREE_LIST);
189                                 break;
190                         case IN_FREE_LIST:
191                                 Error("mallink %p occurs in 2 free_lists",
192                                                                 s, ml);
193                         default:
194                                 Error("unknown mallink %p in free_list",
195                                                                 s, ml);
196                         }
197                         if (size_of(ml) < size)
198                                 Error("size of mallink %p too small", s, ml);
199                         if (size_of(ml) >= 2*size)
200                                 Error("size of mallink %p too large", s, ml);
201                 }
202         }
203         for_all_mallinks (ml)   {
204                 if (working_on(ml))
205                         continue;
206                 if (free_of(ml) && mark_of(ml) != IN_FREE_LIST)
207                         Error("free mallink %p is in no free_list", s, ml);
208                 set_mark(ml, CLEAR);
209         }
210 }
211
212 private
213 check_ml_last(const char *s)    {
214         if (ml_last && _this_size_of(ml_last) == 0)
215                 Error("size of ml_last == 0, at %p", s, ml_last);
216 }
217
218 private size_type
219 checksum(mallink *ml)   {
220         size_type sum = 0;
221         
222         if (free_of(ml))        {
223                 sum += (size_type)_log_prev_of(ml);
224                 sum += (size_type)_log_next_of(ml);
225         }
226         sum += (size_type)prev_size_of(ml);
227         sum += (size_type)_this_size_of(ml);
228         return sum;
229 }
230
231 private
232 calc_checksum(mallink *ml)      {
233         set_checksum(ml, checksum(ml));
234 }
235
236 #define N_COLOUR        10
237 static mallink *off_colour[N_COLOUR];
238
239 private
240 started_working_on(mallink *ml) {
241         int i;
242         
243         for (i = 0; i < N_COLOUR; i++)
244                 if (off_colour[i] == MAL_NULL)  {
245                         off_colour[i] = ml;
246                         return;
247                 }
248         Error("out of off_colour array at %p", "started_working_on", ml);
249 }
250
251 private
252 stopped_working_on(mallink *ml) {
253         int i;
254         
255         for (i = 0; i < N_COLOUR; i++)
256                 if (off_colour[i] == ml)        {
257                         off_colour[i] = MAL_NULL;
258                         return;
259                 }
260         Error("stopped working on mallink %p", "stopped_working_on", ml);
261 }
262
263 private int
264 working_on(mallink *ml) {
265         int i;
266         
267         for (i = 0; i < N_COLOUR; i++)
268                 if (off_colour[i] == ml)
269                         return 1;
270         return 0;
271 }
272
273 private
274 check_work_empty(const char *s) {
275         int i;
276         int cnt = 0;
277         
278         for (i = 0; i < N_COLOUR; i++)
279                 if (off_colour[i] != MAL_NULL)
280                         cnt++;
281         if (cnt != 0)
282                 Error("off_colour not empty", s, MAL_NULL);
283 }
284
285 private int
286 Error(const char *fmt, const char *s, mallink *ml)      {
287         static int already_called = 0;
288
289         if (already_called++) return 0;
290         setbuf(stdout, (char *) 0);
291         printf("%s: ", s);
292         printf(fmt, (long)ml);
293         printf("\n");
294         acquire_malout();
295         fprintf(malout, "%s: ", s);
296         fprintf(malout, fmt, (long)ml);
297         fprintf(malout, "\n");
298         fflush(stdout);
299         maldump(1);
300         return 0;                       /* to satisfy lint */
301 }
302
303 #endif  /* CHECK */