xref: /openbsd/bin/ksh/alloc.c (revision 6c72b531)
1*6c72b531Sjca /*	$OpenBSD: alloc.c,v 1.19 2018/01/16 22:52:32 jca Exp $	*/
259bf25f9Sespie 
359bf25f9Sespie /* Public domain, like most of the rest of ksh */
47cb960a2Sdownsj 
57cb960a2Sdownsj /*
67cb960a2Sdownsj  * area-based allocation built on malloc/free
77cb960a2Sdownsj  */
87cb960a2Sdownsj 
9322c3a8aSmmcc #include <stdint.h>
104a010e0cStb #include <stdlib.h>
11b608f594Smmcc 
127cb960a2Sdownsj #include "sh.h"
137cb960a2Sdownsj 
145c55448cSespie struct link {
155c55448cSespie 	struct link *prev;
165c55448cSespie 	struct link *next;
175c55448cSespie };
183b015934Smillert 
193b015934Smillert Area *
ainit(Area * ap)205c55448cSespie ainit(Area *ap)
213b015934Smillert {
225c55448cSespie 	ap->freelist = NULL;
233b015934Smillert 	return ap;
243b015934Smillert }
253b015934Smillert 
263b015934Smillert void
afreeall(Area * ap)275c55448cSespie afreeall(Area *ap)
283b015934Smillert {
295c55448cSespie 	struct link *l, *l2;
305c55448cSespie 
315c55448cSespie 	for (l = ap->freelist; l != NULL; l = l2) {
325c55448cSespie 		l2 = l->next;
335c55448cSespie 		free(l);
345c55448cSespie 	}
355c55448cSespie 	ap->freelist = NULL;
363b015934Smillert }
373b015934Smillert 
385c55448cSespie #define L2P(l)	( (void *)(((char *)(l)) + sizeof(struct link)) )
395c55448cSespie #define P2L(p)	( (struct link *)(((char *)(p)) - sizeof(struct link)) )
405c55448cSespie 
413b015934Smillert void *
alloc(size_t size,Area * ap)425c55448cSespie alloc(size_t size, Area *ap)
433b015934Smillert {
445c55448cSespie 	struct link *l;
455c55448cSespie 
46a6a9e28aSmmcc 	/* ensure that we don't overflow by allocating space for link */
47a6a9e28aSmmcc 	if (size > SIZE_MAX - sizeof(struct link))
48*6c72b531Sjca 		internal_errorf("unable to allocate memory");
49a6a9e28aSmmcc 
50e1b6fda6Stb 	l = malloc(sizeof(struct link) + size);
5108d672a4Smillert 	if (l == NULL)
52*6c72b531Sjca 		internal_errorf("unable to allocate memory");
535c55448cSespie 	l->next = ap->freelist;
545c55448cSespie 	l->prev = NULL;
555c55448cSespie 	if (ap->freelist)
565c55448cSespie 		ap->freelist->prev = l;
575c55448cSespie 	ap->freelist = l;
585c55448cSespie 
595c55448cSespie 	return L2P(l);
603b015934Smillert }
613b015934Smillert 
62322c3a8aSmmcc /*
63322c3a8aSmmcc  * Copied from calloc().
64322c3a8aSmmcc  *
65322c3a8aSmmcc  * This is sqrt(SIZE_MAX+1), as s1*s2 <= SIZE_MAX
66322c3a8aSmmcc  * if both s1 < MUL_NO_OVERFLOW and s2 < MUL_NO_OVERFLOW
67322c3a8aSmmcc  */
68322c3a8aSmmcc #define MUL_NO_OVERFLOW	(1UL << (sizeof(size_t) * 4))
69322c3a8aSmmcc 
70322c3a8aSmmcc void *
areallocarray(void * ptr,size_t nmemb,size_t size,Area * ap)71f05e5426Smmcc areallocarray(void *ptr, size_t nmemb, size_t size, Area *ap)
72322c3a8aSmmcc {
73322c3a8aSmmcc 	/* condition logic cloned from calloc() */
74322c3a8aSmmcc 	if ((nmemb >= MUL_NO_OVERFLOW || size >= MUL_NO_OVERFLOW) &&
75322c3a8aSmmcc 	    nmemb > 0 && SIZE_MAX / nmemb < size) {
76*6c72b531Sjca 		internal_errorf("unable to allocate memory");
77322c3a8aSmmcc 	}
78322c3a8aSmmcc 
79f05e5426Smmcc 	return aresize(ptr, nmemb * size, ap);
80322c3a8aSmmcc }
81322c3a8aSmmcc 
823b015934Smillert void *
aresize(void * ptr,size_t size,Area * ap)835c55448cSespie aresize(void *ptr, size_t size, Area *ap)
843b015934Smillert {
855c55448cSespie 	struct link *l, *l2, *lprev, *lnext;
865c55448cSespie 
875c55448cSespie 	if (ptr == NULL)
885c55448cSespie 		return alloc(size, ap);
895c55448cSespie 
904f0a1b90Smmcc 	/* ensure that we don't overflow by allocating space for link */
914f0a1b90Smmcc 	if (size > SIZE_MAX - sizeof(struct link))
92*6c72b531Sjca 		internal_errorf("unable to allocate memory");
934f0a1b90Smmcc 
945c55448cSespie 	l = P2L(ptr);
955c55448cSespie 	lprev = l->prev;
965c55448cSespie 	lnext = l->next;
975c55448cSespie 
982c71ba4cSderaadt 	l2 = realloc(l, sizeof(struct link) + size);
9908d672a4Smillert 	if (l2 == NULL)
100*6c72b531Sjca 		internal_errorf("unable to allocate memory");
1015c55448cSespie 	if (lprev)
1025c55448cSespie 		lprev->next = l2;
1035c55448cSespie 	else
1045c55448cSespie 		ap->freelist = l2;
1055c55448cSespie 	if (lnext)
1065c55448cSespie 		lnext->prev = l2;
10708d672a4Smillert 
1085c55448cSespie 	return L2P(l2);
1095c55448cSespie }
1105c55448cSespie 
1115c55448cSespie void
afree(void * ptr,Area * ap)1125c55448cSespie afree(void *ptr, Area *ap)
1135c55448cSespie {
114526c36bdSjca 	struct link *l;
1155c55448cSespie 
1163b015934Smillert 	if (!ptr)
1175c55448cSespie 		return;
1185c55448cSespie 
1195c55448cSespie 	l = P2L(ptr);
1205c55448cSespie 	if (l->prev)
1215c55448cSespie 		l->prev->next = l->next;
1223b015934Smillert 	else
1235c55448cSespie 		ap->freelist = l->next;
1245c55448cSespie 	if (l->next)
1255c55448cSespie 		l->next->prev = l->prev;
1263b015934Smillert 
1275c55448cSespie 	free(l);
1287cb960a2Sdownsj }
129