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