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
/* The mutex which protects in the debug version the hash table
12
containing the list of live memory heaps, and also the global
14
UNIV_INTERN mutex_t mem_hash_mutex;
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
UNIV_INTERN 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);
80
mem_field_header_get_len(byte* field)
82
return(mach_read_from_4(field - 2 * sizeof(ulint)));
87
mem_field_header_set_check(byte* field, ulint check)
89
mach_write_to_4(field - sizeof(ulint), check);
94
mem_field_header_get_check(byte* field)
96
return(mach_read_from_4(field - sizeof(ulint)));
101
mem_field_trailer_set_check(byte* field, ulint check)
103
mach_write_to_4(field + mem_field_header_get_len(field), check);
108
mem_field_trailer_get_check(byte* field)
110
return(mach_read_from_4(field
111
+ mem_field_header_get_len(field)));
113
#endif /* UNIV_MEM_DEBUG */
115
/**********************************************************************
116
Initializes the memory system. */
121
ulint size) /* in: common pool size in bytes */
123
#ifdef UNIV_MEM_DEBUG
127
/* Initialize the hash table */
128
ut_a(FALSE == mem_hash_initialized);
130
mutex_create(&mem_hash_mutex, SYNC_MEM_HASH);
132
for (i = 0; i < MEM_HASH_SIZE; i++) {
133
UT_LIST_INIT(*mem_hash_get_nth_cell(i));
136
UT_LIST_INIT(mem_all_list_base);
138
mem_hash_initialized = TRUE;
141
mem_comm_pool = mem_pool_create(size);
144
#ifdef UNIV_MEM_DEBUG
145
/**********************************************************************
146
Initializes an allocated memory field in the debug version. */
151
byte* buf, /* in: memory field */
152
ulint n) /* in: how many bytes the user requested */
157
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
159
/* In the debug version write the length field and the
160
check fields to the start and the end of the allocated storage.
161
The field header consists of a length field and
162
a random number field, in this order. The field trailer contains
163
the same random number as a check field. */
165
mem_field_header_set_len(usr_buf, n);
167
rnd = ut_rnd_gen_ulint();
169
mem_field_header_set_check(usr_buf, rnd);
170
mem_field_trailer_set_check(usr_buf, rnd);
172
/* Update the memory allocation information */
174
mutex_enter(&mem_hash_mutex);
176
mem_total_allocated_memory += n;
177
mem_current_allocated_memory += n;
180
if (mem_current_allocated_memory > mem_max_allocated_memory) {
181
mem_max_allocated_memory = mem_current_allocated_memory;
184
mutex_exit(&mem_hash_mutex);
186
/* In the debug version set the buffer to a random
187
combination of 0xBA and 0xBE */
189
mem_init_buf(usr_buf, n);
192
/**********************************************************************
193
Erases an allocated memory field in the debug version. */
198
byte* buf, /* in: memory field */
199
ulint n __attribute__((unused)))
200
/* in: how many bytes the user requested */
204
usr_buf = buf + MEM_FIELD_HEADER_SIZE;
206
mutex_enter(&mem_hash_mutex);
207
mem_current_allocated_memory -= n;
208
mutex_exit(&mem_hash_mutex);
210
/* Check that the field lengths agree */
211
ut_ad(n == (ulint)mem_field_header_get_len(usr_buf));
213
/* In the debug version, set the freed space to a random
214
combination of 0xDE and 0xAD */
216
mem_erase_buf(buf, MEM_SPACE_NEEDED(n));
219
/*******************************************************************
220
Initializes a buffer to a random combination of hex BA and BE.
221
Used to initialize allocated memory. */
226
byte* buf, /* in: pointer to buffer */
227
ulint n) /* in: length of buffer */
231
UNIV_MEM_ASSERT_W(buf, n);
233
for (ptr = buf; ptr < buf + n; ptr++) {
235
if (ut_rnd_gen_ibool()) {
242
UNIV_MEM_INVALID(buf, n);
245
/*******************************************************************
246
Initializes a buffer to a random combination of hex DE and AD.
247
Used to erase freed memory.*/
252
byte* buf, /* in: pointer to buffer */
253
ulint n) /* in: length of buffer */
257
UNIV_MEM_ASSERT_W(buf, n);
259
for (ptr = buf; ptr < buf + n; ptr++) {
260
if (ut_rnd_gen_ibool()) {
267
UNIV_MEM_FREE(buf, n);
270
/*******************************************************************
271
Inserts a created memory heap to the hash table of current allocated
277
mem_heap_t* heap, /* in: the created heap */
278
const char* file_name, /* in: file name of creation */
279
ulint line) /* in: line where created */
281
mem_hash_node_t* new_node;
284
ut_ad(mem_heap_check(heap));
286
mutex_enter(&mem_hash_mutex);
288
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
290
/* Allocate a new node to the list */
291
new_node = ut_malloc(sizeof(mem_hash_node_t));
293
new_node->heap = heap;
294
new_node->file_name = file_name;
295
new_node->line = line;
296
new_node->nth_heap = mem_n_created_heaps;
298
/* Insert into lists */
299
UT_LIST_ADD_FIRST(list, *mem_hash_get_nth_cell(cell_no), new_node);
301
UT_LIST_ADD_LAST(all_list, mem_all_list_base, new_node);
303
mem_n_created_heaps++;
305
mutex_exit(&mem_hash_mutex);
308
/*******************************************************************
309
Removes a memory heap (which is going to be freed by the caller)
310
from the list of live memory heaps. Returns the size of the heap
311
in terms of how much memory in bytes was allocated for the user of
312
the heap (not the total space occupied by the heap).
313
Also validates the heap.
314
NOTE: This function does not free the storage occupied by the
315
heap itself, only the node in the list of heaps. */
320
mem_heap_t* heap, /* in: the heap to be freed */
321
const char* file_name, /* in: file name of freeing */
322
ulint line) /* in: line where freed */
324
mem_hash_node_t* node;
329
ut_ad(mem_heap_check(heap));
331
mutex_enter(&mem_hash_mutex);
333
cell_no = ut_hash_ulint((ulint)heap, MEM_HASH_SIZE);
335
/* Look for the heap in the hash table list */
336
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(cell_no));
338
while (node != NULL) {
339
if (node->heap == heap) {
344
node = UT_LIST_GET_NEXT(list, node);
349
"Memory heap or buffer freed in %s line %lu"
351
file_name, (ulong) line);
355
/* Remove from lists */
356
UT_LIST_REMOVE(list, *mem_hash_get_nth_cell(cell_no), node);
358
UT_LIST_REMOVE(all_list, mem_all_list_base, node);
360
/* Validate the heap which will be freed */
361
mem_heap_validate_or_print(node->heap, NULL, FALSE, &error, &size,
365
"Inconsistency in memory heap or"
366
" buffer n:o %lu created\n"
367
"in %s line %lu and tried to free in %s line %lu.\n"
368
"Hex dump of 400 bytes around memory heap"
369
" first block start:\n",
370
node->nth_heap, node->file_name, (ulong) node->line,
371
file_name, (ulong) line);
372
ut_print_buf(stderr, (byte*)node->heap - 200, 400);
373
fputs("\nDump of the mem heap:\n", stderr);
374
mem_heap_validate_or_print(node->heap, NULL, TRUE, &error,
379
/* Free the memory occupied by the node struct */
382
mem_current_allocated_memory -= size;
384
mutex_exit(&mem_hash_mutex);
386
#endif /* UNIV_MEM_DEBUG */
388
#if defined UNIV_MEM_DEBUG || defined UNIV_DEBUG
389
/*******************************************************************
390
Checks a memory heap for consistency and prints the contents if requested.
391
Outputs the sum of sizes of buffers given to the user (only in
392
the debug version), the physical size of the heap and the number of
393
blocks in the heap. In case of error returns 0 as sizes and number
397
mem_heap_validate_or_print(
398
/*=======================*/
399
mem_heap_t* heap, /* in: memory heap */
400
byte* top __attribute__((unused)),
401
/* in: calculate and validate only until
402
this top pointer in the heap is reached,
403
if this pointer is NULL, ignored */
404
ibool print, /* in: if TRUE, prints the contents
405
of the heap; works only in
407
ibool* error, /* out: TRUE if error */
408
ulint* us_size,/* out: allocated memory
409
(for the user) in the heap,
410
if a NULL pointer is passed as this
411
argument, it is ignored; in the
412
non-debug version this is always -1 */
413
ulint* ph_size,/* out: physical size of the heap,
414
if a NULL pointer is passed as this
415
argument, it is ignored */
416
ulint* n_blocks) /* out: number of blocks in the heap,
417
if a NULL pointer is passed as this
418
argument, it is ignored */
422
ulint block_count = 0;
424
#ifdef UNIV_MEM_DEBUG
431
/* Pessimistically, we set the parameters to error values */
432
if (us_size != NULL) {
435
if (ph_size != NULL) {
438
if (n_blocks != NULL) {
445
if (block->magic_n != MEM_BLOCK_MAGIC_N) {
450
fputs("Memory heap:", stderr);
453
while (block != NULL) {
454
phys_len += mem_block_get_len(block);
456
if ((block->type == MEM_HEAP_BUFFER)
457
&& (mem_block_get_len(block) > UNIV_PAGE_SIZE)) {
460
"InnoDB: Error: mem block %p"
461
" length %lu > UNIV_PAGE_SIZE\n",
463
(ulong) mem_block_get_len(block));
469
#ifdef UNIV_MEM_DEBUG
470
/* We can trace the fields of the block only in the debug
473
fprintf(stderr, " Block %ld:", block_count);
476
field = (byte*)block + mem_block_get_start(block);
478
if (top && (field == top)) {
483
while (field < (byte*)block + mem_block_get_free(block)) {
485
/* Calculate the pointer to the storage
486
which was given to the user */
488
user_field = field + MEM_FIELD_HEADER_SIZE;
490
len = mem_field_header_get_len(user_field);
493
ut_print_buf(stderr, user_field, len);
497
check_field = mem_field_header_get_check(user_field);
500
!= mem_field_trailer_get_check(user_field)) {
504
"InnoDB: Error: block %lx mem"
505
" field %lx len %lu\n"
506
"InnoDB: header check field is"
507
" %lx but trailer %lx\n",
509
(ulint)field, len, check_field,
510
mem_field_trailer_get_check(
516
/* Move to next field */
517
field = field + MEM_SPACE_NEEDED(len);
519
if (top && (field == top)) {
526
/* At the end check that we have arrived to the first free
529
if (field != (byte*)block + mem_block_get_free(block)) {
533
"InnoDB: Error: block %lx end of"
535
"InnoDB: but block free at %lx\n",
536
(ulint)block, (ulint)field,
538
+ mem_block_get_free(block)));
545
block = UT_LIST_GET_NEXT(list, block);
548
#ifdef UNIV_MEM_DEBUG
551
if (us_size != NULL) {
552
*us_size = total_len;
554
if (ph_size != NULL) {
557
if (n_blocks != NULL) {
558
*n_blocks = block_count;
563
/******************************************************************
564
Prints the contents of a memory heap. */
569
mem_heap_t* heap) /* in: memory heap */
576
ut_ad(mem_heap_check(heap));
578
mem_heap_validate_or_print(heap, NULL, TRUE, &error,
579
&us_size, &phys_size, &n_blocks);
581
"\nheap type: %lu; size: user size %lu;"
582
" physical size %lu; blocks %lu.\n",
583
(ulong) heap->type, (ulong) us_size,
584
(ulong) phys_size, (ulong) n_blocks);
588
/******************************************************************
589
Validates the contents of a memory heap. */
594
/* out: TRUE if ok */
595
mem_heap_t* heap) /* in: memory heap */
602
ut_ad(mem_heap_check(heap));
604
mem_heap_validate_or_print(heap, NULL, FALSE, &error, &us_size,
605
&phys_size, &n_blocks);
607
mem_heap_print(heap);
614
#endif /* UNIV_MEM_DEBUG || UNIV_DEBUG */
617
/******************************************************************
618
Checks that an object is a memory heap (or a block of it). */
623
/* out: TRUE if ok */
624
mem_heap_t* heap) /* in: memory heap */
626
ut_a(heap->magic_n == MEM_BLOCK_MAGIC_N);
630
#endif /* UNIV_DEBUG */
632
#ifdef UNIV_MEM_DEBUG
633
/*********************************************************************
634
TRUE if no memory is currently allocated. */
639
/* out: TRUE if no heaps exist */
641
mem_hash_node_t* node;
642
ulint heap_count = 0;
647
mutex_enter(&mem_hash_mutex);
649
for (i = 0; i < MEM_HASH_SIZE; i++) {
651
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
652
while (node != NULL) {
654
node = UT_LIST_GET_NEXT(list, node);
658
mutex_exit(&mem_hash_mutex);
660
if (heap_count == 0) {
662
ut_a(mem_pool_get_reserved(mem_comm_pool) == 0);
670
/*********************************************************************
671
Validates the dynamic memory allocation system. */
674
mem_validate_no_assert(void)
675
/*========================*/
676
/* out: TRUE if error */
678
mem_hash_node_t* node;
682
ulint total_allocated_mem = 0;
687
mem_pool_validate(mem_comm_pool);
689
mutex_enter(&mem_hash_mutex);
691
for (i = 0; i < MEM_HASH_SIZE; i++) {
693
node = UT_LIST_GET_FIRST(*mem_hash_get_nth_cell(i));
695
while (node != NULL) {
698
mem_heap_validate_or_print(node->heap, NULL,
701
&ph_size, &n_blocks);
705
"\nERROR!!!!!!!!!!!!!!!!!!!"
706
"!!!!!!!!!!!!!!!!!!!!!!!\n\n"
707
"Inconsistency in memory heap"
708
" or buffer created\n"
710
node->file_name, node->line);
712
mutex_exit(&mem_hash_mutex);
717
total_allocated_mem += allocated_mem;
718
node = UT_LIST_GET_NEXT(list, node);
722
if ((n_heaps == 0) && (mem_current_allocated_memory != 0)) {
726
if (mem_total_allocated_memory < mem_current_allocated_memory) {
730
if (mem_max_allocated_memory > mem_total_allocated_memory) {
734
if (mem_n_created_heaps < n_heaps) {
738
mutex_exit(&mem_hash_mutex);
743
/****************************************************************
744
Validates the dynamic memory */
749
/* out: TRUE if ok */
751
ut_a(!mem_validate_no_assert());
755
#endif /* UNIV_MEM_DEBUG */
757
/****************************************************************
758
Tries to find neigboring memory allocation blocks and dumps to stderr
759
the neighborhood of a given pointer. */
762
mem_analyze_corruption(
763
/*===================*/
764
void* ptr) /* in: pointer to place of possible corruption */
770
fputs("InnoDB: Apparent memory corruption: mem dump ", stderr);
771
ut_print_buf(stderr, (byte*)ptr - 250, 500);
773
fputs("\nInnoDB: Scanning backward trying to find"
774
" previous allocated mem blocks\n", stderr);
779
for (i = 0; i < 10; i++) {
781
if (((ulint)p) % 4 == 0) {
783
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
785
"Mem block at - %lu,"
786
" file %s, line %lu\n",
796
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
798
"Freed mem block at - %lu,"
799
" file %s, line %lu\n",
819
"InnoDB: Scanning forward trying to find next"
820
" allocated mem blocks\n");
825
for (i = 0; i < 10; i++) {
827
if (((ulint)p) % 4 == 0) {
829
if (*((ulint*)p) == MEM_BLOCK_MAGIC_N) {
831
"Mem block at + %lu, file %s,"
842
if (*((ulint*)p) == MEM_FREED_BLOCK_MAGIC_N) {
844
"Freed mem block at + %lu,"
845
" file %s, line %lu\n",
865
/*********************************************************************
866
Prints information of dynamic memory usage and currently allocated
867
memory heaps or buffers. Can only be used in the debug version. */
872
ibool print_all) /* in: if TRUE, all heaps are printed,
873
else only the heaps allocated after the
874
previous call of this function */
876
#ifdef UNIV_MEM_DEBUG
877
mem_hash_node_t* node;
881
ulint total_allocated_mem = 0;
887
/* outfile = fopen("ibdebug", "a"); */
891
fprintf(outfile, "\n");
893
"________________________________________________________\n");
894
fprintf(outfile, "MEMORY ALLOCATION INFORMATION\n\n");
896
#ifndef UNIV_MEM_DEBUG
898
UT_NOT_USED(print_all);
900
mem_pool_print_info(outfile, mem_comm_pool);
903
"Sorry, non-debug version cannot give more memory info\n");
905
/* fclose(outfile); */
909
mutex_enter(&mem_hash_mutex);
911
fprintf(outfile, "LIST OF CREATED HEAPS AND ALLOCATED BUFFERS: \n\n");
914
fprintf(outfile, "AFTER THE LAST PRINT INFO\n");
917
node = UT_LIST_GET_FIRST(mem_all_list_base);
919
while (node != NULL) {
922
if (!print_all && node->nth_heap < mem_last_print_info) {
927
mem_heap_validate_or_print(node->heap, NULL,
928
FALSE, &error, &allocated_mem,
929
&ph_size, &n_blocks);
930
total_allocated_mem += allocated_mem;
933
"%lu: file %s line %lu of size %lu phys.size %lu"
934
" with %lu blocks, type %lu\n",
935
node->nth_heap, node->file_name, node->line,
936
allocated_mem, ph_size, n_blocks,
939
node = UT_LIST_GET_NEXT(all_list, node);
942
fprintf(outfile, "\n");
944
fprintf(outfile, "Current allocated memory : %lu\n",
945
mem_current_allocated_memory);
946
fprintf(outfile, "Current allocated heaps and buffers : %lu\n",
948
fprintf(outfile, "Cumulative allocated memory : %lu\n",
949
mem_total_allocated_memory);
950
fprintf(outfile, "Maximum allocated memory : %lu\n",
951
mem_max_allocated_memory);
952
fprintf(outfile, "Cumulative created heaps and buffers : %lu\n",
953
mem_n_created_heaps);
954
fprintf(outfile, "Cumulative number of allocations : %lu\n",
957
mem_last_print_info = mem_n_created_heaps;
959
mutex_exit(&mem_hash_mutex);
961
mem_pool_print_info(outfile, mem_comm_pool);
963
/* mem_validate(); */
965
/* fclose(outfile); */
969
/*********************************************************************
970
Prints information of dynamic memory usage and currently allocated memory
971
heaps or buffers. Can only be used in the debug version. */
977
mem_print_info_low(TRUE);
980
/*********************************************************************
981
Prints information of dynamic memory usage and currently allocated memory
982
heaps or buffers since the last ..._print_info or..._print_new_info. */
985
mem_print_new_info(void)
986
/*====================*/
988
mem_print_info_low(FALSE);