Line data Source code
1 : /*
2 : SSSD
3 :
4 : Common utilities for check-based tests using talloc.
5 :
6 : Authors:
7 : Martin Nagy <mnagy@redhat.com>
8 :
9 : Copyright (C) Red Hat, Inc 2009
10 :
11 : This program is free software; you can redistribute it and/or modify
12 : it under the terms of the GNU General Public License as published by
13 : the Free Software Foundation; either version 3 of the License, or
14 : (at your option) any later version.
15 :
16 : This program is distributed in the hope that it will be useful,
17 : but WITHOUT ANY WARRANTY; without even the implied warranty of
18 : MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19 : GNU General Public License for more details.
20 :
21 : You should have received a copy of the GNU General Public License
22 : along with this program. If not, see <http://www.gnu.org/licenses/>.
23 : */
24 :
25 : #include <stdio.h>
26 : #include "tests/common.h"
27 : #include "util/util.h"
28 : #include "util/dlinklist.h"
29 :
30 : TALLOC_CTX *global_talloc_context = NULL;
31 : char leak_err_msg[256];
32 :
33 : struct size_snapshot {
34 : struct size_snapshot *prev;
35 : struct size_snapshot *next;
36 :
37 : TALLOC_CTX *ctx;
38 : size_t bytes_allocated;
39 : };
40 :
41 : static struct size_snapshot *snapshot_stack;
42 :
43 : #define _set_leak_err_msg(fmt, ...) do { \
44 : snprintf(leak_err_msg, sizeof(leak_err_msg), \
45 : fmt, ##__VA_ARGS__); \
46 : } while(0);
47 :
48 0 : const char *check_leaks_err_msg(void)
49 : {
50 0 : return leak_err_msg;
51 : }
52 :
53 : bool
54 792 : _check_leaks(TALLOC_CTX *ctx, size_t bytes, const char *location)
55 : {
56 : size_t bytes_allocated;
57 :
58 792 : if (ctx == NULL) {
59 0 : return false;
60 : }
61 :
62 792 : bytes_allocated = talloc_total_size(ctx);
63 792 : if (bytes_allocated != bytes) {
64 1 : fprintf(stderr, "Leak report for %s:\n", location);
65 1 : talloc_report_full(ctx, stderr);
66 1 : _set_leak_err_msg("%s: memory leaks detected, %zd bytes still allocated",
67 : location, bytes_allocated - bytes);
68 1 : return false;
69 : }
70 :
71 791 : return true;
72 : }
73 :
74 : void
75 532 : check_leaks_push(TALLOC_CTX *ctx)
76 : {
77 : struct size_snapshot *snapshot;
78 :
79 532 : snapshot = talloc(NULL, struct size_snapshot);
80 532 : snapshot->ctx = ctx;
81 532 : snapshot->bytes_allocated = talloc_total_size(ctx);
82 532 : DLIST_ADD(snapshot_stack, snapshot);
83 532 : }
84 :
85 : bool
86 532 : _check_leaks_pop(TALLOC_CTX *ctx, const char *location)
87 : {
88 : struct size_snapshot *snapshot;
89 : TALLOC_CTX *old_ctx;
90 : size_t bytes_allocated;
91 :
92 532 : if (ctx == NULL) {
93 7 : return false;
94 : }
95 :
96 525 : if (snapshot_stack == NULL) {
97 0 : _set_leak_err_msg("%s: trying to pop an empty stack", location);
98 0 : return false;
99 : }
100 :
101 525 : snapshot = snapshot_stack;
102 525 : DLIST_REMOVE(snapshot_stack, snapshot);
103 :
104 525 : old_ctx = snapshot->ctx;
105 525 : bytes_allocated = snapshot->bytes_allocated;
106 :
107 525 : if (old_ctx != ctx) {
108 0 : _set_leak_err_msg("Bad push/pop order");
109 0 : return false;
110 : }
111 :
112 525 : talloc_zfree(snapshot);
113 525 : return _check_leaks(old_ctx, bytes_allocated, location);
114 : }
115 :
116 : bool
117 267 : leak_check_setup(void)
118 : {
119 267 : talloc_enable_null_tracking();
120 267 : global_talloc_context = talloc_new(NULL);
121 267 : if (global_talloc_context == NULL) {
122 0 : _set_leak_err_msg("talloc_new failed");
123 0 : return false;
124 : }
125 :
126 267 : check_leaks_push(global_talloc_context);
127 267 : return true;
128 : }
129 :
130 : bool
131 267 : leak_check_teardown(void)
132 : {
133 : bool res;
134 267 : check_leaks_pop(global_talloc_context);
135 267 : if (snapshot_stack != NULL) {
136 0 : _set_leak_err_msg("Exiting with a non-empty stack");
137 0 : return false;
138 : }
139 267 : res = check_leaks(global_talloc_context, 0);
140 267 : talloc_disable_null_tracking();
141 267 : talloc_free(global_talloc_context);
142 267 : return res;
143 : }
|