1/* TMP_ALLOC routines for debugging. 2 3Copyright 2000, 2001, 2004 Free Software Foundation, Inc. 4 5This file is part of the GNU MP Library. 6 7The GNU MP Library is free software; you can redistribute it and/or modify 8it under the terms of the GNU Lesser General Public License as published by 9the Free Software Foundation; either version 3 of the License, or (at your 10option) any later version. 11 12The GNU MP Library is distributed in the hope that it will be useful, but 13WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 14or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public 15License for more details. 16 17You should have received a copy of the GNU Lesser General Public License 18along with the GNU MP Library. If not, see http://www.gnu.org/licenses/. */ 19 20#include <stdio.h> 21#include <stdlib.h> 22#include <string.h> 23#include "gmp.h" 24#include "gmp-impl.h" 25 26 27/* This method aims to help a malloc debugger find problems. A linked list 28 of allocated block is kept for TMP_FREE to release. This is reentrant 29 and thread safe. 30 31 Each TMP_ALLOC is a separate malloced block, so redzones or sentinels 32 applied by a malloc debugger either above or below can guard against 33 accesses outside the allocated area. 34 35 A marker is a "struct tmp_debug_t *" so that TMP_DECL can initialize it 36 to NULL and we can detect TMP_ALLOC without TMP_MARK. 37 38 It will work to realloc an MPZ_TMP_INIT variable, but when TMP_FREE comes 39 to release the memory it will have the old size, thereby triggering an 40 error from tests/memory.c. 41 42 Possibilities: 43 44 It'd be possible to keep a global list of active "struct tmp_debug_t" 45 records, so at the end of a program any TMP leaks could be printed. But 46 if only a couple of routines are under test at any one time then the 47 likely culprit should be easy enough to spot. */ 48 49 50void 51__gmp_tmp_debug_mark (const char *file, int line, 52 struct tmp_debug_t **markp, struct tmp_debug_t *mark, 53 const char *decl_name, const char *mark_name) 54{ 55 if (strcmp (mark_name, decl_name) != 0) 56 { 57 __gmp_assert_header (file, line); 58 fprintf (stderr, "GNU MP: TMP_MARK(%s) but TMP_DECL(%s) is in scope\n", 59 mark_name, decl_name); 60 abort (); 61 } 62 63 if (*markp != NULL) 64 { 65 __gmp_assert_header (file, line); 66 fprintf (stderr, "GNU MP: Repeat of TMP_MARK(%s)\n", mark_name); 67 if (mark->file != NULL && mark->file[0] != '\0' && mark->line != -1) 68 { 69 __gmp_assert_header (mark->file, mark->line); 70 fprintf (stderr, "previous was here\n"); 71 } 72 abort (); 73 } 74 75 *markp = mark; 76 mark->file = file; 77 mark->line = line; 78 mark->list = NULL; 79} 80 81void * 82__gmp_tmp_debug_alloc (const char *file, int line, int dummy, 83 struct tmp_debug_t **markp, 84 const char *decl_name, size_t size) 85{ 86 struct tmp_debug_t *mark = *markp; 87 struct tmp_debug_entry_t *p; 88 89 ASSERT_ALWAYS (size >= 1); 90 91 if (mark == NULL) 92 { 93 __gmp_assert_header (file, line); 94 fprintf (stderr, "GNU MP: TMP_ALLOC without TMP_MARK(%s)\n", decl_name); 95 abort (); 96 } 97 98 p = __GMP_ALLOCATE_FUNC_TYPE (1, struct tmp_debug_entry_t); 99 p->size = size; 100 p->block = (*__gmp_allocate_func) (size); 101 p->next = mark->list; 102 mark->list = p; 103 return p->block; 104} 105 106void 107__gmp_tmp_debug_free (const char *file, int line, int dummy, 108 struct tmp_debug_t **markp, 109 const char *decl_name, const char *free_name) 110{ 111 struct tmp_debug_t *mark = *markp; 112 struct tmp_debug_entry_t *p, *next; 113 114 if (mark == NULL) 115 { 116 __gmp_assert_header (file, line); 117 fprintf (stderr, "GNU MP: TMP_FREE(%s) without TMP_MARK(%s)\n", 118 free_name, decl_name); 119 abort (); 120 } 121 122 if (strcmp (free_name, decl_name) != 0) 123 { 124 __gmp_assert_header (file, line); 125 fprintf (stderr, "GNU MP: TMP_FREE(%s) when TMP_DECL(%s) is in scope\n", 126 free_name, decl_name); 127 abort (); 128 } 129 130 p = mark->list; 131 while (p != NULL) 132 { 133 next = p->next; 134 (*__gmp_free_func) (p->block, p->size); 135 __GMP_FREE_FUNC_TYPE (p, 1, struct tmp_debug_entry_t); 136 p = next; 137 } 138 139 *markp = NULL; 140} 141