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