1 /*- 2 * Copyright 2009 3 * Thorsten Glaser <tg (at) mirbsd.org> 4 * 5 * Provided that these terms and disclaimer and all copyright notices 6 * are retained or reproduced in an accompanying document, permission 7 * is granted to deal in this work without restriction, including un 8 * limited rights to use, publicly perform, distribute, sell, modify, 9 * merge, give away, or sublicence. 10 * 11 * This work is provided AS IS and WITHOUT WARRANTY of any kind, to 12 * the utmost extent permitted by applicable law, neither express nor 13 * implied; without malicious intent or gross negligence. In no event 14 * may a licensor, author or contributor be held liable for indirect, 15 * direct, other damage, loss, or other issues arising in any way out 16 * of dealing in the work, even if advised of the possibility of such 17 * damage or existence of a defect, except proven that it results out 18 * of said persons immediate fault when using the work as intended. 19 */ 20 21 #include "sh.h" 22 23 __RCSID("$MirOS: src/bin/mksh/lalloc.c,v 1.11 2009/08/08 13:08:51 tg Exp $"); 24 25 /* build with CPPFLAGS+= -DUSE_REALLOC_MALLOC=0 on ancient systems */ 26 #if defined(USE_REALLOC_MALLOC) && (USE_REALLOC_MALLOC == 0) 27 #define remalloc(p,n) ((p) == NULL ? malloc(n) : realloc((p), (n))) 28 #else 29 #define remalloc(p,n) realloc((p), (n)) 30 #endif 31 32 #define ALLOC_ISUNALIGNED(p) (((ptrdiff_t)(p)) % ALLOC_SIZE) 33 34 static ALLOC_ITEM *findptr(ALLOC_ITEM **, char *, Area *); 35 36 void 37 ainit(Area *ap) 38 { 39 /* area pointer is an ALLOC_ITEM, just the head of the list */ 40 ap->next = NULL; 41 } 42 43 static ALLOC_ITEM * 44 findptr(ALLOC_ITEM **lpp, char *ptr, Area *ap) 45 { 46 void *lp; 47 48 #ifndef MKSH_SMALL 49 if (ALLOC_ISUNALIGNED(ptr)) 50 goto fail; 51 #endif 52 /* get address of ALLOC_ITEM from user item */ 53 /* 54 * note: the alignment of "ptr" to ALLOC_SIZE is checked 55 * above; the "void *" gets us rid of a gcc 2.95 warning 56 */ 57 *lpp = (lp = ptr - ALLOC_SIZE); 58 /* search for allocation item in group list */ 59 while (ap->next != lp) 60 if ((ap = ap->next) == NULL) { 61 #ifndef MKSH_SMALL 62 fail: 63 #endif 64 internal_errorf("rogue pointer %p", ptr); 65 } 66 return (ap); 67 } 68 69 void * 70 aresize(void *ptr, size_t numb, Area *ap) 71 { 72 ALLOC_ITEM *lp = NULL; 73 74 /* resizing (true) or newly allocating? */ 75 if (ptr != NULL) { 76 ALLOC_ITEM *pp; 77 78 pp = findptr(&lp, ptr, ap); 79 pp->next = lp->next; 80 } 81 82 if ((numb >= SIZE_MAX - ALLOC_SIZE) || 83 (lp = remalloc(lp, numb + ALLOC_SIZE)) == NULL 84 #ifndef MKSH_SMALL 85 || ALLOC_ISUNALIGNED(lp) 86 #endif 87 ) 88 internal_errorf("cannot allocate %lu data bytes", 89 (unsigned long)numb); 90 /* this only works because Area is an ALLOC_ITEM */ 91 lp->next = ap->next; 92 ap->next = lp; 93 /* return user item address */ 94 return ((char *)lp + ALLOC_SIZE); 95 } 96 97 void 98 afree(void *ptr, Area *ap) 99 { 100 if (ptr != NULL) { 101 ALLOC_ITEM *lp, *pp; 102 103 pp = findptr(&lp, ptr, ap); 104 /* unhook */ 105 pp->next = lp->next; 106 /* now free ALLOC_ITEM */ 107 free(lp); 108 } 109 } 110 111 void 112 afreeall(Area *ap) 113 { 114 ALLOC_ITEM *lp; 115 116 /* traverse group (linked list) */ 117 while ((lp = ap->next) != NULL) { 118 /* make next ALLOC_ITEM head of list */ 119 ap->next = lp->next; 120 /* free old head */ 121 free(lp); 122 } 123 } 124