ack/lang/cem/libcc.ansi/stdlib/malloc/check.c
1994-06-24 14:02:31 +00:00

304 lines
6.5 KiB
C

/* $Id$ */
/*
* (c) copyright 1987 by the Vrije Universiteit, Amsterdam, The Netherlands.
* See the copyright notice in the ACK home directory, in the file "Copyright".
*/
#include <stdio.h>
#ifdef CHECK /* otherwise this whole file is skipped */
/* ??? check these later */
private acquire_malout(void), check_ml_last(const char *s);
private dump_all_mallinks(void), dump_free_list(int i);
private dump_mallink(const char *s, mallink *ml), print_loop(mallink *ml);
private working_on(mallink *ml);
private size_type checksum(mallink *ml);
static FILE *malout;
private mallink *free_list_entry(int i);
#define for_free_list(i,p) \
for (p = free_list_entry(i); p; p = log_next_of(p))
#define for_all_mallinks(ml) /* backwards! */ \
for (ml = ml_last; ml; \
ml = first_mallink(ml) ? MAL_NULL : phys_prev_of(ml))
/* Maldump */
static int pr_cnt = 0;
maldump(int n) {
/* Dump pertinent info in pseudo-readable format;
abort afterwards if n != 0.
*/
static int dumping = 0;
int i;
if (dumping)
return;
dumping++;
acquire_malout();
fprintf(malout,
">>>>>>>>>>>>>>>> DUMP OF ALL MALLINKS <<<<<<<<<<<<<<<<");
fprintf(malout, " ml_last = %p\n", ml_last);
if (++pr_cnt == 100) pr_cnt = 0;
dump_all_mallinks();
fprintf(malout,
">>>>>>>>>>>>>>>> DUMP OF FREE_LISTS <<<<<<<<<<<<<<<<\n");
if (++pr_cnt == 100) pr_cnt = 0;
for (i = 0; i < MAX_FLIST; i++)
dump_free_list(i);
fprintf(malout,
">>>>>>>>>>>>>>>> END OF DUMP <<<<<<<<<<<<<<<<\n");
fclose(malout);
dumping--;
if (n)
abort();
}
private
acquire_malout(void) {
static char buf[BUFSIZ];
if (!malout) {
malout = freopen("mal.out", "w", stderr);
setbuf(malout, buf);
}
}
private
dump_all_mallinks(void) {
mallink *ml;
for_all_mallinks (ml) {
if (print_loop(ml))
return;
dump_mallink((char *)0, ml);
}
}
private
dump_free_list(int i) {
mallink *ml = free_list_entry(i);
if (!ml)
return;
fprintf(malout, "%2d: ", i);
for_free_list(i, ml) {
if (print_loop(ml))
return;
fprintf(malout, "%p ", ml);
}
fprintf(malout, "<\n");
}
private int
print_loop(mallink *ml) {
if (print_of(ml) == pr_cnt) {
fprintf(malout, "... PRINT LOOP\n");
return 1;
}
set_print(ml, pr_cnt);
return 0;
}
private
dump_mallink(const char *s, mallink *ml) {
acquire_malout();
if (s)
fprintf(malout, "%s: ", s);
fprintf(malout, "@: %p;", ml);
if (ml && checksum_of(ml) != checksum(ml))
fprintf(malout, ">>>> CORRUPTED <<<<");
if (!ml) {
fprintf(malout, "\n");
return;
}
if (free_of(ml)) {
fprintf(malout, " l_p: %p;", _log_prev_of(ml));
fprintf(malout, " l_n: %p;", _log_next_of(ml));
}
fprintf(malout, " p_s: %p;", prev_size_of(ml));
fprintf(malout, " t_s: %p;", _this_size_of(ml));
fprintf(malout, " sz: %lu;", (unsigned long) size_of(ml));
fprintf(malout, " fr: %d;", free_of(ml));
fprintf(malout, "\n");
}
/* Check_mallinks() checks the total data structure as accessible
through free_list[] and ml_last. All check_sums should be OK,
except those held in the small array off_colour. This is a
trick to allow to continue checking even when a few mallinks
are temporarily out of order.
Check_mallinks() tests for a lot of internal consistency.
*/
/* Some arbitrary constants */
#define IN_ML_LAST 93
#define IN_FREE_LIST 57 /* and in ml_last */
#define CLEAR 21
#define VRIJ 1
#define BEZET 2
private
check_mallinks(const char *s) {
mallink *ml;
size_type size;
int i;
char stat;
check_ml_last(s);
stat = BEZET;
for_all_mallinks(ml) {
if (checksum_of(ml) != checksum(ml))
Error("mallink info at %p corrupted", s, ml);
if (working_on(ml)) {
stat = BEZET;
continue;
}
if ( !last_mallink(ml) &&
phys_prev_of(phys_next_of(ml)) != ml
)
Error("upward chain bad at %p", s, ml);
if ( !first_mallink(ml) &&
phys_next_of(phys_prev_of(ml)) != ml
)
Error("downward chain bad at %p", s, ml);
if (free_of(ml)) {
if (stat == VRIJ)
Error("free mallink at %p follows free mallink",
s, ml);
stat = VRIJ;
}
else
stat = BEZET;
set_mark(ml, IN_ML_LAST);
}
for (i = 0, size = MIN_SIZE; i < MAX_FLIST; i++, size *= 2) {
for_free_list(i, ml) {
if (working_on(ml))
continue;
if (!free_of(ml))
Error("occupied mallink %p occurs in free_list", s, ml);
switch (mark_of(ml)) {
case IN_ML_LAST:
set_mark(ml, IN_FREE_LIST);
break;
case IN_FREE_LIST:
Error("mallink %p occurs in 2 free_lists",
s, ml);
default:
Error("unknown mallink %p in free_list",
s, ml);
}
if (size_of(ml) < size)
Error("size of mallink %p too small", s, ml);
if (size_of(ml) >= 2*size)
Error("size of mallink %p too large", s, ml);
}
}
for_all_mallinks (ml) {
if (working_on(ml))
continue;
if (free_of(ml) && mark_of(ml) != IN_FREE_LIST)
Error("free mallink %p is in no free_list", s, ml);
set_mark(ml, CLEAR);
}
}
private
check_ml_last(const char *s) {
if (ml_last && _this_size_of(ml_last) == 0)
Error("size of ml_last == 0, at %p", s, ml_last);
}
private size_type
checksum(mallink *ml) {
size_type sum = 0;
if (free_of(ml)) {
sum += (size_type)_log_prev_of(ml);
sum += (size_type)_log_next_of(ml);
}
sum += (size_type)prev_size_of(ml);
sum += (size_type)_this_size_of(ml);
return sum;
}
private
calc_checksum(mallink *ml) {
set_checksum(ml, checksum(ml));
}
#define N_COLOUR 10
static mallink *off_colour[N_COLOUR];
private
started_working_on(mallink *ml) {
int i;
for (i = 0; i < N_COLOUR; i++)
if (off_colour[i] == MAL_NULL) {
off_colour[i] = ml;
return;
}
Error("out of off_colour array at %p", "started_working_on", ml);
}
private
stopped_working_on(mallink *ml) {
int i;
for (i = 0; i < N_COLOUR; i++)
if (off_colour[i] == ml) {
off_colour[i] = MAL_NULL;
return;
}
Error("stopped working on mallink %p", "stopped_working_on", ml);
}
private int
working_on(mallink *ml) {
int i;
for (i = 0; i < N_COLOUR; i++)
if (off_colour[i] == ml)
return 1;
return 0;
}
private
check_work_empty(const char *s) {
int i;
int cnt = 0;
for (i = 0; i < N_COLOUR; i++)
if (off_colour[i] != MAL_NULL)
cnt++;
if (cnt != 0)
Error("off_colour not empty", s, MAL_NULL);
}
private int
Error(const char *fmt, const char *s, mallink *ml) {
static int already_called = 0;
if (already_called++) return 0;
setbuf(stdout, (char *) 0);
printf("%s: ", s);
printf(fmt, (long)ml);
printf("\n");
acquire_malout();
fprintf(malout, "%s: ", s);
fprintf(malout, fmt, (long)ml);
fprintf(malout, "\n");
fflush(stdout);
maldump(1);
return 0; /* to satisfy lint */
}
#endif /* CHECK */