1/* 2 Samba Unix SMB/CIFS implementation. 3 Samba temporary memory allocation functions 4 Copyright (C) Andrew Tridgell 2000 5 Copyright (C) 2001, 2002 by Martin Pool <mbp@samba.org> 6 7 This program is free software; you can redistribute it and/or modify 8 it under the terms of the GNU General Public License as published by 9 the Free Software Foundation; either version 2 of the License, or 10 (at your option) any later version. 11 12 This program is distributed in the hope that it will be useful, 13 but WITHOUT ANY WARRANTY; without even the implied warranty of 14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 15 GNU General Public License for more details. 16 17 You should have received a copy of the GNU General Public License 18 along with this program; if not, write to the Free Software 19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 20*/ 21 22/** 23 @defgroup talloc Simple memory allocator 24 @{ 25 26 This is a very simple temporary memory allocator. To use it do the following: 27 28 1) when you first want to allocate a pool of meomry use 29 talloc_init() and save the resulting context pointer somewhere 30 31 2) to allocate memory use talloc() 32 33 3) when _all_ of the memory allocated using this context is no longer needed 34 use talloc_destroy() 35 36 talloc does not zero the memory. It guarantees memory of a 37 TALLOC_ALIGN alignment 38 39 @sa talloc.h 40*/ 41 42/** 43 * @todo We could allocate both the talloc_chunk structure, and the 44 * memory it contains all in one allocation, which might be a bit 45 * faster and perhaps use less memory overhead. 46 * 47 * That smells like a premature optimization, though. -- mbp 48 **/ 49 50/** 51 * If you want testing for memory corruption, link with dmalloc or use 52 * Insure++. It doesn't seem useful to duplicate them here. 53 **/ 54 55#include "includes.h" 56 57/* Max allowable allococation - 256mb - 0x10000000 */ 58#define MAX_TALLOC_SIZE (1024*1024*256) 59 60/** 61 * Start of linked list of all talloc pools. 62 * 63 * @todo We should turn the global list off when using Insure++, 64 * otherwise all the memory will be seen as still reachable. 65 **/ 66static TALLOC_CTX *list_head = NULL; 67 68 69/** 70 * Add to the global list 71 **/ 72static void talloc_enroll(TALLOC_CTX *t) 73{ 74 t->next_ctx = list_head; 75 list_head = t; 76} 77 78 79static void talloc_disenroll(TALLOC_CTX *t) 80{ 81 TALLOC_CTX **ttmp; 82 83 /* Use a double-* so that no special case is required for the 84 * list head. */ 85 for (ttmp = &list_head; *ttmp; ttmp = &((*ttmp)->next_ctx)) 86 if (*ttmp == t) { 87 /* ttmp is the link that points to t, either 88 * list_head or the next_ctx link in its 89 * predecessor */ 90 *ttmp = t->next_ctx; 91 t->next_ctx = NULL; /* clobber */ 92 return; 93 } 94 abort(); /* oops, this talloc was already 95 * clobbered or something else went 96 * wrong. */ 97} 98 99 100/** Create a new talloc context. **/ 101static TALLOC_CTX *talloc_init_internal(void) 102{ 103 TALLOC_CTX *t; 104 105 t = (TALLOC_CTX *)SMB_MALLOC(sizeof(TALLOC_CTX)); 106 if (t) { 107 t->list = NULL; 108 t->total_alloc_size = 0; 109 t->name = NULL; 110 talloc_enroll(t); 111 } 112 113 return t; 114} 115 116 117 118/** 119 * Create a new talloc context, with a name specifying its purpose. 120 **/ 121 122 TALLOC_CTX *talloc_init(char const *fmt, ...) 123{ 124 TALLOC_CTX *t; 125 va_list ap; 126 127 t = talloc_init_internal(); 128 if (t && fmt) { 129 /* 130 * t->name must not be talloced. 131 * as destroying the pool would destroy it. JRA. 132 */ 133 t->name = NULL; 134 va_start(ap, fmt); 135 vasprintf(&t->name, fmt, ap); 136 va_end(ap); 137 if (!t->name) { 138 talloc_destroy(t); 139 t = NULL; 140 } 141 } 142 143 return t; 144} 145 146 147/** Allocate a bit of memory from the specified pool **/ 148#if defined(PARANOID_MALLOC_CHECKER) 149void *talloc_(TALLOC_CTX *t, size_t size) 150#else 151void *talloc(TALLOC_CTX *t, size_t size) 152#endif 153{ 154 void *p; 155 struct talloc_chunk *tc; 156 157 if (!t || size == 0) return NULL; 158 159 p = SMB_MALLOC(size); 160 if (p) { 161 tc = SMB_MALLOC(sizeof(*tc)); 162 if (tc) { 163 tc->ptr = p; 164 tc->size = size; 165 tc->next = t->list; 166 t->list = tc; 167 t->total_alloc_size += size; 168 } 169 else { 170 SAFE_FREE(p); 171 } 172 } 173 return p; 174} 175 176/** Allocate an array of count elements of size x */ 177#if defined(PARANOID_MALLOC_CHECKER) 178void *talloc_array_(TALLOC_CTX *ctx, size_t el_size, unsigned int count) 179#else 180void *talloc_array(TALLOC_CTX *ctx, size_t el_size, unsigned int count) 181#endif 182{ 183 if (count >= MAX_TALLOC_SIZE/el_size) { 184 return NULL; 185 } 186 return TALLOC(ctx, el_size * count); 187} 188 189/** A talloc version of realloc */ 190#if defined(PARANOID_MALLOC_CHECKER) 191void *talloc_realloc_(TALLOC_CTX *t, void *ptr, size_t size) 192#else 193void *talloc_realloc(TALLOC_CTX *t, void *ptr, size_t size) 194#endif 195{ 196 struct talloc_chunk *tc; 197 void *new_ptr; 198 199 /* size zero is equivalent to free() */ 200 if (!t || size == 0) 201 return NULL; 202 203 /* realloc(NULL) is equavalent to malloc() */ 204 if (ptr == NULL) 205 return TALLOC(t, size); 206 207 for (tc=t->list; tc; tc=tc->next) { 208 if (tc->ptr == ptr) { 209 new_ptr = SMB_REALLOC(ptr, size); 210 if (new_ptr) { 211 t->total_alloc_size += (size - tc->size); 212 tc->size = size; 213 tc->ptr = new_ptr; 214 } 215 return new_ptr; 216 } 217 } 218 return NULL; 219} 220 221/** Re-allocate an array of count elements of size x */ 222#if defined(PARANOID_MALLOC_CHECKER) 223void *talloc_realloc_array_(TALLOC_CTX *ctx, void *ptr, size_t el_size, unsigned int count) 224#else 225void *talloc_realloc_array(TALLOC_CTX *ctx, void *ptr, size_t el_size, unsigned int count) 226#endif 227{ 228 if (count >= MAX_TALLOC_SIZE/el_size) { 229 return NULL; 230 } 231 return TALLOC_REALLOC(ctx, ptr, el_size * count); 232} 233 234/** Destroy all the memory allocated inside @p t, but not @p t 235 * itself. */ 236void talloc_destroy_pool(TALLOC_CTX *t) 237{ 238 struct talloc_chunk *c; 239 240 if (!t) 241 return; 242 243 while (t->list) { 244 c = t->list->next; 245 SAFE_FREE(t->list->ptr); 246 SAFE_FREE(t->list); 247 t->list = c; 248 } 249 250 t->total_alloc_size = 0; 251} 252 253/** Destroy a whole pool including the context */ 254void talloc_destroy(TALLOC_CTX *t) 255{ 256 if (!t) 257 return; 258 259 talloc_destroy_pool(t); 260 talloc_disenroll(t); 261 SAFE_FREE(t->name); 262 memset(t, 0, sizeof(TALLOC_CTX)); 263 SAFE_FREE(t); 264} 265 266/** Return the current total size of the pool. */ 267size_t talloc_pool_size(TALLOC_CTX *t) 268{ 269 if (t) 270 return t->total_alloc_size; 271 else 272 return 0; 273} 274 275const char * talloc_pool_name(TALLOC_CTX const *t) 276{ 277 if (t) 278 return t->name; 279 else 280 return NULL; 281} 282 283 284/** talloc and zero memory. */ 285#if defined(PARANOID_MALLOC_CHECKER) 286void *talloc_zero_(TALLOC_CTX *t, size_t size) 287#else 288void *talloc_zero(TALLOC_CTX *t, size_t size) 289#endif 290{ 291 void *p = TALLOC(t, size); 292 293 if (p) 294 memset(p, '\0', size); 295 296 return p; 297} 298 299#if defined(PARANOID_MALLOC_CHECKER) 300void *talloc_zero_array_(TALLOC_CTX *t, size_t el_size, unsigned int count) 301#else 302void *talloc_zero_array(TALLOC_CTX *t, size_t el_size, unsigned int count) 303#endif 304{ 305#if defined(PARANOID_MALLOC_CHECKER) 306 void *p = talloc_array_(t, el_size, count); 307#else 308 void *p = talloc_array(t, el_size, count); 309#endif 310 311 if (p) 312 memset(p, '\0', el_size*count); 313 314 return p; 315} 316 317/** memdup with a talloc. */ 318#if defined(PARANOID_MALLOC_CHECKER) 319void *talloc_memdup_(TALLOC_CTX *t, const void *p, size_t size) 320#else 321void *talloc_memdup(TALLOC_CTX *t, const void *p, size_t size) 322#endif 323{ 324 void *newp = TALLOC(t,size); 325 326 if (newp) 327 memcpy(newp, p, size); 328 329 return newp; 330} 331 332/** strdup with a talloc */ 333char *talloc_strdup(TALLOC_CTX *t, const char *p) 334{ 335 if (p) 336 return TALLOC_MEMDUP(t, p, strlen(p) + 1); 337 else 338 return NULL; 339} 340 341/** strdup_upper with a talloc */ 342char *talloc_strdup_upper(TALLOC_CTX *t, const char *p) 343{ 344 char *r; 345 if (p) { 346 char *q = strdup_upper(p); 347 if (q) { 348 r = talloc_strdup(t, q); 349 SAFE_FREE(q); 350 return r; 351 } else { 352 return NULL; 353 } 354 } else { 355 return NULL; 356 } 357} 358 359/** strdup_w with a talloc */ 360smb_ucs2_t *talloc_strdup_w(TALLOC_CTX *t, const smb_ucs2_t *p) 361{ 362 if (p) 363 return TALLOC_MEMDUP(t, p, (strlen_w(p) + 1) * sizeof(smb_ucs2_t)); 364 else 365 return NULL; 366} 367 368/** 369 * Perform string formatting, and return a pointer to newly allocated 370 * memory holding the result, inside a memory pool. 371 **/ 372 char *talloc_asprintf(TALLOC_CTX *t, const char *fmt, ...) 373{ 374 va_list ap; 375 char *ret; 376 377 va_start(ap, fmt); 378 ret = talloc_vasprintf(t, fmt, ap); 379 va_end(ap); 380 return ret; 381} 382 383 384 char *talloc_vasprintf(TALLOC_CTX *t, const char *fmt, va_list ap) 385{ 386 int len; 387 char *ret; 388 va_list ap2; 389 390 VA_COPY(ap2, ap); 391 392 len = vsnprintf(NULL, 0, fmt, ap2); 393 394 ret = TALLOC(t, len+1); 395 if (ret) { 396 VA_COPY(ap2, ap); 397 vsnprintf(ret, len+1, fmt, ap2); 398 } 399 400 return ret; 401} 402 403 404/** 405 * Realloc @p s to append the formatted result of @p fmt and return @p 406 * s, which may have moved. Good for gradually accumulating output 407 * into a string buffer. 408 **/ 409 char *talloc_asprintf_append(TALLOC_CTX *t, char *s, 410 const char *fmt, ...) 411{ 412 va_list ap; 413 414 va_start(ap, fmt); 415 s = talloc_vasprintf_append(t, s, fmt, ap); 416 va_end(ap); 417 return s; 418} 419 420 421 422/** 423 * Realloc @p s to append the formatted result of @p fmt and @p ap, 424 * and return @p s, which may have moved. Good for gradually 425 * accumulating output into a string buffer. 426 **/ 427 char *talloc_vasprintf_append(TALLOC_CTX *t, char *s, 428 const char *fmt, va_list ap) 429{ 430 int len, s_len; 431 va_list ap2; 432 433 VA_COPY(ap2, ap); 434 435 s_len = strlen(s); 436 len = vsnprintf(NULL, 0, fmt, ap2); 437 438 s = TALLOC_REALLOC(t, s, s_len + len+1); 439 if (!s) return NULL; 440 441 VA_COPY(ap2, ap); 442 443 vsnprintf(s+s_len, len+1, fmt, ap2); 444 445 return s; 446} 447 448 449/** 450 * Return a human-readable description of all talloc memory usage. 451 * The result is allocated from @p t. 452 **/ 453char *talloc_describe_all(TALLOC_CTX *rt) 454{ 455 int n_pools = 0, total_chunks = 0; 456 size_t total_bytes = 0; 457 TALLOC_CTX *it; 458 char *s; 459 460 if (!rt) return NULL; 461 462 s = talloc_asprintf(rt, "global talloc allocations in pid: %u\n", 463 (unsigned) sys_getpid()); 464 s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n", 465 "name", "chunks", "bytes"); 466 s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n", 467 "----------------------------------------", 468 "--------", 469 "--------"); 470 471 for (it = list_head; it; it = it->next_ctx) { 472 size_t bytes; 473 int n_chunks; 474 fstring what; 475 476 n_pools++; 477 478 talloc_get_allocation(it, &bytes, &n_chunks); 479 480 if (it->name) 481 fstrcpy(what, it->name); 482 else 483 slprintf(what, sizeof(what), "@%p", it); 484 485 s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n", 486 what, 487 (unsigned) n_chunks, 488 (unsigned) bytes); 489 total_bytes += bytes; 490 total_chunks += n_chunks; 491 } 492 493 s = talloc_asprintf_append(rt, s, "%-40s %8s %8s\n", 494 "----------------------------------------", 495 "--------", 496 "--------"); 497 498 s = talloc_asprintf_append(rt, s, "%-40s %8u %8u\n", 499 "TOTAL", 500 (unsigned) total_chunks, (unsigned) total_bytes); 501 502 return s; 503} 504 505 506 507/** 508 * Return an estimated memory usage for the specified pool. This does 509 * not include memory used by the underlying malloc implementation. 510 **/ 511void talloc_get_allocation(TALLOC_CTX *t, 512 size_t *total_bytes, 513 int *n_chunks) 514{ 515 struct talloc_chunk *chunk; 516 517 if (t) { 518 *total_bytes = 0; 519 *n_chunks = 0; 520 521 for (chunk = t->list; chunk; chunk = chunk->next) { 522 n_chunks[0]++; 523 *total_bytes += chunk->size; 524 } 525 } 526} 527 528 529/** @} */ 530