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