2 * Copyright (c) 2016, Olivier MATZ <zer0@droids-corp.org>
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are met:
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.
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.
33 #include <ecoli_log.h>
34 #include <ecoli_malloc.h>
35 #include <ecoli_test.h>
38 static struct ec_test_list test_list = TAILQ_HEAD_INITIALIZER(test_list);
40 /* register a driver */
41 void ec_test_register(struct ec_test *test)
43 TAILQ_INSERT_TAIL(&test_list, test, next);
46 int ec_test_check_tk_parse(const struct ec_tk *tk, const char *input,
49 struct ec_parsed_tk *p;
53 p = ec_tk_parse(tk, input);
54 s = ec_parsed_tk_to_string(p);
55 if (s == NULL && expected == NULL)
57 else if (s != NULL && expected != NULL &&
61 if (expected == NULL && ret != 0)
62 ec_log(EC_LOG_ERR, "tk should not match but matches <%s>\n", s);
63 if (expected != NULL && ret != 0)
64 ec_log(EC_LOG_ERR, "tk should match <%s> but matches <%s>\n",
72 int ec_test_check_tk_complete(const struct ec_tk *tk, const char *input,
75 struct ec_completed_tk *c;
79 assert(expected != NULL);
81 c = ec_tk_complete(tk, input);
82 s = ec_completed_tk_smallest_start(c);
83 if (!strcmp(s, expected))
88 "should complete with <%s> but completes with <%s>\n",
91 ec_completed_tk_free(c);
96 int ec_test_check_tk_complete_list(const struct ec_tk *tk,
97 const char *input, ...)
99 struct ec_completed_tk *c = NULL;
100 struct ec_completed_tk_elt *elt;
103 unsigned int count = 0;
108 c = ec_tk_complete(tk, input);
112 for (s = va_arg(ap, const char *);
114 s = va_arg(ap, const char *)) {
119 TAILQ_FOREACH(elt, &c->elts, next) {
120 if (strcmp(elt->add, s) == 0)
126 "completion <%s> not in list\n", s);
131 if (count != ec_completed_tk_count(c)) {
133 "nb_completion (%d) does not match (%d)\n",
134 count, ec_completed_tk_count(c));
135 ec_completed_tk_dump(stdout, c);
142 ec_completed_tk_free(c);
147 TAILQ_HEAD(debug_alloc_hdr_list, debug_alloc_hdr);
148 static struct debug_alloc_hdr_list debug_alloc_hdr_list =
149 TAILQ_HEAD_INITIALIZER(debug_alloc_hdr_list);
151 struct debug_alloc_hdr {
152 TAILQ_ENTRY(debug_alloc_hdr) next;
159 struct debug_alloc_ftr {
161 } __attribute__((packed));
163 static void *debug_malloc(size_t size, const char *file, unsigned int line)
165 struct debug_alloc_hdr *hdr;
166 struct debug_alloc_ftr *ftr;
167 size_t new_size = size + sizeof(*hdr) + sizeof(*ftr);
170 hdr = malloc(new_size);
177 hdr->cookie = 0x12345678;
178 TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next);
180 ftr = (struct debug_alloc_ftr *)(
181 (char *)hdr + size + sizeof(*hdr));
182 ftr->cookie = 0x12345678;
185 ec_log(EC_LOG_INFO, "%s:%d: info: malloc(%zd) -> %p\n",
186 file, line, size, ret);
191 static void debug_free(void *ptr, const char *file, unsigned int line)
193 struct debug_alloc_hdr *hdr, *h;
194 struct debug_alloc_ftr *ftr;
199 ec_log(EC_LOG_INFO, "%s:%d: info: free(%p)\n", file, line, ptr);
204 hdr = (ptr - sizeof(*hdr));
205 if (hdr->cookie != 0x12345678) {
206 ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad start cookie\n",
211 ftr = (ptr + hdr->size);
212 if (ftr->cookie != 0x12345678) {
213 ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad end cookie\n",
218 TAILQ_FOREACH(h, &debug_alloc_hdr_list, next) {
224 ec_log(EC_LOG_ERR, "%s:%d: error: free(%p): bad ptr\n",
229 TAILQ_REMOVE(&debug_alloc_hdr_list, hdr, next);
233 void *debug_realloc(void *ptr, size_t size, const char *file, unsigned int line)
235 struct debug_alloc_hdr *hdr, *h;
236 struct debug_alloc_ftr *ftr;
237 size_t new_size = size + sizeof(*hdr) + sizeof(unsigned int);
241 hdr = (ptr - sizeof(*hdr));
242 if (hdr->cookie != 0x12345678) {
244 "%s:%d: error: realloc(%p): bad start cookie\n",
249 ftr = (ptr + hdr->size);
250 if (ftr->cookie != 0x12345678) {
252 "%s:%d: error: realloc(%p): bad end cookie\n",
257 TAILQ_FOREACH(h, &debug_alloc_hdr_list, next) {
263 ec_log(EC_LOG_ERR, "%s:%d: error: realloc(%p): bad ptr\n",
268 TAILQ_REMOVE(&debug_alloc_hdr_list, h, next);
269 hdr = realloc(hdr, new_size);
271 TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, h, next);
277 hdr = realloc(NULL, new_size);
288 hdr->cookie = 0x12345678;
289 TAILQ_INSERT_TAIL(&debug_alloc_hdr_list, hdr, next);
290 ftr = (struct debug_alloc_ftr *)(
291 (char *)hdr + size + sizeof(*hdr));
292 ftr->cookie = 0x12345678;
295 ec_log(EC_LOG_INFO, "%s:%d: info: realloc(%p, %zd) -> %p\n",
296 file, line, ptr, size, ret);
301 void debug_alloc_dump(void)
303 struct debug_alloc_hdr *hdr;
305 TAILQ_FOREACH(hdr, &debug_alloc_hdr_list, next) {
306 ec_log(EC_LOG_ERR, "%s:%d: error: memory leak size=%zd ptr=%p\n",
307 hdr->file, hdr->line, hdr->size, hdr + 1);
311 int ec_test_all(void)
313 struct ec_test *test;
316 TAILQ_INIT(&debug_alloc_hdr_list);
318 /* register a new malloc to trac memleaks */
319 if (ec_malloc_register(debug_malloc, debug_free, debug_realloc) < 0) {
320 ec_log(EC_LOG_ERR, "cannot register new malloc\n");
324 TAILQ_FOREACH(test, &test_list, next) {
325 if (test->test() == 0) {
326 ec_log(EC_LOG_INFO, "== test %-20s success\n",
329 ec_log(EC_LOG_INFO, "== test %-20s failed\n",
335 ec_malloc_unregister();