/* error.c * (c) 2002 Mikulas Patocka * This file is a part of the Links program, released under GPL. */ #include "links.h" #if DEBUGLEVEL >= 2 #define RED_ZONE 'R' #endif #if DEBUGLEVEL >= 3 #define FREE_FILL 0xfe #define REALLOC_FILL 0xfd #define ALLOC_FILL 0xfc #endif #if DEBUGLEVEL < 0 #define FREE_FILL 0xfe #endif #ifdef RED_ZONE #define RED_ZONE_INC 1 #else #define RED_ZONE_INC 0 #endif volatile char dummy_val; volatile char * volatile dummy_ptr = &dummy_val; volatile char * volatile x_ptr; void *do_not_optimize_here(void *p) { /* break ANSI aliasing */ x_ptr = p; *dummy_ptr = 0; return p; } #if defined(USE_WIN32_HEAP) #include /*#define NEW_HEAP*/ static HANDLE heap; #define heap_malloc(s) HeapAlloc(heap, 0, (s)) #define heap_calloc(s) HeapAlloc(heap, HEAP_ZERO_MEMORY, (s)) #define heap_free(p) HeapFree(heap, 0, (p)) #define heap_realloc(p, s) HeapReAlloc(heap, 0, (p), (s)) void init_heap(void) { #ifndef NEW_HEAP heap = GetProcessHeap(); #else if (!(heap = HeapCreate(0, 0, 0))) fatal_exit("HeapCreate failed: %x", (unsigned)GetLastError()); #endif { ULONG heap_frag = 2; if (!HeapSetInformation(heap, HeapCompatibilityInformation, &heap_frag, sizeof(heap_frag))) { /*fatal_exit("HeapSetInformation failed: %x", (unsigned)GetLastError());*/ } } } static void exit_heap(void) { #if DEBUGLEVEL >= 1 if (!HeapValidate(heap, 0, NULL)) internal_error("HeapValidate failed: %x", (unsigned)GetLastError()); #endif #ifdef NEW_HEAP if (!HeapDestroy(heap)) internal_error("HeapDestroy failed: %x", (unsigned)GetLastError()); #endif } #elif defined(OS2_ADVANCED_HEAP) || defined(VMS_ADVANCED_HEAP) #define SIZE_THRESHOLD 65536 #define REALLOC_PART 32 struct heap_entry { void *ptr; size_t len; }; static struct heap_entry *heap_entries; unsigned long mem_bigalloc; unsigned long blocks_bigalloc; unsigned long blocks_bigalloc_allocated; static my_uintptr_t heap_mask; static void *big_calloc(size_t size, int re_al) { void *ptr; my_uintptr_t mask; size_t padding; if (blocks_bigalloc == blocks_bigalloc_allocated) { struct heap_entry *he; if (blocks_bigalloc_allocated > MAXINT / 2 / sizeof(struct heap_entry) - 1) return NULL; he = realloc(heap_entries, (blocks_bigalloc_allocated + 1) * sizeof(struct heap_entry)); if (!he) return NULL; heap_entries = he; blocks_bigalloc_allocated++; } padding = page_size; if (re_al) { while (padding < size / REALLOC_PART && (size_t)(padding * 2) != 0) padding *= 2; } size = (size + padding - 1) & ~(padding - 1); if (!size) return NULL; ptr = virtual_alloc(size); if (!ptr) return NULL; heap_entries[blocks_bigalloc].ptr = ptr; heap_entries[blocks_bigalloc].len = size; blocks_bigalloc++; mem_bigalloc += size; mask = (my_uintptr_t)ptr; mask ^= (mask - 1); mask >>= 1; heap_mask &= mask; /*fprintf(stderr, "mask: %p -> %x -> %x\n", ptr, mask, heap_mask);*/ return ptr; } static void *heap_malloc(size_t size) { if (size >= SIZE_THRESHOLD) { void *ptr = big_calloc(size, 0); if (ptr) return ptr; } #ifdef OPENVMS_64BIT if (size > 0x77fffff0) return NULL; #endif return malloc(size); } static void *heap_calloc(size_t size) { if (size >= SIZE_THRESHOLD) { void *ptr = big_calloc(size, 0); if (ptr) return ptr; } #ifdef OPENVMS_64BIT if (size > 0x77fffff0) return NULL; #endif return calloc(1, size); } static void heap_free(void *ptr) { unsigned i; if (!((my_uintptr_t)ptr & heap_mask)) { for (i = 0; i < blocks_bigalloc; i++) { if (heap_entries[i].ptr == ptr) { virtual_free(ptr, heap_entries[i].len); mem_bigalloc -= heap_entries[i].len; blocks_bigalloc--; heap_entries[i] = heap_entries[blocks_bigalloc]; return; } } } free(ptr); } static void *heap_realloc(void *ptr, size_t size) { void *new_ptr; if (!((my_uintptr_t)ptr & heap_mask)) { unsigned i; for (i = 0; i < blocks_bigalloc; i++) { if (heap_entries[i].ptr == ptr) { if (size <= heap_entries[i].len) return ptr; new_ptr = big_calloc(size, 1); if (!new_ptr) new_ptr = heap_malloc(size); if (!new_ptr) return NULL; memcpy(new_ptr, ptr, heap_entries[i].len); heap_free(ptr); return new_ptr; } } } #ifdef OPENVMS_64BIT if (size > 0x77fffff0) return NULL; #endif if (size >= SIZE_THRESHOLD) { new_ptr = big_calloc(size, 1); if (new_ptr) { #ifdef HAVE__MSIZE size_t to_copy = _msize(ptr); if (to_copy > size) to_copy = size; memcpy(new_ptr, ptr, to_copy); #else ptr = realloc(ptr, size); if (!ptr) { heap_free(new_ptr); return NULL; } memcpy(new_ptr, ptr, size); #endif free(ptr); return new_ptr; } } return realloc(ptr, size); } void init_heap(void) { mem_bigalloc = 0; blocks_bigalloc = 0; blocks_bigalloc_allocated = 0; heap_entries = NULL; heap_mask = -1; } static void exit_heap(void) { free(heap_entries); heap_entries = NULL; } #else #define heap_malloc malloc #define heap_realloc realloc #define heap_free free #ifdef HAVE_CALLOC #define heap_calloc(x) calloc(1, (x)) #else static inline void *heap_calloc(size_t x) { void *p; if ((p = heap_malloc(x))) memset(p, 0, x); return p; } #endif void init_heap(void) { } #define exit_heap() do { } while (0) #endif #ifdef LEAK_DEBUG my_uintptr_t mem_amount = 0; my_uintptr_t mem_blocks = 0; #define ALLOC_MAGIC 0xa110c #define ALLOC_FREE_MAGIC 0xf4ee #define ALLOC_REALLOC_MAGIC 0x4ea110c #ifndef LEAK_DEBUG_LIST struct alloc_header { int magic; size_t size; }; #else struct alloc_header { list_entry_1st size_t size; unsigned char *file; unsigned char *comment; list_entry_last int line; int magic; }; static struct list_head memory_list = { &memory_list, &memory_list }; #endif #define L_D_S ((sizeof(struct alloc_header) + 15) & ~15) unsigned alloc_overhead = L_D_S + RED_ZONE_INC; #endif static inline void force_dump(void) { #if defined(DOS) fprintf(stderr, "\n"ANSI_SET_BOLD"Exiting"ANSI_CLEAR_BOLD"\n"); fflush(stdout); fflush(stderr); exit(RET_INTERNAL); #else int rs; fprintf(stderr, "\n"ANSI_SET_BOLD"Forcing core dump"ANSI_CLEAR_BOLD"\n"); fflush(stdout); fflush(stderr); EINTRLOOP(rs, raise(SIGSEGV)); #endif } void check_memory_leaks(void) { #if defined(LEAK_DEBUG) && !defined(NO_IE) if (mem_amount || mem_blocks) { char rb[OS_REPORT_ERROR_BUFFER]; char *rp = rb; fatal_tty_exit(); fprintf(stderr, "\n"ANSI_SET_BOLD"Memory leak by %lu bytes (%lu blocks)"ANSI_CLEAR_BOLD"\n", (unsigned long)mem_amount, (unsigned long)mem_blocks); snprintf(rp, sizeof rb - (rp - rb), "Memory leak by %lu bytes (%lu blocks)", (unsigned long)mem_amount, (unsigned long)mem_blocks); rp = strchr(rp, 0); #ifdef LEAK_DEBUG_LIST fprintf(stderr, "\nList of blocks: "); snprintf(rp, sizeof rb - (rp - rb), ":\r\n"); rp = strchr(rp, 0); { int r = 0; struct alloc_header *ah; struct list_head *lah; foreach(struct alloc_header, ah, lah, memory_list) { fprintf(stderr, "%s%p:%lu @ %s:%d", r ? ", ": "", (unsigned char *)ah + L_D_S, (unsigned long)ah->size, ah->file, ah->line); snprintf(rp, sizeof rb - (rp - rb), "%s%p:%lu @ %s:%d", r ? ", ": "", (unsigned char *)ah + L_D_S, (unsigned long)ah->size, ah->file, ah->line); rp = strchr(rp, 0); if (ah->comment) { fprintf(stderr, ":\"%s\"", ah->comment); snprintf(rb, sizeof rb - (rp - rb), ":\"%s\"", ah->comment); rp = strchr(rp, 0); } r = 1; } fprintf(stderr, "\n"); } #endif os_report_error("Memory leak", rb, NULL); force_dump(); } #endif exit_heap(); } static void er(int b, const char *m, va_list l) { #ifdef HAVE_VPRINTF vfprintf(stderr, cast_const_char m, l); #else fprintf(stderr, "%s", m); #endif if (b) fprintf(stderr, ANSI_BELL); fprintf(stderr, "\n"); fflush(stderr); portable_sleep(1000); } void error(const char *m, ...) { va_list l; va_start(l, m); os_report_error_va("Error", m, l); va_end(l); va_start(l, m); fprintf(stderr, "\n"); er(1, m, l); va_end(l); } void fatal_exit(const char *m, ...) { va_list l; va_start(l, m); os_report_error_va("Fatal error", m, l); va_end(l); fatal_tty_exit(); va_start(l, m); fprintf(stderr, "\n"); er(1, m, l); va_end(l); fflush(stdout); fflush(stderr); exit(RET_FATAL); } int errline; unsigned char *errfile; static unsigned char errbuf[4096]; void int_error(const char *m, ...) { #ifdef NO_IE return; #else va_list l; sprintf(cast_char errbuf, "Internal error at %s:%d\r\n%s", errfile, errline, m); va_start(l, m); os_report_error_va("Internal error", cast_const_char errbuf, l); va_end(l); fatal_tty_exit(); sprintf(cast_char errbuf, "\n"ANSI_SET_BOLD"INTERNAL ERROR"ANSI_CLEAR_BOLD" at %s:%d: %s", errfile, errline, m); va_start(l, m); er(1, cast_char errbuf, l); va_end(l); force_dump(); exit(RET_INTERNAL); #endif } void debug_msg(const char *m, ...) { va_list l; va_start(l, m); sprintf(cast_char errbuf, "\nDEBUG MESSAGE at %s:%d: %s", errfile, errline, m); er(0, cast_char errbuf, l); va_end(l); } #ifdef LEAK_DEBUG void *debug_mem_alloc(unsigned char *file, int line, size_t size, int mayfail) { void *p; #ifdef LEAK_DEBUG struct alloc_header *ah; #endif dos_poll_break(); debug_test_free(file, line); if (!size) return DUMMY; if (size > MAX_SIZE_T - L_D_S - RED_ZONE_INC) { if (mayfail) return NULL; overalloc_at(file, line); } size += L_D_S; retry: #ifdef LEAK_DEBUG mem_amount += size - L_D_S; mem_blocks++; #endif if (!(p = heap_malloc(size + RED_ZONE_INC))) { #ifdef LEAK_DEBUG mem_amount -= size - L_D_S; mem_blocks--; #endif if (out_of_memory_fl(0, !mayfail ? cast_uchar "malloc" : NULL, size + RED_ZONE_INC, file, line)) goto retry; return NULL; } #ifdef RED_ZONE *((unsigned char *)p + size + RED_ZONE_INC - 1) = RED_ZONE; #endif #ifdef LEAK_DEBUG ah = p; p = (unsigned char *)p + L_D_S; ah->size = size - L_D_S; ah->magic = ALLOC_MAGIC; #ifdef LEAK_DEBUG_LIST ah->file = file; ah->line = line; ah->comment = NULL; add_to_list(memory_list, ah); #endif #endif #ifdef ALLOC_FILL memset(p, ALLOC_FILL, size - L_D_S); #endif return p; } void *debug_mem_calloc(unsigned char *file, int line, size_t size, int mayfail) { void *p; #ifdef LEAK_DEBUG struct alloc_header *ah; #endif dos_poll_break(); debug_test_free(file, line); if (!size) return DUMMY; if (size > MAX_SIZE_T - L_D_S - RED_ZONE_INC) { if (mayfail) return NULL; overalloc_at(file, line); } size += L_D_S; retry: #ifdef LEAK_DEBUG mem_amount += size - L_D_S; mem_blocks++; #endif if (!(p = heap_calloc(size + RED_ZONE_INC))) { #ifdef LEAK_DEBUG mem_amount -= size - L_D_S; mem_blocks--; #endif if (out_of_memory_fl(0, !mayfail ? cast_uchar "calloc" : NULL, size + RED_ZONE_INC, file, line)) goto retry; return NULL; } #ifdef RED_ZONE *((unsigned char *)p + size + RED_ZONE_INC - 1) = RED_ZONE; #endif #ifdef LEAK_DEBUG ah = p; p = (unsigned char *)p + L_D_S; ah->size = size - L_D_S; ah->magic = ALLOC_MAGIC; #ifdef LEAK_DEBUG_LIST ah->file = file; ah->line = line; ah->comment = NULL; add_to_list(memory_list, ah); #endif #endif return p; } void debug_mem_free(unsigned char *file, int line, void *p) { #ifdef LEAK_DEBUG struct alloc_header *ah; #endif dos_poll_break(); if (p == DUMMY) return; if (!p) { errfile = file, errline = line, int_error("mem_free(NULL)"); return; } #ifdef LEAK_DEBUG p = (unsigned char *)p - L_D_S; ah = p; if (ah->magic != ALLOC_MAGIC) { errfile = file, errline = line, int_error("mem_free: magic doesn't match: %08x", ah->magic); return; } #ifdef FREE_FILL memset((unsigned char *)p + L_D_S, FREE_FILL, ah->size); #endif ah->magic = ALLOC_FREE_MAGIC; #ifdef LEAK_DEBUG_LIST del_from_list(ah); #endif mem_amount -= ah->size; mem_blocks--; #endif #ifdef RED_ZONE if (*((unsigned char *)p + L_D_S + ah->size + RED_ZONE_INC - 1) != RED_ZONE) { errfile = file, errline = line, int_error("mem_free: red zone damaged: %02x (block allocated at %s:%d%s%s)", *((unsigned char *)p + L_D_S + ah->size + RED_ZONE_INC - 1), #ifdef LEAK_DEBUG_LIST ah->file, ah->line, ah->comment ? ":" : "", ah->comment ? ah->comment : (unsigned char *)""); #else "-", 0, "-"); #endif return; } #endif #ifdef LEAK_DEBUG_LIST if (ah->comment) heap_free(ah->comment); #endif heap_free(p); } void *debug_mem_realloc(unsigned char *file, int line, void *p, size_t size, int mayfail) { #ifdef LEAK_DEBUG struct alloc_header *ah; #endif void *np; if (p == DUMMY) return debug_mem_alloc(file, line, size, mayfail); dos_poll_break(); debug_test_free(file, line); if (!p) { errfile = file, errline = line, int_error("mem_realloc(NULL, %lu)", (unsigned long)size); return NULL; } if (!size) { debug_mem_free(file, line, p); return DUMMY; } if (size > MAX_SIZE_T - L_D_S - RED_ZONE_INC) { if (mayfail) return NULL; overalloc_at(file, line); } #ifdef LEAK_DEBUG p = (unsigned char *)p - L_D_S; ah = p; if (ah->magic != ALLOC_MAGIC) { errfile = file, errline = line, int_error("mem_realloc: magic doesn't match: %08x", ah->magic); return NULL; } ah->magic = ALLOC_REALLOC_MAGIC; #ifdef REALLOC_FILL if (!mayfail && size < (size_t)ah->size) memset((unsigned char *)p + L_D_S + size, REALLOC_FILL, ah->size - size); #endif #endif #ifdef RED_ZONE if (*((unsigned char *)p + L_D_S + ah->size + RED_ZONE_INC - 1) != RED_ZONE) { errfile = file, errline = line, int_error("mem_realloc: red zone damaged: %02x (block allocated at %s:%d%s%s)", *((unsigned char *)p + L_D_S + ah->size + RED_ZONE_INC - 1), #ifdef LEAK_DEBUG_LIST ah->file, ah->line, ah->comment ? ":" : "", ah->comment ? ah->comment : (unsigned char *)""); #else "-", 0, "-"); #endif return (unsigned char *)p + L_D_S; } #endif retry: if (!(np = heap_realloc(p, size + L_D_S + RED_ZONE_INC))) { if (out_of_memory_fl(0, !mayfail ? cast_uchar "realloc" : NULL, size + L_D_S + RED_ZONE_INC, file, line)) goto retry; ah->magic = ALLOC_MAGIC; return NULL; } p = np; #ifdef RED_ZONE *((unsigned char *)p + size + L_D_S + RED_ZONE_INC - 1) = RED_ZONE; #endif #ifdef LEAK_DEBUG ah = p; /* OpenVMS Alpha C miscompiles this: mem_amount += size - ah->size; */ mem_amount += size; mem_amount -= ah->size; ah->size = size; ah->magic = ALLOC_MAGIC; #ifdef LEAK_DEBUG_LIST fix_list_after_realloc(ah); #endif #endif return (unsigned char *)p + L_D_S; } void set_mem_comment(void *p, unsigned char *c, int l) { #ifdef LEAK_DEBUG_LIST struct alloc_header *ah = (struct alloc_header *)((unsigned char *)p - L_D_S); if (ah->comment) heap_free(ah->comment); if ((ah->comment = heap_malloc(l + 1))) memcpy(ah->comment, c, l), ah->comment[l] = 0; #endif } #ifdef JS unsigned char *get_mem_comment(void *p) { #ifdef LEAK_DEBUG_LIST /* perm je prase: return ((struct alloc_header*)((unsigned char*)((void*)((unsigned char*)p-sizeof(int))) - L_D_S))->comment;*/ struct alloc_header *ah = (struct alloc_header *)((unsigned char *)p - L_D_S); if (!ah->comment) return cast_uchar ""; else return ah->comment; #else return cast_uchar ""; #endif } #endif #else void *mem_alloc_(size_t size, int mayfail) { void *p; dos_poll_break(); debug_test_free(NULL, 0); if (!size) return DUMMY; if (size > MAX_SIZE_T) { if (mayfail) return NULL; overalloc(); } retry: if (!(p = heap_malloc(size))) { if (out_of_memory_fl(0, !mayfail ? cast_uchar "malloc" : NULL, size, NULL, 0)) goto retry; return NULL; } return p; } void *mem_calloc_(size_t size, int mayfail) { void *p; dos_poll_break(); debug_test_free(NULL, 0); if (!size) return DUMMY; if (size > MAX_SIZE_T) { if (mayfail) return NULL; overalloc(); } retry: if (!(p = heap_calloc(size))) { if (out_of_memory_fl(0, !mayfail ? cast_uchar "calloc" : NULL, size, NULL, 0)) goto retry; return NULL; } return p; } void mem_free(void *p) { dos_poll_break(); if (p == DUMMY) return; if (!p) { internal_error("mem_free(NULL)"); return; } heap_free(p); } void *mem_realloc_(void *p, size_t size, int mayfail) { void *np; if (p == DUMMY) return mem_alloc_(size, mayfail); dos_poll_break(); debug_test_free(NULL, 0); if (!p) { internal_error("mem_realloc(NULL, %lu)", (unsigned long)size); return NULL; } if (!size) { mem_free(p); return DUMMY; } if (size > MAX_SIZE_T) { if (mayfail) return NULL; overalloc(); } retry: if (!(np = heap_realloc(p, size))) { if (out_of_memory_fl(0, !mayfail ? cast_uchar "realloc" : NULL, size, NULL, 0)) goto retry; return NULL; } return np; } #endif #if !(defined(LEAK_DEBUG) && defined(LEAK_DEBUG_LIST)) unsigned char *memacpy(const unsigned char *src, size_t len) { unsigned char *m; if (!(len + 1)) overalloc(); m = (unsigned char *)mem_alloc(len + 1); if (len) memcpy(m, src, len); m[len] = 0; return m; } unsigned char *stracpy(const unsigned char *src) { return src ? memacpy(src, src != DUMMY ? strlen(cast_const_char src) : 0) : NULL; } #else unsigned char *debug_memacpy(unsigned char *f, int l, const unsigned char *src, size_t len) { unsigned char *m; m = (unsigned char *)debug_mem_alloc(f, l, len + 1, 0); if (len) memcpy(m, src, len); m[len] = 0; return m; } unsigned char *debug_stracpy(unsigned char *f, int l, const unsigned char *src) { return src ? (unsigned char *)debug_memacpy(f, l, src, src != DUMMY ? strlen(cast_const_char src) : 0L) : NULL; } #endif #if defined(LEAK_DEBUG) && defined(LEAK_DEBUG_LIST) struct memory_entry { struct alloc_header *ah; my_uintptr_t cumulative_size; my_uintptr_t n_blocks; }; LIBC_CALLBACK static int memory_sort_file_line(const void *l1_, const void *l2_) { const struct memory_entry *l1 = (const struct memory_entry *)l1_; const struct memory_entry *l2 = (const struct memory_entry *)l2_; int c; c = strcmp(cast_const_char l1->ah->file, cast_const_char l2->ah->file); if (c) return c; if (l1->ah->line != l2->ah->line) return l1->ah->line - l2->ah->line; return 0; } LIBC_CALLBACK static int memory_sort_cumulative_size(const void *l1_, const void *l2_) { const struct memory_entry *l1 = (const struct memory_entry *)l1_; const struct memory_entry *l2 = (const struct memory_entry *)l2_; int c; if (l1->cumulative_size < l2->cumulative_size) return 1; if (l1->cumulative_size > l2->cumulative_size) return -1; if (l1->n_blocks < l2->n_blocks) return 1; if (l1->n_blocks > l2->n_blocks) return -1; c = strcmp(cast_const_char l1->ah->file, cast_const_char l2->ah->file); if (c) return c; if (l1->ah->line != l2->ah->line) return l1->ah->line - l2->ah->line; return 0; } static int num_digits(my_uintptr_t num) { int n = 0; do { n++; num /= 10; } while (num); return n; } unsigned char *get_top_memory(int mode, unsigned n) { struct memory_entry *entries; struct alloc_header *ah; struct list_head *lah; my_uintptr_t offs, offs2, mr, ln; unsigned char *r; int rl; int nd = 0; /* against warning */ entries = malloc(sizeof(struct memory_entry) * mem_blocks); if (!entries) return stracpy(cast_uchar "Not enough memory"); offs = 0; foreach(struct alloc_header, ah, lah, memory_list) { entries[offs].ah = ah; entries[offs].cumulative_size = ah->size; entries[offs].n_blocks = 1; offs++; } if (offs) qsort(entries, offs, sizeof(struct memory_entry), (int (*)(const void *, const void *))memory_sort_file_line); if (mode == GTM_MOST_ALLOCATED) { offs2 = 0; for (mr = 0; mr < offs; mr++) { entries[offs2] = entries[mr]; while (mr + 1 < offs && !strcmp(cast_const_char entries[mr].ah->file, cast_const_char entries[mr + 1].ah->file) && entries[mr].ah->line == entries[mr + 1].ah->line) { mr++; entries[offs2].cumulative_size += entries[mr].ah->size; entries[offs2].n_blocks++; } offs2++; } } else { offs2 = offs; } if (offs2) qsort(entries, offs2, sizeof(struct memory_entry), (int (*)(const void *, const void *))memory_sort_cumulative_size); r = init_str(); rl = 0; if (offs2) { nd = num_digits(entries[0].cumulative_size); } for (mr = 0, ln = 0; mr < offs2 && ln < n; mr++, ln++) { int l1 = rl; int d1; unsigned char *g, *f = entries[mr].ah->file; while ((g = cast_uchar strchr(cast_const_char f, '/'))) f = g + 1; add_to_str(&r, &rl, f); add_chr_to_str(&r, &rl, ':'); add_num_to_str(&r, &rl, entries[mr].ah->line); add_chr_to_str(&r, &rl, ' '); d1 = num_digits(entries[mr].cumulative_size); while (rl < l1 + 24 + (nd - d1)) add_chr_to_str(&r, &rl, ' '); add_num_to_str(&r, &rl, entries[mr].cumulative_size); if (mode == GTM_MOST_ALLOCATED) { add_to_str(&r, &rl, cast_uchar " / "); add_num_to_str(&r, &rl, entries[mr].n_blocks); } else if (mode == GTM_LARGEST_BLOCKS) { my_uintptr_t mq; for (mq = mr + 1; mq < offs2; mq++) { if (strcmp(cast_const_char entries[mr].ah->file, cast_const_char entries[mq].ah->file)) break; if (entries[mr].ah->line != entries[mq].ah->line) break; if (entries[mr].cumulative_size != entries[mq].cumulative_size) break; } if (mq > mr + 1) { add_to_str(&r, &rl, cast_uchar " x "); add_num_to_str(&r, &rl, mq - mr); } mr = mq - 1; } add_chr_to_str(&r, &rl, '\n'); } if (rl) { rl--; r[rl] = 0; } free(entries); return r; } #endif #ifdef OOPS struct prot { list_entry_1st sigjmp_buf buf; list_entry_last }; static struct list_head prot = { &prot, &prot }; static void fault(void *dummy) { struct prot *p; /*fprintf(stderr, "FAULT: %d !\n", (int)(unsigned long)dummy);*/ if (list_empty(prot)) { fatal_tty_exit(); exit(0); } p = list_struct(prot.next, struct prot); del_from_list(p); longjmp(p->buf, 1); } sigjmp_buf *new_stack_frame(void) { static int handled = 0; struct prot *new; if (!handled) { #ifdef SIGILL install_signal_handler(SIGILL, fault, (void *)SIGILL, 1); #endif #ifdef SIGABRT install_signal_handler(SIGABRT, fault, (void *)SIGABRT, 1); #endif #ifdef SIGFPE install_signal_handler(SIGFPE, fault, (void *)SIGFPE, 1); #endif #ifdef SIGSEGV install_signal_handler(SIGSEGV, fault, (void *)SIGSEGV, 1); #endif #ifdef SIGBUS install_signal_handler(SIGBUS, fault, (void *)SIGBUS, 1); #endif handled = 1; } if (!(new = mem_alloc(sizeof(struct prot)))) return NULL; add_to_list(prot, new); return &new->buf; } void xpr(void) { if (!list_empty(prot)) { struct prot *next = list_struct(prot.next, struct prot); del_from_list(next); mem_free(next); } } void nopr(void) { free_list(struct prot, prot); } #endif