1 #include "links.h"
2 
3 char dummy_val;
4 volatile char *dummy_ptr = &dummy_val;
5 
do_not_optimize_here(void * p)6 void do_not_optimize_here(void *p)
7 {
8 	*dummy_ptr = 0;
9 	/* break ANSI aliasing */
10 }
11 
12 #ifdef LEAK_DEBUG
13 my_uintptr_t mem_amount = 0;
14 #ifdef LEAK_DEBUG_LIST
15 struct list_head memory_list = { &memory_list, &memory_list };
16 #endif
17 #endif
18 
force_dump()19 static inline void force_dump()
20 {
21 	int rs;
22 	fprintf(stderr, "\n"ANSI_SET_BOLD"Forcing core dump"ANSI_CLEAR_BOLD"\n");
23 	fflush(stdout);
24 	fflush(stderr);
25 	fatal_tty_exit();
26 	EINTRLOOP(rs, raise(SIGSEGV));
27 }
28 
check_memory_leaks()29 void check_memory_leaks()
30 {
31 #ifdef LEAK_DEBUG
32 	if (mem_amount) {
33 		fprintf(stderr, "\n"ANSI_SET_BOLD"Memory leak by %lu bytes"ANSI_CLEAR_BOLD"\n", (unsigned long)mem_amount);
34 #ifdef LEAK_DEBUG_LIST
35 		fprintf(stderr, "\nList of blocks: ");
36 		{
37 			int r = 0;
38 			struct alloc_header *ah;
39 			foreach (ah, memory_list) {
40 				fprintf(stderr, "%s%p:%lu @ %s:%d", r ? ", ": "", (char *)ah + L_D_S, (unsigned long)ah->size, ah->file, ah->line), r = 1;
41 				if (ah->comment) fprintf(stderr, ":\"%s\"", ah->comment);
42 			}
43 			fprintf(stderr, "\n");
44 		}
45 #endif
46 		force_dump();
47 	}
48 #endif
49 }
50 
er(int b,char * m,va_list l)51 void er(int b, char *m, va_list l)
52 {
53 #ifdef HAVE_VPRINTF
54 	vfprintf(stderr, m, l);
55 #else
56 	fprintf(stderr, "%s", m);
57 #endif
58 	if (b) fprintf(stderr, ANSI_BELL);
59 	fprintf(stderr, "\n");
60 	fflush(stderr);
61 	sleep(1);
62 }
63 
error(char * m,...)64 void error(char *m, ...)
65 {
66 	va_list l;
67 	va_start(l, m);
68 	er(1, m, l);
69 	va_end(l);
70 }
71 
72 int errline;
73 unsigned char *errfile;
74 
75 unsigned char errbuf[4096];
76 
int_error(char * m,...)77 void int_error(char *m, ...)
78 {
79 	va_list l;
80 	va_start(l, m);
81 	sprintf(errbuf, ANSI_SET_BOLD"INTERNAL ERROR"ANSI_CLEAR_BOLD" at %s:%d: ", errfile, errline);
82 	strcat(errbuf, m);
83 	er(1, errbuf, l);
84 	force_dump();
85 	va_end(l);
86 }
87 
debug_msg(char * m,...)88 void debug_msg(char *m, ...)
89 {
90 	va_list l;
91 	va_start(l, m);
92 	sprintf(errbuf, "DEBUG MESSAGE at %s:%d: ", errfile, errline);
93 	strcat(errbuf, m);
94 	er(0, errbuf, l);
95 	va_end(l);
96 }
97 
98 #ifdef LEAK_DEBUG
99 
debug_mem_alloc(unsigned char * file,int line,size_t size)100 void *debug_mem_alloc(unsigned char *file, int line, size_t size)
101 {
102 	void *p;
103 #ifdef LEAK_DEBUG
104 	struct alloc_header *ah;
105 #endif
106 	if (!size) return DUMMY;
107 	if (size > MAXINT) overalloc();
108 #ifdef LEAK_DEBUG
109 	mem_amount += size;
110 	size += L_D_S;
111 #endif
112 	if (!(p = malloc(size))) {
113 		error("ERROR: out of memory (malloc returned NULL)");
114 		fatal_tty_exit();
115 		exit(RET_FATAL);
116 		return NULL;
117 	}
118 #ifdef LEAK_DEBUG
119 	ah = p;
120 	p = (char *)p + L_D_S;
121 	ah->size = size - L_D_S;
122 #ifdef LEAK_DEBUG_LIST
123 	ah->file = file;
124 	ah->line = line;
125 	ah->comment = NULL;
126 	add_to_list(memory_list, ah);
127 #endif
128 #endif
129 	return p;
130 }
131 
debug_mem_free(unsigned char * file,int line,void * p)132 void debug_mem_free(unsigned char *file, int line, void *p)
133 {
134 #ifdef LEAK_DEBUG
135 	struct alloc_header *ah;
136 #endif
137 	if (p == DUMMY) return;
138 	if (!p) {
139 		errfile = file, errline = line, int_error("mem_free(NULL)");
140 		return;
141 	}
142 #ifdef LEAK_DEBUG
143 	p = (char *)p - L_D_S;
144 	ah = p;
145 #ifdef LEAK_DEBUG_LIST
146 	del_from_list(ah);
147 	if (ah->comment) free(ah->comment);
148 #endif
149 	mem_amount -= ah->size;
150 #endif
151 	free(p);
152 }
153 
debug_mem_realloc(unsigned char * file,int line,void * p,size_t size)154 void *debug_mem_realloc(unsigned char *file, int line, void *p, size_t size)
155 {
156 #ifdef LEAK_DEBUG
157 	struct alloc_header *ah;
158 #endif
159 	if (p == DUMMY) return debug_mem_alloc(file, line, size);
160 	if (!p) {
161 		errfile = file, errline = line, int_error("mem_realloc(NULL, %lu)", (unsigned long)size);
162 		return NULL;
163 	}
164 	if (!size) {
165 		debug_mem_free(file, line, p);
166 		return DUMMY;
167 	}
168 	if (size > MAXINT) overalloc();
169 	if (!(p = realloc((char *)p - L_D_S, size + L_D_S))) {
170 		error("ERROR: out of memory (realloc returned NULL)");
171 		fatal_tty_exit();
172 		exit(RET_FATAL);
173 		return NULL;
174 	}
175 #ifdef LEAK_DEBUG
176 	ah = p;
177 	mem_amount += size - ah->size;
178 	ah->size = size;
179 #ifdef LEAK_DEBUG_LIST
180 	ah->prev->next = ah;
181 	ah->next->prev = ah;
182 #endif
183 #endif
184 	return (char *)p + L_D_S;
185 }
186 
set_mem_comment(void * p,unsigned char * c,int l)187 void set_mem_comment(void *p, unsigned char *c, int l)
188 {
189 #ifdef LEAK_DEBUG_LIST
190 	struct alloc_header *ah = (struct alloc_header *)((char *)p - L_D_S);
191 	if (ah->comment) free(ah->comment);
192 	if ((ah->comment = malloc(l + 1))) memcpy(ah->comment, c, l), ah->comment[l] = 0;
193 #endif
194 }
195 
196 #endif
197 
198