-
Notifications
You must be signed in to change notification settings - Fork 6
/
alloc.c
128 lines (102 loc) · 2.32 KB
/
alloc.c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
/* $OpenBSD: alloc.c,v 1.19 2018/01/16 22:52:32 jca Exp $ */
/* Public domain, like most of the rest of ksh */
/*
* area-based allocation built on malloc/free
*/
#include <stdint.h>
#include <stdlib.h>
#include "sh.h"
struct link {
struct link *prev;
struct link *next;
};
Area *
ainit(Area *ap)
{
ap->freelist = NULL;
return ap;
}
void
afreeall(Area *ap)
{
struct link *l, *l2;
for (l = ap->freelist; l != NULL; l = l2) {
l2 = l->next;
free(l);
}
ap->freelist = NULL;
}
#define L2P(l) ( (void *)(((char *)(l)) + sizeof(struct link)) )
#define P2L(p) ( (struct link *)(((char *)(p)) - sizeof(struct link)) )
void *
alloc(size_t size, Area *ap)
{
struct link *l;
/* ensure that we don't overflow by allocating space for link */
if (size > SIZE_MAX - sizeof(struct link))
internal_errorf("unable to allocate memory");
l = malloc(sizeof(struct link) + size);
if (l == NULL)
internal_errorf("unable to allocate memory");
l->next = ap->freelist;
l->prev = NULL;
if (ap->freelist)
ap->freelist->prev = l;
ap->freelist = l;
return L2P(l);
}
/*
* Copied from calloc().
*
* This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
* if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
*/
#define MUL_NO_OVERFLOW (1UL << (sizeof(size_t) * 4))
void *
areallocarray(void *ptr, size_t nmemb, size_t size, Area *ap)
{
/* condition logic cloned from calloc() */
if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
nmemb > 0 && SIZE_MAX / nmemb < size) {
internal_errorf("unable to allocate memory");
}
return aresize(ptr, nmemb * size, ap);
}
void *
aresize(void *ptr, size_t size, Area *ap)
{
struct link *l, *l2, *lprev, *lnext;
if (ptr == NULL)
return alloc(size, ap);
/* ensure that we don't overflow by allocating space for link */
if (size > SIZE_MAX - sizeof(struct link))
internal_errorf("unable to allocate memory");
l = P2L(ptr);
lprev = l->prev;
lnext = l->next;
l2 = realloc(l, sizeof(struct link) + size);
if (l2 == NULL)
internal_errorf("unable to allocate memory");
if (lprev)
lprev->next = l2;
else
ap->freelist = l2;
if (lnext)
lnext->prev = l2;
return L2P(l2);
}
void
afree(void *ptr, Area *ap)
{
struct link *l;
if (!ptr)
return;
l = P2L(ptr);
if (l->prev)
l->prev->next = l->next;
else
ap->freelist = l->next;
if (l->next)
l->next->prev = l->prev;
free(l);
}