save
[protos/libecoli.git] / lib / main.c
1 /*
2  * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions are met:
6  *
7  *     * Redistributions of source code must retain the above copyright
8  *       notice, this list of conditions and the following disclaimer.
9  *     * Redistributions in binary form must reproduce the above copyright
10  *       notice, this list of conditions and the following disclaimer in the
11  *       documentation and/or other materials provided with the distribution.
12  *     * Neither the name of the University of California, Berkeley nor the
13  *       names of its contributors may be used to endorse or promote products
14  *       derived from this software without specific prior written permission.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ANY
17  * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19  * DISCLAIMED. IN NO EVENT SHALL THE REGENTS AND CONTRIBUTORS BE LIABLE FOR ANY
20  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26  */
27
28 #include <stdlib.h>
29 #include <stdio.h>
30 #include <assert.h>
31 #include <getopt.h>
32
33 #include <ecoli_test.h>
34 #include <ecoli_malloc.h>
35
36 static const char ec_short_options[] =
37         "h" /* help */
38         ;
39
40 enum {
41         /* long options */
42         EC_OPT_LONG_MIN_NUM = 256,
43 #define EC_OPT_HELP "help"
44         EC_OPT_HELP_NUM,
45 };
46
47 static const struct option ec_long_options[] = {
48         {EC_OPT_HELP, 1, NULL, EC_OPT_HELP_NUM},
49         {NULL, 0, NULL, 0}
50 };
51
52 static void usage(const char *prgname)
53 {
54         printf("%s [options]\n"
55                    "  --"EC_OPT_HELP": show this help\n"
56                 , prgname);
57 }
58
59 static void parse_args(int argc, char **argv)
60 {
61         int opt;
62
63         while ((opt = getopt_long(argc, argv, ec_short_options,
64                                 ec_long_options, NULL)) != EOF) {
65
66                 switch (opt) {
67                 case 'h': /* help */
68                 case EC_OPT_HELP_NUM:
69                         usage(argv[0]);
70                         exit(0);
71
72                 default:
73                         usage(argv[0]);
74                         exit(1);
75                 }
76         }
77 }
78
79 TAILQ_HEAD(debug_alloc_hdr_list, debug_alloc_hdr);
80 static struct debug_alloc_hdr_list debug_alloc_hdr_list =
81         TAILQ_HEAD_INITIALIZER(debug_alloc_hdr_list);
82
83 struct debug_alloc_hdr {
84         TAILQ_ENTRY(debug_alloc_hdr) next;
85         const char *file;
86         unsigned int line;
87         size_t size;
88         unsigned int cookie;
89 };
90
91 struct debug_alloc_ftr {
92         unsigned int cookie;
93 } __attribute__((packed));
94
95 static void *debug_malloc(size_t size, const char *file, unsigned int line)
96 {
97         struct debug_alloc_hdr *hdr;
98         struct debug_alloc_ftr *ftr;
99         size_t new_size = size + sizeof(*hdr) + sizeof(*ftr);
100         void *ret;
101
102         hdr = malloc(new_size);
103         if (hdr == NULL) {
104                 ret = NULL;
105         } else {
106                 hdr->file = file;
107                 hdr->line = line;
108                 hdr->size = size;
109                 hdr->cookie = 0x12345678;
110                 TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next);
111                 ret = hdr + 1;
112                 ftr = (struct debug_alloc_ftr *)(
113                         (char *)hdr + size + sizeof(*hdr));
114                 ftr->cookie = 0x12345678;
115         }
116
117         ec_log(EC_LOG_INFO, "%s:%d: info: malloc(%zd) -> %p\n",
118                 file, line, size, ret);
119
120         return ret;
121 }
122
123 static void debug_free(void *ptr, const char *file, unsigned int line)
124 {
125         struct debug_alloc_hdr *hdr, *h;
126         struct debug_alloc_ftr *ftr;
127
128         (void)file;
129         (void)line;
130
131         ec_log(EC_LOG_INFO, "%s:%d: info: free(%p)\n", file, line, ptr);
132
133         if (ptr == NULL)
134                 return;
135
136         hdr = (ptr - sizeof(*hdr));
137         if (hdr->cookie != 0x12345678) {
138                 ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad start cookie\n",
139                         file, line, ptr);
140                 abort();
141         }
142
143         ftr = (ptr + hdr->size);
144         if (ftr->cookie != 0x12345678) {
145                 ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad end cookie\n",
146                         file, line, ptr);
147                 abort();
148         }
149
150         TAILQ_FOREACH(h, &debug_alloc_hdr_list, next) {
151                 if (h == hdr)
152                         break;
153         }
154
155         if (h == NULL) {
156                 ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad ptr\n",
157                         file, line, ptr);
158                 abort();
159         }
160
161         TAILQ_REMOVE(&debug_alloc_hdr_list, hdr, next);
162         free(hdr);
163 }
164
165 void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line)
166 {
167         struct debug_alloc_hdr *hdr, *h;
168         struct debug_alloc_ftr *ftr;
169         size_t new_size = size + sizeof(*hdr) + sizeof(unsigned int);
170         void *ret;
171
172         if (ptr != NULL) {
173                 hdr =  (ptr - sizeof(*hdr));
174                 if (hdr->cookie != 0x12345678) {
175                         ec_log(EC_LOG_ERR,
176                                 "%s:%d: error: realloc(%p): bad start cookie\n",
177                                 file, line, ptr);
178                         abort();
179                 }
180
181                 ftr = (ptr + hdr->size);
182                 if (ftr->cookie != 0x12345678) {
183                         ec_log(EC_LOG_ERR,
184                                 "%s:%d: error: realloc(%p): bad end cookie\n",
185                                 file, line, ptr);
186                         abort();
187                 }
188
189                 TAILQ_FOREACH(h, &debug_alloc_hdr_list, next) {
190                         if (h == hdr)
191                                 break;
192                 }
193
194                 if (h == NULL) {
195                         ec_log(EC_LOG_ERR, "%s:%d: error: realloc(%p): bad ptr\n",
196                                 file, line, ptr);
197                         abort();
198                 }
199
200                 TAILQ_REMOVE(&debug_alloc_hdr_list, h, next);
201                 hdr = realloc(hdr, new_size);
202                 if (hdr == NULL) {
203                         TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, h, next);
204                         ret = NULL;
205                 } else {
206                         ret = hdr + 1;
207                 }
208         } else {
209                 hdr = realloc(NULL, new_size);
210                 if (hdr == NULL)
211                         ret = NULL;
212                 else
213                         ret = hdr + 1;
214         }
215
216         if (hdr != NULL) {
217                 hdr->file = file;
218                 hdr->line = line;
219                 hdr->size = size;
220                 hdr->cookie = 0x12345678;
221                 TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next);
222                 ftr = (struct debug_alloc_ftr *)(
223                         (char *)hdr + size + sizeof(*hdr));
224                 ftr->cookie = 0x12345678;
225         }
226
227         ec_log(EC_LOG_INFO, "%s:%d: info: realloc(%p, %zd) -> %p\n",
228                 file, line, ptr, size, ret);
229
230         return ret;
231 }
232
233 void debug_alloc_dump(void)
234 {
235         struct debug_alloc_hdr *hdr;
236
237         TAILQ_FOREACH(hdr, &debug_alloc_hdr_list, next) {
238                 ec_log(EC_LOG_ERR, "%s:%d: error: memory leak size=%zd ptr=%p\n",
239                         hdr->file, hdr->line, hdr->size, hdr + 1);
240         }
241 }
242
243 int main(int argc, char **argv)
244 {
245         int ret;
246
247         parse_args(argc, argv);
248
249         TAILQ_INIT(&debug_alloc_hdr_list);
250         /* register a new malloc to track memleaks */
251         if (ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) {
252                 ec_log(EC_LOG_ERR, "cannot register new malloc\n");
253                 return -1;
254         }
255
256         ret = ec_test_all();
257
258         ec_malloc_unregister();
259         debug_alloc_dump();
260
261         if (ret != 0)
262                 printf("tests failed\n");
263
264         return 0;
265 }