Update Gnulib to the latest git version
[deliverable/binutils-gdb.git] / gnulib / import / malloca.c
CommitLineData
98399780 1/* Safe automatic memory allocation.
c0c3707f
CB
2 Copyright (C) 2003, 2006-2007, 2009-2019 Free Software Foundation, Inc.
3 Written by Bruno Haible <bruno@clisp.org>, 2003, 2018.
98399780
YQ
4
5 This program is free software; you can redistribute it and/or modify
6 it under the terms of the GNU General Public License as published by
7 the Free Software Foundation; either version 3, or (at your option)
8 any later version.
9
10 This program is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
c0c3707f 16 along with this program; if not, see <https://www.gnu.org/licenses/>. */
98399780
YQ
17
18#define _GL_USE_STDLIB_ALLOC 1
19#include <config.h>
20
21/* Specification. */
22#include "malloca.h"
23
98399780
YQ
24#include "verify.h"
25
26/* The speed critical point in this file is freea() applied to an alloca()
27 result: it must be fast, to match the speed of alloca(). The speed of
28 mmalloca() and freea() in the other case are not critical, because they
c0c3707f
CB
29 are only invoked for big memory sizes.
30 Here we use a bit in the address as an indicator, an idea by Ondřej Bílka.
31 malloca() can return three types of pointers:
32 - Pointers ≡ 0 mod 2*sa_alignment_max come from stack allocation.
33 - Pointers ≡ sa_alignment_max mod 2*sa_alignment_max come from heap
34 allocation.
35 - NULL comes from a failed heap allocation. */
36
37/* Type for holding very small pointer differences. */
38typedef unsigned char small_t;
39/* Verify that it is wide enough. */
40verify (2 * sa_alignment_max - 1 <= (small_t) -1);
98399780
YQ
41
42void *
43mmalloca (size_t n)
44{
45#if HAVE_ALLOCA
c0c3707f
CB
46 /* Allocate one more word, used to determine the address to pass to freea(),
47 and room for the alignment ≡ sa_alignment_max mod 2*sa_alignment_max. */
48 size_t nplus = n + sizeof (small_t) + 2 * sa_alignment_max - 1;
98399780
YQ
49
50 if (nplus >= n)
51 {
c0c3707f 52 char *mem = (char *) malloc (nplus);
98399780 53
c0c3707f 54 if (mem != NULL)
98399780 55 {
c0c3707f
CB
56 char *p =
57 (char *)((((uintptr_t)mem + sizeof (small_t) + sa_alignment_max - 1)
58 & ~(uintptr_t)(2 * sa_alignment_max - 1))
59 + sa_alignment_max);
60 /* Here p >= mem + sizeof (small_t),
61 and p <= mem + sizeof (small_t) + 2 * sa_alignment_max - 1
62 hence p + n <= mem + nplus.
63 So, the memory range [p, p+n) lies in the allocated memory range
64 [mem, mem + nplus). */
65 ((small_t *) p)[-1] = p - mem;
66 /* p ≡ sa_alignment_max mod 2*sa_alignment_max. */
98399780
YQ
67 return p;
68 }
69 }
70 /* Out of memory. */
71 return NULL;
72#else
73# if !MALLOC_0_IS_NONNULL
74 if (n == 0)
75 n = 1;
76# endif
77 return malloc (n);
78#endif
79}
80
81#if HAVE_ALLOCA
82void
83freea (void *p)
84{
c0c3707f
CB
85 /* Check argument. */
86 if ((uintptr_t) p & (sa_alignment_max - 1))
7a6dbc2f 87 {
c0c3707f
CB
88 /* p was not the result of a malloca() call. Invalid argument. */
89 abort ();
90 }
91 /* Determine whether p was a non-NULL pointer returned by mmalloca(). */
92 if ((uintptr_t) p & sa_alignment_max)
93 {
94 void *mem = (char *) p - ((small_t *) p)[-1];
95 free (mem);
98399780
YQ
96 }
97}
98#endif
c0c3707f
CB
99
100/*
101 * Hey Emacs!
102 * Local Variables:
103 * coding: utf-8
104 * End:
105 */
This page took 0.425626 seconds and 4 git commands to generate.