(root)/
gmp-6.3.0/
tal-debug.c
       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  }