media/libnestegg/src/halloc.c

Tue, 06 Jan 2015 21:39:09 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Tue, 06 Jan 2015 21:39:09 +0100
branch
TOR_BUG_9701
changeset 8
97036ab72558
permissions
-rw-r--r--

Conditionally force memory storage according to privacy.thirdparty.isolate;
This solves Tor bug #9701, complying with disk avoidance documented in
https://www.torproject.org/projects/torbrowser/design/#disk-avoidance.

michael@0 1 /*
michael@0 2 * Copyright (c) 2004i-2010 Alex Pankratov. All rights reserved.
michael@0 3 *
michael@0 4 * Hierarchical memory allocator, 1.2.1
michael@0 5 * http://swapped.cc/halloc
michael@0 6 */
michael@0 7
michael@0 8 /*
michael@0 9 * The program is distributed under terms of BSD license.
michael@0 10 * You can obtain the copy of the license by visiting:
michael@0 11 *
michael@0 12 * http://www.opensource.org/licenses/bsd-license.php
michael@0 13 */
michael@0 14
michael@0 15 #include <stdlib.h> /* realloc */
michael@0 16 #include <string.h> /* memset & co */
michael@0 17
michael@0 18 #include "halloc.h"
michael@0 19 #include "align.h"
michael@0 20 #include "hlist.h"
michael@0 21
michael@0 22 /*
michael@0 23 * block control header
michael@0 24 */
michael@0 25 typedef struct hblock
michael@0 26 {
michael@0 27 #ifndef NDEBUG
michael@0 28 #define HH_MAGIC 0x20040518L
michael@0 29 long magic;
michael@0 30 #endif
michael@0 31 hlist_item_t siblings; /* 2 pointers */
michael@0 32 hlist_head_t children; /* 1 pointer */
michael@0 33 max_align_t data[1]; /* not allocated, see below */
michael@0 34
michael@0 35 } hblock_t;
michael@0 36
michael@0 37 #define sizeof_hblock offsetof(hblock_t, data)
michael@0 38
michael@0 39 /*
michael@0 40 *
michael@0 41 */
michael@0 42 realloc_t halloc_allocator = NULL;
michael@0 43
michael@0 44 #define allocator halloc_allocator
michael@0 45
michael@0 46 /*
michael@0 47 * static methods
michael@0 48 */
michael@0 49 static void _set_allocator(void);
michael@0 50 static void * _realloc(void * ptr, size_t n);
michael@0 51
michael@0 52 static int _relate(hblock_t * b, hblock_t * p);
michael@0 53 static void _free_children(hblock_t * p);
michael@0 54
michael@0 55 /*
michael@0 56 * Core API
michael@0 57 */
michael@0 58 void * halloc(void * ptr, size_t len)
michael@0 59 {
michael@0 60 hblock_t * p;
michael@0 61
michael@0 62 /* set up default allocator */
michael@0 63 if (! allocator)
michael@0 64 {
michael@0 65 _set_allocator();
michael@0 66 assert(allocator);
michael@0 67 }
michael@0 68
michael@0 69 /* calloc */
michael@0 70 if (! ptr)
michael@0 71 {
michael@0 72 if (! len)
michael@0 73 return NULL;
michael@0 74
michael@0 75 p = allocator(0, len + sizeof_hblock);
michael@0 76 if (! p)
michael@0 77 return NULL;
michael@0 78 #ifndef NDEBUG
michael@0 79 p->magic = HH_MAGIC;
michael@0 80 #endif
michael@0 81 hlist_init(&p->children);
michael@0 82 hlist_init_item(&p->siblings);
michael@0 83
michael@0 84 return p->data;
michael@0 85 }
michael@0 86
michael@0 87 p = structof(ptr, hblock_t, data);
michael@0 88 assert(p->magic == HH_MAGIC);
michael@0 89
michael@0 90 /* realloc */
michael@0 91 if (len)
michael@0 92 {
michael@0 93 p = allocator(p, len + sizeof_hblock);
michael@0 94 if (! p)
michael@0 95 return NULL;
michael@0 96
michael@0 97 hlist_relink(&p->siblings);
michael@0 98 hlist_relink_head(&p->children);
michael@0 99
michael@0 100 return p->data;
michael@0 101 }
michael@0 102
michael@0 103 /* free */
michael@0 104 _free_children(p);
michael@0 105 hlist_del(&p->siblings);
michael@0 106 allocator(p, 0);
michael@0 107
michael@0 108 return NULL;
michael@0 109 }
michael@0 110
michael@0 111 void hattach(void * block, void * parent)
michael@0 112 {
michael@0 113 hblock_t * b, * p;
michael@0 114
michael@0 115 if (! block)
michael@0 116 {
michael@0 117 assert(! parent);
michael@0 118 return;
michael@0 119 }
michael@0 120
michael@0 121 /* detach */
michael@0 122 b = structof(block, hblock_t, data);
michael@0 123 assert(b->magic == HH_MAGIC);
michael@0 124
michael@0 125 hlist_del(&b->siblings);
michael@0 126
michael@0 127 if (! parent)
michael@0 128 return;
michael@0 129
michael@0 130 /* attach */
michael@0 131 p = structof(parent, hblock_t, data);
michael@0 132 assert(p->magic == HH_MAGIC);
michael@0 133
michael@0 134 /* sanity checks */
michael@0 135 assert(b != p); /* trivial */
michael@0 136 assert(! _relate(p, b)); /* heavy ! */
michael@0 137
michael@0 138 hlist_add(&p->children, &b->siblings);
michael@0 139 }
michael@0 140
michael@0 141 /*
michael@0 142 * malloc/free api
michael@0 143 */
michael@0 144 void * h_malloc(size_t len)
michael@0 145 {
michael@0 146 return halloc(0, len);
michael@0 147 }
michael@0 148
michael@0 149 void * h_calloc(size_t n, size_t len)
michael@0 150 {
michael@0 151 void * ptr = halloc(0, len*=n);
michael@0 152 return ptr ? memset(ptr, 0, len) : NULL;
michael@0 153 }
michael@0 154
michael@0 155 void * h_realloc(void * ptr, size_t len)
michael@0 156 {
michael@0 157 return halloc(ptr, len);
michael@0 158 }
michael@0 159
michael@0 160 void h_free(void * ptr)
michael@0 161 {
michael@0 162 halloc(ptr, 0);
michael@0 163 }
michael@0 164
michael@0 165 char * h_strdup(const char * str)
michael@0 166 {
michael@0 167 size_t len = strlen(str);
michael@0 168 char * ptr = halloc(0, len + 1);
michael@0 169 return ptr ? (ptr[len] = 0, memcpy(ptr, str, len)) : NULL;
michael@0 170 }
michael@0 171
michael@0 172 /*
michael@0 173 * static stuff
michael@0 174 */
michael@0 175 static void _set_allocator(void)
michael@0 176 {
michael@0 177 void * p;
michael@0 178 assert(! allocator);
michael@0 179
michael@0 180 /*
michael@0 181 * the purpose of the test below is to check the behaviour
michael@0 182 * of realloc(ptr, 0), which is defined in the standard
michael@0 183 * as an implementation-specific. if it returns zero,
michael@0 184 * then it's equivalent to free(). it can however return
michael@0 185 * non-zero, in which case it cannot be used for freeing
michael@0 186 * memory blocks and we'll need to supply our own version
michael@0 187 *
michael@0 188 * Thanks to Stan Tobias for pointing this tricky part out.
michael@0 189 */
michael@0 190 allocator = realloc;
michael@0 191 if (! (p = malloc(1)))
michael@0 192 /* hmm */
michael@0 193 return;
michael@0 194
michael@0 195 if ((p = realloc(p, 0)))
michael@0 196 {
michael@0 197 /* realloc cannot be used as free() */
michael@0 198 allocator = _realloc;
michael@0 199 free(p);
michael@0 200 }
michael@0 201 }
michael@0 202
michael@0 203 static void * _realloc(void * ptr, size_t n)
michael@0 204 {
michael@0 205 /*
michael@0 206 * free'ing realloc()
michael@0 207 */
michael@0 208 if (n)
michael@0 209 return realloc(ptr, n);
michael@0 210 free(ptr);
michael@0 211 return NULL;
michael@0 212 }
michael@0 213
michael@0 214 static int _relate(hblock_t * b, hblock_t * p)
michael@0 215 {
michael@0 216 hlist_item_t * i;
michael@0 217
michael@0 218 if (!b || !p)
michael@0 219 return 0;
michael@0 220
michael@0 221 /*
michael@0 222 * since there is no 'parent' pointer, which would've allowed
michael@0 223 * O(log(n)) upward traversal, the check must use O(n) downward
michael@0 224 * iteration of the entire hierarchy; and this can be VERY SLOW
michael@0 225 */
michael@0 226 hlist_for_each(i, &p->children)
michael@0 227 {
michael@0 228 hblock_t * q = structof(i, hblock_t, siblings);
michael@0 229 if (q == b || _relate(b, q))
michael@0 230 return 1;
michael@0 231 }
michael@0 232 return 0;
michael@0 233 }
michael@0 234
michael@0 235 static void _free_children(hblock_t * p)
michael@0 236 {
michael@0 237 hlist_item_t * i, * tmp;
michael@0 238
michael@0 239 #ifndef NDEBUG
michael@0 240 /*
michael@0 241 * this catches loops in hierarchy with almost zero
michael@0 242 * overhead (compared to _relate() running time)
michael@0 243 */
michael@0 244 assert(p && p->magic == HH_MAGIC);
michael@0 245 p->magic = 0;
michael@0 246 #endif
michael@0 247 hlist_for_each_safe(i, tmp, &p->children)
michael@0 248 {
michael@0 249 hblock_t * q = structof(i, hblock_t, siblings);
michael@0 250 _free_children(q);
michael@0 251 allocator(q, 0);
michael@0 252 }
michael@0 253 }
michael@0 254

mercurial