3 Copyright (C) 2005 Silicon Graphics, Inc. All Rights Reserved.
5 This program is free software; you can redistribute it and/or modify it
6 under the terms of version 2.1 of the GNU Lesser General Public License
7 as published by the Free Software Foundation.
9 This program is distributed in the hope that it would be useful, but
10 WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 Further, this software is distributed without any warranty that it is
14 free of the rightful claim of any third person regarding infringement
15 or the like. Any license provided herein, whether implied or
16 otherwise, applies only to this software file. Patent licenses, if
17 any, provided herein do not apply to combinations of this program with
18 other software, or any other product whatsoever.
20 You should have received a copy of the GNU Lesser General Public
21 License along with this program; if not, write the Free Software
22 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301,
25 Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane,
26 Mountain View, CA 94043, or:
30 For further information regarding this notice, see:
32 http://oss.sgi.com/projects/GenInfo/NoticeExplan
38 /* malloc_check.c For checking dealloc completeness.
40 This code is as simple as possible and works ok for
41 reasonable size allocation counts.
43 It treats allocation as global, and so will not
44 work very well if an application opens more than one
50 #include <stdlib.h> /* for exit() and various malloc
53 #include "dwarf_incl.h"
54 #include "malloc_check.h"
55 #ifdef WANT_LIBBDWARF_MALLOC_CHECK
57 /* To turn off printing every entry, just change the define
58 to set PRINT_MALLOC_DETAILS 0.
60 #define PRINT_MALLOC_DETAILS 0
62 #define MC_TYPE_UNKNOWN 0
63 #define MC_TYPE_ALLOC 1
64 #define MC_TYPE_DEALLOC 2
67 struct mc_data_s
*mc_prev
;
68 unsigned long mc_address
; /* Assumes this is large enough to hold
71 long mc_alloc_number
; /* Assigned in order by when record
73 unsigned char mc_alloc_code
; /* Allocation code, libdwarf. */
74 unsigned char mc_type
;
75 unsigned char mc_dealloc_noted
; /* Used on an ALLOC node. */
76 unsigned char mc_dealloc_noted_count
; /* Used on an ALLOC
84 #define HASH_TABLE_SIZE 10501
85 static struct mc_data_s
*mc_data_hash
[HASH_TABLE_SIZE
];
86 static long mc_data_list_size
= 0;
88 static char *alloc_type_name
[MAX_DW_DLA
+ 1] = {
112 "DW_DLA_FRAME_BLOCK",
118 "DW_DLA_ABBREV_LIST",
122 "DW_DLA_GLOBAL_CONTEXT",
124 "DW_DLA_LINE_CONTEXT",
127 "DW_DLA_FUNC_CONTEXT",
128 "DW_DLA_TYPENAME_CONTEXT",
129 "DW_DLA_VAR_CONTEXT",
130 "DW_DLA_WEAK_CONTEXT",
131 "DW_DLA_PUBTYPES_CONTEXT"
132 /* Don't forget to expand this list if the list of codes
137 hash_address(unsigned long addr
)
139 unsigned long a
= addr
>> 2;
141 return a
% HASH_TABLE_SIZE
;
144 #if PRINT_MALLOC_DETAILS
146 print_alloc_dealloc_detail(unsigned long addr
,
147 int code
, char *whichisit
)
150 "%s addr 0x%lx code %d (%s) entry %ld\n",
151 whichisit
, addr
, code
, alloc_type_name
[code
],
155 #define print_alloc_dealloc_detail(a,b,c) /* nothing */
158 /* Create a zeroed struct or die. */
162 struct mc_data_s
*newd
= malloc(sizeof(struct mc_data_s
));
165 fprintf(stderr
, "out of memory , # %ld\n", mc_data_list_size
);
168 memset(newd
, 0, sizeof(struct mc_data_s
));
172 /* Notify checker that get_alloc has allocated user data. */
174 dwarf_malloc_check_alloc_data(void *addr_in
, unsigned char code
)
176 struct mc_data_s
*newd
= newone();
177 unsigned long addr
= (unsigned long) addr_in
;
178 struct mc_data_s
**base
= &mc_data_hash
[hash_address(addr
)];
180 print_alloc_dealloc_detail(addr
, code
, "alloc ");
181 newd
->mc_address
= addr
;
182 newd
->mc_alloc_code
= code
;
183 newd
->mc_type
= MC_TYPE_ALLOC
;
184 newd
->mc_alloc_number
= mc_data_list_size
;
185 newd
->mc_prev
= *base
;
187 newd
->mc_alloc_number
= mc_data_list_size
;
188 mc_data_list_size
+= 1;
192 print_entry(char *msg
, struct mc_data_s
*data
)
195 "%s: 0x%08lx code %2d (%s) type %s dealloc noted %u ct %u\n",
197 (long) data
->mc_address
,
199 alloc_type_name
[data
->mc_alloc_code
],
200 (data
->mc_type
== MC_TYPE_ALLOC
) ? "alloc " :
201 (data
->mc_type
== MC_TYPE_DEALLOC
) ? "dealloc" : "unknown",
202 (unsigned) data
->mc_dealloc_noted
,
203 (unsigned) data
->mc_dealloc_noted_count
);
206 /* newd is a 'dealloc'.
209 balanced_by_alloc_p(struct mc_data_s
*newd
,
210 long *addr_match_num
,
211 struct mc_data_s
**addr_match
,
212 struct mc_data_s
*base
)
214 struct mc_data_s
*cur
= base
;
216 for (; cur
; cur
= cur
->mc_prev
) {
217 if (cur
->mc_address
== newd
->mc_address
) {
218 if (cur
->mc_type
== MC_TYPE_ALLOC
) {
219 if (cur
->mc_alloc_code
== newd
->mc_alloc_code
) {
221 *addr_match_num
= cur
->mc_alloc_number
;
222 return cur
->mc_alloc_number
;
226 *addr_match_num
= cur
->mc_alloc_number
;
230 /* Unbalanced new/del */
232 *addr_match_num
= cur
->mc_alloc_number
;
240 /* A dealloc is to take place. Ensure it balances an alloc.
243 dwarf_malloc_check_dealloc_data(void *addr_in
, unsigned char code
)
245 struct mc_data_s
*newd
= newone();
247 long addr_match_num
= -1;
248 struct mc_data_s
*addr_match
= 0;
249 unsigned long addr
= (unsigned long) addr_in
;
250 struct mc_data_s
**base
= &mc_data_hash
[hash_address(addr
)];
253 print_alloc_dealloc_detail(addr
, code
, "dealloc ");
254 newd
->mc_address
= (unsigned long) addr
;
255 newd
->mc_alloc_code
= code
;
256 newd
->mc_type
= MC_TYPE_DEALLOC
;
257 newd
->mc_prev
= *base
;
259 balanced_by_alloc_p(newd
, &addr_match_num
, &addr_match
, *base
);
262 "Unbalanced dealloc at index %ld\n", mc_data_list_size
);
263 print_entry("new", newd
);
264 fprintf(stderr
, "addr-match_num? %ld\n", addr_match_num
);
266 print_entry("prev entry", addr_match
);
267 if (addr_match
->mc_dealloc_noted
> 1) {
268 fprintf(stderr
, "Above is Duplicate dealloc!\n");
274 addr_match
->mc_dealloc_noted
= 1;
275 addr_match
->mc_dealloc_noted_count
+= 1;
276 if (addr_match
->mc_dealloc_noted_count
> 1) {
277 fprintf(stderr
, "Double dealloc entry %ld\n", addr_match_num
);
278 print_entry("new dealloc entry", newd
);
279 print_entry("bad alloc entry", addr_match
);
282 mc_data_list_size
+= 1;
285 /* Final check for leaks.
288 dwarf_malloc_check_complete(char *msg
)
291 long total
= mc_data_list_size
;
292 long hash_slots_used
= 0;
293 long max_chain_length
= 0;
295 fprintf(stderr
, "Run complete, %s. %ld entries\n", msg
, total
);
296 for (; i
< HASH_TABLE_SIZE
; ++i
) {
297 struct mc_data_s
*cur
= mc_data_hash
[i
];
298 long cur_chain_length
= 0;
303 for (; cur
; cur
= cur
->mc_prev
) {
305 if (cur
->mc_type
== MC_TYPE_ALLOC
) {
306 if (cur
->mc_dealloc_noted
) {
307 if (cur
->mc_dealloc_noted
> 1) {
309 " Duplicate dealloc! entry %ld\n",
310 cur
->mc_alloc_number
);
311 print_entry("duplicate dealloc", cur
);
316 fprintf(stderr
, "malloc no dealloc, entry %ld\n",
317 cur
->mc_alloc_number
);
318 print_entry("dangle", cur
);
321 /* mc_type is MC_TYPE_DEALLOC, already checked */
325 if (cur_chain_length
> max_chain_length
) {
326 max_chain_length
= cur_chain_length
;
329 fprintf(stderr
, "mc hash table slots=%ld, "
330 "used=%ld, maxchain=%ld\n",
331 (long) HASH_TABLE_SIZE
, hash_slots_used
, max_chain_length
);
337 extern void *libdwarf_an_unused_function_so_not_empty_c_file();
339 #endif /* WANT_LIBBDWARF_MALLOC_CHECK */