failtest: free up everything on exit.
[ccan] / ccan / failtest / failtest.c
index 092d2091b137bf3ea8b4e193931c1b239019c7ad..5d7a54f187f1f627ed6c950e9c7f06dfef82b1e1 100644 (file)
@@ -66,12 +66,19 @@ static unsigned int fd_orig_num = 0;
 
 static const char info_to_arg[] = "mceoprw";
 
+/* Dummy call used for failtest_undo wrappers. */
+static struct failtest_call unrecorded_call;
+
 static struct failtest_call *add_history_(enum failtest_call_type type,
                                          const char *file,
                                          unsigned int line,
                                          const void *elem,
                                          size_t elem_size)
 {
+       /* NULL file is how we suppress failure. */
+       if (!file)
+               return &unrecorded_call;
+
        history = realloc(history, (history_num + 1) * sizeof(*history));
        history[history_num].type = type;
        history[history_num].file = file;
@@ -172,6 +179,9 @@ static bool should_fail(struct failtest_call *call)
        char *out = NULL;
        size_t outlen = 0;
 
+       if (call == &unrecorded_call)
+               return false;
+
        if (failpath) {
                if (tolower(*failpath) != info_to_arg[call->type])
                        errx(1, "Failpath expected '%c' got '%c'\n",
@@ -341,6 +351,9 @@ int failtest_open(const char *pathname, int flags,
                va_end(ap);
        }
        p = add_history(FAILTEST_OPEN, file, line, &call);
+       /* Avoid memory leak! */
+       if (p == &unrecorded_call)
+               free((char *)call.pathname);
        if (should_fail(p)) {
                p->u.open.ret = -1;
                /* FIXME: Play with error codes? */
@@ -509,12 +522,33 @@ void failtest_init(int argc, char *argv[])
        }
 }
 
+/* Free up memory, so valgrind doesn't report leaks. */
+static void free_everything(void)
+{
+       unsigned int i;
+
+       for (i = 0; i < writes_num; i++) {
+               free(writes[i].data);
+               if (writes[i].hdr.offset != (off_t)-1)
+                       free(writes[i].olddata);
+       }
+       free(writes);
+       free(fd_orig);
+       for (i = 0; i < history_num; i++) {
+               if (history[i].type == FAILTEST_OPEN)
+                       free((char *)history[i].u.open.pathname);
+       }
+       free(history);
+}
+
 void failtest_exit(int status)
 {
        unsigned int i;
 
-       if (control_fd == -1)
+       if (control_fd == -1) {
+               free_everything();
                exit(status);
+       }
 
        if (failtest_exit_check) {
                if (!failtest_exit_check(history, history_num))
@@ -542,6 +576,7 @@ void failtest_exit(int status)
                        close(fd_orig[i].fd);
        }
 
+       free_everything();
        tell_parent(SUCCESS);
        exit(0);
 }