1
/**************************************************************************
3
* Copyright 2008 VMware, Inc.
6
* Permission is hereby granted, free of charge, to any person obtaining a
7
* copy of this software and associated documentation files (the
8
* "Software"), to deal in the Software without restriction, including
9
* without limitation the rights to use, copy, modify, merge, publish,
10
* distribute, sub license, and/or sell copies of the Software, and to
11
* permit persons to whom the Software is furnished to do so, subject to
12
* the following conditions:
14
* The above copyright notice and this permission notice (including the
15
* next paragraph) shall be included in all copies or substantial portions
18
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
19
* OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
20
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
21
* IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
22
* ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
23
* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
24
* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26
**************************************************************************/
32
* @author José Fonseca <jfonseca@vmware.com>
35
#include "pipe/p_config.h"
37
#define DEBUG_MEMORY_IMPLEMENTATION
39
#include "os/os_thread.h"
41
#include "util/u_debug.h"
42
#include "util/u_debug_stack.h"
43
#include "util/list.h"
44
#include "util/os_memory.h"
45
#include "util/os_memory_debug.h"
48
#define DEBUG_MEMORY_MAGIC 0x6e34090aU
49
#define DEBUG_MEMORY_STACK 0 /* XXX: disabled until we have symbol lookup */
52
* Set to 1 to enable checking of freed blocks of memory.
53
* Basically, don't really deallocate freed memory; keep it in the list
54
* but mark it as freed and do extra checking in debug_memory_check().
55
* This can detect some cases of use-after-free. But note that since we
56
* never really free anything this will use a lot of memory.
58
#define DEBUG_FREED_MEMORY 0
59
#define DEBUG_FREED_BYTE 0x33
62
struct debug_memory_header
64
struct list_head head;
70
#if DEBUG_MEMORY_STACK
71
struct debug_stack_frame backtrace[DEBUG_MEMORY_STACK];
74
#if DEBUG_FREED_MEMORY
75
boolean freed; /**< Is this a freed block? */
82
struct debug_memory_footer
88
static struct list_head list = { &list, &list };
90
static mtx_t list_mutex = _MTX_INITIALIZER_NP;
92
static unsigned long last_no = 0;
95
static inline struct debug_memory_header *
96
header_from_data(void *data)
99
return (struct debug_memory_header *)((char *)data - sizeof(struct debug_memory_header));
105
data_from_header(struct debug_memory_header *hdr)
108
return (void *)((char *)hdr + sizeof(struct debug_memory_header));
113
static inline struct debug_memory_footer *
114
footer_from_header(struct debug_memory_header *hdr)
117
return (struct debug_memory_footer *)((char *)hdr + sizeof(struct debug_memory_header) + hdr->size);
124
debug_malloc(const char *file, unsigned line, const char *function,
127
struct debug_memory_header *hdr;
128
struct debug_memory_footer *ftr;
130
hdr = os_malloc(sizeof(*hdr) + size + sizeof(*ftr));
132
debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
133
file, line, function,
134
(long unsigned)size);
141
hdr->function = function;
143
hdr->magic = DEBUG_MEMORY_MAGIC;
145
#if DEBUG_FREED_MEMORY
149
#if DEBUG_MEMORY_STACK
150
debug_backtrace_capture(hdr->backtrace, 0, DEBUG_MEMORY_STACK);
153
ftr = footer_from_header(hdr);
154
ftr->magic = DEBUG_MEMORY_MAGIC;
156
mtx_lock(&list_mutex);
157
list_addtail(&hdr->head, &list);
158
mtx_unlock(&list_mutex);
160
return data_from_header(hdr);
164
debug_free(const char *file, unsigned line, const char *function,
167
struct debug_memory_header *hdr;
168
struct debug_memory_footer *ftr;
173
hdr = header_from_data(ptr);
174
if (hdr->magic != DEBUG_MEMORY_MAGIC) {
175
debug_printf("%s:%u:%s: freeing bad or corrupted memory %p\n",
176
file, line, function,
182
ftr = footer_from_header(hdr);
183
if (ftr->magic != DEBUG_MEMORY_MAGIC) {
184
debug_printf("%s:%u:%s: buffer overflow %p\n",
185
hdr->file, hdr->line, hdr->function,
190
#if DEBUG_FREED_MEMORY
191
/* Check for double-free */
193
/* Mark the block as freed but don't really free it */
195
/* Save file/line where freed */
198
/* set freed memory to special value */
199
memset(ptr, DEBUG_FREED_BYTE, hdr->size);
201
mtx_lock(&list_mutex);
202
list_del(&hdr->head);
203
mtx_unlock(&list_mutex);
212
debug_calloc(const char *file, unsigned line, const char *function,
213
size_t count, size_t size )
215
void *ptr = debug_malloc( file, line, function, count * size );
217
memset( ptr, 0, count * size );
222
debug_realloc(const char *file, unsigned line, const char *function,
223
void *old_ptr, size_t old_size, size_t new_size )
225
struct debug_memory_header *old_hdr, *new_hdr;
226
struct debug_memory_footer *old_ftr, *new_ftr;
230
return debug_malloc( file, line, function, new_size );
233
debug_free( file, line, function, old_ptr );
237
old_hdr = header_from_data(old_ptr);
238
if (old_hdr->magic != DEBUG_MEMORY_MAGIC) {
239
debug_printf("%s:%u:%s: reallocating bad or corrupted memory %p\n",
240
file, line, function,
246
old_ftr = footer_from_header(old_hdr);
247
if (old_ftr->magic != DEBUG_MEMORY_MAGIC) {
248
debug_printf("%s:%u:%s: buffer overflow %p\n",
249
old_hdr->file, old_hdr->line, old_hdr->function,
255
new_hdr = os_malloc(sizeof(*new_hdr) + new_size + sizeof(*new_ftr));
257
debug_printf("%s:%u:%s: out of memory when trying to allocate %lu bytes\n",
258
file, line, function,
259
(long unsigned)new_size);
262
new_hdr->no = old_hdr->no;
263
new_hdr->file = old_hdr->file;
264
new_hdr->line = old_hdr->line;
265
new_hdr->function = old_hdr->function;
266
new_hdr->size = new_size;
267
new_hdr->magic = DEBUG_MEMORY_MAGIC;
269
#if DEBUG_FREED_MEMORY
270
new_hdr->freed = FALSE;
273
new_ftr = footer_from_header(new_hdr);
274
new_ftr->magic = DEBUG_MEMORY_MAGIC;
276
mtx_lock(&list_mutex);
277
list_replace(&old_hdr->head, &new_hdr->head);
278
mtx_unlock(&list_mutex);
281
new_ptr = data_from_header(new_hdr);
282
memcpy( new_ptr, old_ptr, old_size < new_size ? old_size : new_size );
293
debug_memory_begin(void)
299
debug_memory_end(unsigned long start_no)
301
size_t total_size = 0;
302
struct list_head *entry;
304
if (start_no == last_no)
308
for (; entry != &list; entry = entry->prev) {
309
struct debug_memory_header *hdr;
311
struct debug_memory_footer *ftr;
313
hdr = LIST_ENTRY(struct debug_memory_header, entry, head);
314
ptr = data_from_header(hdr);
315
ftr = footer_from_header(hdr);
317
if (hdr->magic != DEBUG_MEMORY_MAGIC) {
318
debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
319
hdr->file, hdr->line, hdr->function,
324
if ((start_no <= hdr->no && hdr->no < last_no) ||
325
(last_no < start_no && (hdr->no < last_no || start_no <= hdr->no))) {
326
debug_printf("%s:%u:%s: %lu bytes at %p not freed\n",
327
hdr->file, hdr->line, hdr->function,
328
(unsigned long) hdr->size, ptr);
329
#if DEBUG_MEMORY_STACK
330
debug_backtrace_dump(hdr->backtrace, DEBUG_MEMORY_STACK);
332
total_size += hdr->size;
335
if (ftr->magic != DEBUG_MEMORY_MAGIC) {
336
debug_printf("%s:%u:%s: buffer overflow %p\n",
337
hdr->file, hdr->line, hdr->function,
344
debug_printf("Total of %lu KB of system memory apparently leaked\n",
345
(unsigned long) (total_size + 1023)/1024);
348
debug_printf("No memory leaks detected.\n");
354
* Put a tag (arbitrary integer) on a memory block.
355
* Can be useful for debugging.
358
debug_memory_tag(void *ptr, unsigned tag)
360
struct debug_memory_header *hdr;
365
hdr = header_from_data(ptr);
366
if (hdr->magic != DEBUG_MEMORY_MAGIC) {
367
debug_printf("%s corrupted memory at %p\n", __FUNCTION__, ptr);
376
* Check the given block of memory for validity/corruption.
379
debug_memory_check_block(void *ptr)
381
struct debug_memory_header *hdr;
382
struct debug_memory_footer *ftr;
387
hdr = header_from_data(ptr);
388
ftr = footer_from_header(hdr);
390
if (hdr->magic != DEBUG_MEMORY_MAGIC) {
391
debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
392
hdr->file, hdr->line, hdr->function, ptr);
396
if (ftr->magic != DEBUG_MEMORY_MAGIC) {
397
debug_printf("%s:%u:%s: buffer overflow %p\n",
398
hdr->file, hdr->line, hdr->function, ptr);
406
* We can periodically call this from elsewhere to do a basic sanity
407
* check of the heap memory we've allocated.
410
debug_memory_check(void)
412
struct list_head *entry;
415
for (; entry != &list; entry = entry->prev) {
416
struct debug_memory_header *hdr;
417
struct debug_memory_footer *ftr;
420
hdr = LIST_ENTRY(struct debug_memory_header, entry, head);
421
ftr = footer_from_header(hdr);
422
ptr = (const char *) data_from_header(hdr);
424
if (hdr->magic != DEBUG_MEMORY_MAGIC) {
425
debug_printf("%s:%u:%s: bad or corrupted memory %p\n",
426
hdr->file, hdr->line, hdr->function, ptr);
430
if (ftr->magic != DEBUG_MEMORY_MAGIC) {
431
debug_printf("%s:%u:%s: buffer overflow %p\n",
432
hdr->file, hdr->line, hdr->function, ptr);
436
#if DEBUG_FREED_MEMORY
437
/* If this block is marked as freed, check that it hasn't been touched */
440
for (i = 0; i < hdr->size; i++) {
441
if (ptr[i] != DEBUG_FREED_BYTE) {
442
debug_printf("Memory error: byte %d of block at %p of size %d is 0x%x\n",
443
i, ptr, hdr->size, ptr[i]);
444
debug_printf("Block was freed at %s:%d\n", hdr->file, hdr->line);
446
assert(ptr[i] == DEBUG_FREED_BYTE);