loksh-noxz

[fork] a Linux port of OpenBSD's ksh
git clone https://noxz.tech/git/loksh-noxz.git
Log | Files | README

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