1
/************************************************************************
2
The memory management: the debug code. This is not a compilation module,
3
but is included in mem0mem.* !
5
(c) 1994, 1995 Innobase Oy
7
Created 6/9/1994 Heikki Tuuri
8
*************************************************************************/
11
mutex_t mem_hash_mutex; /* The mutex which protects in the
12
debug version the hash table containing
13
the list of live memory heaps, and
14
also the global variables below. */
16
/* The following variables contain information about the
17
extent of memory allocations. Only used in the debug version.
18
Protected by mem_hash_mutex above. */
20
static ulint mem_n_created_heaps = 0;
21
static ulint mem_n_allocations = 0;
22
static ulint mem_total_allocated_memory = 0;
23
ulint mem_current_allocated_memory = 0;
24
static ulint mem_max_allocated_memory = 0;
25
static ulint mem_last_print_info = 0;
27
/* Size of the hash table for memory management tracking */
28
#define MEM_HASH_SIZE 997
30
/* The node of the list containing currently allocated memory heaps */
32
typedef struct mem_hash_node_struct mem_hash_node_t;
33
struct mem_hash_node_struct {
34
UT_LIST_NODE_T(mem_hash_node_t)
35
list; /* hash list node */
36
mem_heap_t* heap; /* memory heap */
37
const char* file_name;/* file where heap was created*/
38
ulint line; /* file line of creation */
39
ulint nth_heap;/* this is the nth heap created */
40
UT_LIST_NODE_T(mem_hash_node_t)
41
all_list;/* list of all created heaps */
44
typedef UT_LIST_BASE_NODE_T(mem_hash_node_t) mem_hash_cell_t;
46
/* The hash table of allocated heaps */
47
static mem_hash_cell_t mem_hash_table[MEM_HASH_SIZE];
49
/* The base node of the list of all allocated heaps */
50
static mem_hash_cell_t mem_all_list_base;
52
static ibool mem_hash_initialized = FALSE;
57
mem_hash_get_nth_cell(ulint i);
59
/* Accessor function for the hash table. Returns a pointer to the
63
mem_hash_get_nth_cell(ulint i)
65
ut_a(i < MEM_HASH_SIZE);
67
return(&(mem_hash_table[i]));
70
/* Accessor functions for a memory field in the debug version */
73
mem_field_header_set_len(byte* field, ulint len)
75
mach_write_to_4(field - 2 * sizeof(ulint), len);
79
mem_field_header_get_len(byte* field)
81
return(mach_read_from_4(field - 2 * sizeof(ulint)));
85
mem_field_header_set_check(byte* field, ulint check)
87
mach_write_to_4(field - sizeof(ulint), check);
91
mem_field_header_get_check(byte* field)
93
return(mach_read_from_4(field - sizeof(ulint)));
97
mem_field_trailer_set_check(byte* field, ulint check)
99
mach_write_to_4(field + mem_field_header_get_len(field), check);
103
mem_field_trailer_get_check(byte* field)
105
return(mach_read_from_4(field
106
+ mem_field_header_get_len(field)));
108
#endif /* UNIV_MEM_DEBUG */
110
/**********************************************************************
111
Initializes the memory system. */
116
ulint size) /* in: common pool size in bytes */
118
#ifdef UNIV_MEM_DEBUG
122
/* Initialize the hash table */
123
ut_a(FALSE == mem_hash_initialized);
125
mutex_create(&mem_hash_mutex, SYNC_MEM_HASH);
127
for (i = 0; i < MEM_HASH_SIZE; i++) {
128
UT_LIST_INIT(*mem_hash_get_nth_cell(i));
131
UT_LIST_INIT(mem_all_list_base);
133
mem_hash_initialized = TRUE;
136
mem_comm_pool = mem_pool_create(size);
139
#ifdef UNIV_MEM_DEBUG
140
/**********************************************************************
141
Initializes an allocated memory field in the debug version. */
146
byte* buf, /* in: memory field */
147
ulint n) /* in: how many bytes the user requested */
152
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
154
/* In the debug version write the length field and the
155
check fields to the start and the end of the allocated storage.
156
The field header consists of a length field and
157
a random number field, in this order. The field trailer contains
158
the same random number as a check field. */
160
mem_field_header_set_len(usr_buf, n);
162
rnd = ut_rnd_gen_ulint();
164
mem_field_header_set_check(usr_buf, rnd);
165
mem_field_trailer_set_check(usr_buf, rnd);
167
/* Update the memory allocation information */
169
mutex_enter(&mem_hash_mutex);
171
mem_total_allocated_memory += n;
172
mem_current_allocated_memory += n;
175
if (mem_current_allocated_memory > mem_max_allocated_memory) {
176
mem_max_allocated_memory = mem_current_allocated_memory;
179
mutex_exit(&mem_hash_mutex);
181
/* In the debug version set the buffer to a random
182
combination of 0xBA and 0xBE */
184
mem_init_buf(usr_buf, n);
187
/**********************************************************************
188
Erases an allocated memory field in the debug version. */
193
byte* buf, /* in: memory field */
194
ulint n __attribute__((unused)))
195
/* in: how many bytes the user requested */
199
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
201
mutex_enter(&mem_hash_mutex);
202
mem_current_allocated_memory -= n;
203
mutex_exit(&mem_hash_mutex);
205
/* Check that the field lengths agree */
206
ut_ad(n == (ulint)mem_field_header_get_len(usr_buf));
208
/* In the debug version, set the freed space to a random
209
combination of 0xDE and 0xAD */
211
mem_erase_buf(buf, MEM_SPACE_NEEDED(n));
214
/*******************************************************************
215
Initializes a buffer to a random combination of hex BA and BE.
216
Used to initialize allocated memory. */
221
byte* buf, /* in: pointer to buffer */
222
ulint n) /* in: length of buffer */
226
UNIV_MEM_ASSERT_W(buf, n);
228
for (ptr = buf; ptr < buf + n; ptr++) {
230
if (ut_rnd_gen_ibool()) {
237
UNIV_MEM_INVALID(buf, n);
240
/*******************************************************************
241
Initializes a buffer to a random combination of hex DE and AD.
242
Used to erase freed memory.*/
247
byte* buf, /* in: pointer to buffer */
248
ulint n) /* in: length of buffer */
252
UNIV_MEM_ASSERT_W(buf, n);
254
for (ptr = buf; ptr < buf + n; ptr++) {
255
if (ut_rnd_gen_ibool()) {
262
UNIV_MEM_FREE(buf, n);
265
/*******************************************************************
266
Inserts a created memory heap to the hash table of current allocated
272
mem_heap_t* heap, /* in: the created heap */
273
const char* file_name, /* in: file name of creation */
274
ulint line) /* in: line where created */
276
mem_hash_node_t* new_node;
279
ut_ad(mem_heap_check(heap));
281
mutex_enter(&mem_hash_mutex);
283
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
285
/* Allocate a new node to the list */
286
new_node = ut_malloc(sizeof(mem_hash_node_t));
288
new_node->heap = heap;
289
new_node->file_name = file_name;
290
new_node->line = line;
291
new_node->nth_heap = mem_n_created_heaps;
293
/* Insert into lists */
294
UT_LIST_ADD_FIRST(list, *mem_hash_get_nth_cell(cell_no), new_node);
296
UT_LIST_ADD_LAST(all_list, mem_all_list_base, new_node);
298
mem_n_created_heaps++;
300
mutex_exit(&mem_hash_mutex);
303
/*******************************************************************
304
Removes a memory heap (which is going to be freed by the caller)
305
from the list of live memory heaps. Returns the size of the heap
306
in terms of how much memory in bytes was allocated for the user of
307
the heap (not the total space occupied by the heap).
308
Also validates the heap.
309
NOTE: This function does not free the storage occupied by the
310
heap itself, only the node in the list of heaps. */
315
mem_heap_t* heap, /* in: the heap to be freed */
316
const char* file_name, /* in: file name of freeing */
317
ulint line) /* in: line where freed */
319
mem_hash_node_t* node;
324
ut_ad(mem_heap_check(heap));
326
mutex_enter(&mem_hash_mutex);
328
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
330
/* Look for the heap in the hash table list */
331
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(cell_no));
333
while (node != NULL) {
334
if (node->heap == heap) {
339
node = UT_LIST_GET_NEXT(list, node);
344
"Memory heap or buffer freed in %s line %lu"
346
file_name, (ulong) line);
350
/* Remove from lists */
351
UT_LIST_REMOVE(list, *mem_hash_get_nth_cell(cell_no), node);
353
UT_LIST_REMOVE(all_list, mem_all_list_base, node);
355
/* Validate the heap which will be freed */
356
mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size,
360
"Inconsistency in memory heap or"
361
" buffer n:o %lu created\n"
362
"in %s line %lu and tried to free in %s line %lu.\n"
363
"Hex dump of 400 bytes around memory heap"
364
" first block start:\n",
365
node->nth_heap, node->file_name, (ulong) node->line,
366
file_name, (ulong) line);
367
ut_print_buf(stderr, (byte*)node->heap - 200, 400);
368
fputs("\nDump of the mem heap:\n", stderr);
369
mem_heap_validate_or_print(node->heap, NULL, TRUE, &error,
374
/* Free the memory occupied by the node struct */
377
mem_current_allocated_memory -= size;
379
mutex_exit(&mem_hash_mutex);
381
#endif /* UNIV_MEM_DEBUG */
383
#if defined UNIV_MEM_DEBUG || defined UNIV_DEBUG
384
/*******************************************************************
385
Checks a memory heap for consistency and prints the contents if requested.
386
Outputs the sum of sizes of buffers given to the user (only in
387
the debug version), the physical size of the heap and the number of
388
blocks in the heap. In case of error returns 0 as sizes and number
392
mem_heap_validate_or_print(
393
/*=======================*/
394
mem_heap_t* heap, /* in: memory heap */
395
byte* top __attribute__((unused)),
396
/* in: calculate and validate only until
397
this top pointer in the heap is reached,
398
if this pointer is NULL, ignored */
399
ibool print, /* in: if TRUE, prints the contents
400
of the heap; works only in
402
ibool* error, /* out: TRUE if error */
403
ulint* us_size,/* out: allocated memory
404
(for the user) in the heap,
405
if a NULL pointer is passed as this
406
argument, it is ignored; in the
407
non-debug version this is always -1 */
408
ulint* ph_size,/* out: physical size of the heap,
409
if a NULL pointer is passed as this
410
argument, it is ignored */
411
ulint* n_blocks) /* out: number of blocks in the heap,
412
if a NULL pointer is passed as this
413
argument, it is ignored */
417
ulint block_count = 0;
419
#ifdef UNIV_MEM_DEBUG
426
/* Pessimistically, we set the parameters to error values */
427
if (us_size != NULL) {
430
if (ph_size != NULL) {
433
if (n_blocks != NULL) {
440
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
445
fputs("Memory heap:", stderr);
448
while (block != NULL) {
449
phys_len += mem_block_get_len(block);
451
if ((block->type == MEM_HEAP_BUFFER)
452
&& (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
455
"InnoDB: Error: mem block %p"
456
" length %lu > UNIV_PAGE_SIZE\n",
458
(ulong) mem_block_get_len(block));
464
#ifdef UNIV_MEM_DEBUG
465
/* We can trace the fields of the block only in the debug
468
fprintf(stderr, " Block %ld:", block_count);
471
field = (byte*)block + mem_block_get_start(block);
473
if (top && (field == top)) {
478
while (field < (byte*)block + mem_block_get_free(block)) {
480
/* Calculate the pointer to the storage
481
which was given to the user */
483
user_field = field + MEM_FIELD_HEADER_SIZE;
485
len = mem_field_header_get_len(user_field);
488
ut_print_buf(stderr, user_field, len);
492
check_field = mem_field_header_get_check(user_field);
495
!= mem_field_trailer_get_check(user_field)) {
499
"InnoDB: Error: block %lx mem"
500
" field %lx len %lu\n"
501
"InnoDB: header check field is"
502
" %lx but trailer %lx\n",
504
(ulint)field, len, check_field,
505
mem_field_trailer_get_check(
511
/* Move to next field */
512
field = field + MEM_SPACE_NEEDED(len);
514
if (top && (field == top)) {
521
/* At the end check that we have arrived to the first free
524
if (field != (byte*)block + mem_block_get_free(block)) {
528
"InnoDB: Error: block %lx end of"
530
"InnoDB: but block free at %lx\n",
531
(ulint)block, (ulint)field,
533
+ mem_block_get_free(block)));
540
block = UT_LIST_GET_NEXT(list, block);
543
#ifdef UNIV_MEM_DEBUG
546
if (us_size != NULL) {
547
*us_size = total_len;
549
if (ph_size != NULL) {
552
if (n_blocks != NULL) {
553
*n_blocks = block_count;
558
/******************************************************************
559
Prints the contents of a memory heap. */
564
mem_heap_t* heap) /* in: memory heap */
571
ut_ad(mem_heap_check(heap));
573
mem_heap_validate_or_print(heap, NULL, TRUE, &error,
574
&us_size, &phys_size, &n_blocks);
576
"\nheap type: %lu; size: user size %lu;"
577
" physical size %lu; blocks %lu.\n",
578
(ulong) heap->type, (ulong) us_size,
579
(ulong) phys_size, (ulong) n_blocks);
583
/******************************************************************
584
Validates the contents of a memory heap. */
589
/* out: TRUE if ok */
590
mem_heap_t* heap) /* in: memory heap */
597
ut_ad(mem_heap_check(heap));
599
mem_heap_validate_or_print(heap, NULL, FALSE, &error, &us_size,
600
&phys_size, &n_blocks);
602
mem_heap_print(heap);
609
#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
612
/******************************************************************
613
Checks that an object is a memory heap (or a block of it). */
618
/* out: TRUE if ok */
619
mem_heap_t* heap) /* in: memory heap */
621
ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N);
625
#endif /* UNIV_DEBUG */
627
#ifdef UNIV_MEM_DEBUG
628
/*********************************************************************
629
TRUE if no memory is currently allocated. */
634
/* out: TRUE if no heaps exist */
636
mem_hash_node_t* node;
637
ulint heap_count = 0;
642
mutex_enter(&mem_hash_mutex);
644
for (i = 0; i < MEM_HASH_SIZE; i++) {
646
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
647
while (node != NULL) {
649
node = UT_LIST_GET_NEXT(list, node);
653
mutex_exit(&mem_hash_mutex);
655
if (heap_count == 0) {
657
ut_a(mem_pool_get_reserved(mem_comm_pool) == 0);
665
/*********************************************************************
666
Validates the dynamic memory allocation system. */
669
mem_validate_no_assert(void)
670
/*========================*/
671
/* out: TRUE if error */
673
mem_hash_node_t* node;
677
ulint total_allocated_mem = 0;
682
mem_pool_validate(mem_comm_pool);
684
mutex_enter(&mem_hash_mutex);
686
for (i = 0; i < MEM_HASH_SIZE; i++) {
688
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
690
while (node != NULL) {
693
mem_heap_validate_or_print(node->heap, NULL,
696
&ph_size, &n_blocks);
700
"\nERROR!!!!!!!!!!!!!!!!!!!"
701
"!!!!!!!!!!!!!!!!!!!!!!!\n\n"
702
"Inconsistency in memory heap"
703
" or buffer created\n"
705
node->file_name, node->line);
707
mutex_exit(&mem_hash_mutex);
712
total_allocated_mem += allocated_mem;
713
node = UT_LIST_GET_NEXT(list, node);
717
if ((n_heaps == 0) && (mem_current_allocated_memory != 0)) {
721
if (mem_total_allocated_memory < mem_current_allocated_memory) {
725
if (mem_max_allocated_memory > mem_total_allocated_memory) {
729
if (mem_n_created_heaps < n_heaps) {
733
mutex_exit(&mem_hash_mutex);
738
/****************************************************************
739
Validates the dynamic memory */
744
/* out: TRUE if ok */
746
ut_a(!mem_validate_no_assert());
750
#endif /* UNIV_MEM_DEBUG */
752
/****************************************************************
753
Tries to find neigboring memory allocation blocks and dumps to stderr
754
the neighborhood of a given pointer. */
757
mem_analyze_corruption(
758
/*===================*/
759
void* ptr) /* in: pointer to place of possible corruption */
765
fputs("InnoDB: Apparent memory corruption: mem dump ", stderr);
766
ut_print_buf(stderr, (byte*)ptr - 250, 500);
768
fputs("\nInnoDB: Scanning backward trying to find"
769
" previous allocated mem blocks\n", stderr);
774
for (i = 0; i < 10; i++) {
776
if (((ulint)p) % 4 == 0) {
778
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
780
"Mem block at - %lu,"
781
" file %s, line %lu\n",
791
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
793
"Freed mem block at - %lu,"
794
" file %s, line %lu\n",
814
"InnoDB: Scanning forward trying to find next"
815
" allocated mem blocks\n");
820
for (i = 0; i < 10; i++) {
822
if (((ulint)p) % 4 == 0) {
824
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
826
"Mem block at + %lu, file %s,"
837
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
839
"Freed mem block at + %lu,"
840
" file %s, line %lu\n",
860
/*********************************************************************
861
Prints information of dynamic memory usage and currently allocated
862
memory heaps or buffers. Can only be used in the debug version. */
867
ibool print_all) /* in: if TRUE, all heaps are printed,
868
else only the heaps allocated after the
869
previous call of this function */
871
#ifdef UNIV_MEM_DEBUG
872
mem_hash_node_t* node;
876
ulint total_allocated_mem = 0;
882
/* outfile = fopen("ibdebug", "a"); */
886
fprintf(outfile, "\n");
888
"________________________________________________________\n");
889
fprintf(outfile, "MEMORY ALLOCATION INFORMATION\n\n");
891
#ifndef UNIV_MEM_DEBUG
893
UT_NOT_USED(print_all);
895
mem_pool_print_info(outfile, mem_comm_pool);
898
"Sorry, non-debug version cannot give more memory info\n");
900
/* fclose(outfile); */
904
mutex_enter(&mem_hash_mutex);
906
fprintf(outfile, "LIST OF CREATED HEAPS AND ALLOCATED BUFFERS: \n\n");
909
fprintf(outfile, "AFTER THE LAST PRINT INFO\n");
912
node = UT_LIST_GET_FIRST(mem_all_list_base);
914
while (node != NULL) {
917
if (!print_all && node->nth_heap < mem_last_print_info) {
922
mem_heap_validate_or_print(node->heap, NULL,
923
FALSE, &error, &allocated_mem,
924
&ph_size, &n_blocks);
925
total_allocated_mem += allocated_mem;
928
"%lu: file %s line %lu of size %lu phys.size %lu"
929
" with %lu blocks, type %lu\n",
930
node->nth_heap, node->file_name, node->line,
931
allocated_mem, ph_size, n_blocks,
934
node = UT_LIST_GET_NEXT(all_list, node);
937
fprintf(outfile, "\n");
939
fprintf(outfile, "Current allocated memory : %lu\n",
940
mem_current_allocated_memory);
941
fprintf(outfile, "Current allocated heaps and buffers : %lu\n",
943
fprintf(outfile, "Cumulative allocated memory : %lu\n",
944
mem_total_allocated_memory);
945
fprintf(outfile, "Maximum allocated memory : %lu\n",
946
mem_max_allocated_memory);
947
fprintf(outfile, "Cumulative created heaps and buffers : %lu\n",
948
mem_n_created_heaps);
949
fprintf(outfile, "Cumulative number of allocations : %lu\n",
952
mem_last_print_info = mem_n_created_heaps;
954
mutex_exit(&mem_hash_mutex);
956
mem_pool_print_info(outfile, mem_comm_pool);
958
/* mem_validate(); */
960
/* fclose(outfile); */
964
/*********************************************************************
965
Prints information of dynamic memory usage and currently allocated memory
966
heaps or buffers. Can only be used in the debug version. */
972
mem_print_info_low(TRUE);
975
/*********************************************************************
976
Prints information of dynamic memory usage and currently allocated memory
977
heaps or buffers since the last ..._print_info or..._print_new_info. */
980
mem_print_new_info(void)
981
/*====================*/
983
mem_print_info_low(FALSE);