Changeset 988 for vendor/current/lib/talloc/talloc.c
- Timestamp:
- Nov 24, 2016, 1:14:11 PM (9 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
vendor/current/lib/talloc/talloc.c
r746 r988 1 /* 1 /* 2 2 Samba Unix SMB/CIFS implementation. 3 3 … … 8 8 Copyright (C) Andrew Tridgell 2004 9 9 Copyright (C) Stefan Metzmacher 2006 10 10 11 11 ** NOTE! The following LGPL license applies to the talloc 12 12 ** library. This does NOT imply that all of Samba is released 13 13 ** under the LGPL 14 14 15 15 This library is free software; you can redistribute it and/or 16 16 modify it under the terms of the GNU Lesser General Public … … 33 33 #include "replace.h" 34 34 #include "talloc.h" 35 36 #ifdef HAVE_SYS_AUXV_H 37 #include <sys/auxv.h> 38 #endif 35 39 36 40 #ifdef TALLOC_BUILD_VERSION_MAJOR … … 61 65 62 66 #define MAX_TALLOC_SIZE 0x10000000 63 #define TALLOC_MAGIC_BASE 0xe814ec7064 #define TALLOC_MAGIC ( \65 TALLOC_MAGIC_BASE + \66 (TALLOC_VERSION_MAJOR << 12) + \67 (TALLOC_VERSION_MINOR << 4) \68 )69 67 70 68 #define TALLOC_FLAG_FREE 0x01 … … 72 70 #define TALLOC_FLAG_POOL 0x04 /* This is a talloc pool */ 73 71 #define TALLOC_FLAG_POOLMEM 0x08 /* This is allocated in a pool */ 72 73 /* 74 * Bits above this are random, used to make it harder to fake talloc 75 * headers during an attack. Try not to change this without good reason. 76 */ 77 #define TALLOC_FLAG_MASK 0x0F 78 74 79 #define TALLOC_MAGIC_REFERENCE ((const char *)1) 75 80 76 /* by default we abort when given a bad pointer (such as when talloc_free() is called 81 #define TALLOC_MAGIC_BASE 0xe814ec70 82 static unsigned int talloc_magic = ( 83 TALLOC_MAGIC_BASE + 84 (TALLOC_VERSION_MAJOR << 12) + 85 (TALLOC_VERSION_MINOR << 4)); 86 87 /* by default we abort when given a bad pointer (such as when talloc_free() is called 77 88 on a pointer that came from malloc() */ 78 89 #ifndef TALLOC_ABORT … … 228 239 }; 229 240 241 struct talloc_memlimit { 242 struct talloc_chunk *parent; 243 struct talloc_memlimit *upper; 244 size_t max_size; 245 size_t cur_size; 246 }; 247 248 static inline bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size); 249 static inline void talloc_memlimit_grow(struct talloc_memlimit *limit, 250 size_t size); 251 static inline void talloc_memlimit_shrink(struct talloc_memlimit *limit, 252 size_t size); 253 static inline void talloc_memlimit_update_on_free(struct talloc_chunk *tc); 254 255 static inline void _talloc_set_name_const(const void *ptr, const char *name); 256 230 257 typedef int (*talloc_destructor_t)(void *); 231 258 259 struct talloc_pool_hdr; 260 232 261 struct talloc_chunk { 262 unsigned flags; 233 263 struct talloc_chunk *next, *prev; 234 264 struct talloc_chunk *parent, *child; … … 237 267 const char *name; 238 268 size_t size; 239 unsigned flags;240 269 241 270 /* 242 * "pool" has dual use: 243 * 244 * For the talloc pool itself (i.e. TALLOC_FLAG_POOL is set), "pool" 245 * marks the end of the currently allocated area. 246 * 247 * For members of the pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool" 271 * limit semantics: 272 * if 'limit' is set it means all *new* children of the context will 273 * be limited to a total aggregate size ox max_size for memory 274 * allocations. 275 * cur_size is used to keep track of the current use 276 */ 277 struct talloc_memlimit *limit; 278 279 /* 280 * For members of a pool (i.e. TALLOC_FLAG_POOLMEM is set), "pool" 248 281 * is a pointer to the struct talloc_chunk of the pool that it was 249 282 * allocated from. This way children can quickly find the pool to chew 250 283 * from. 251 284 */ 252 void*pool;285 struct talloc_pool_hdr *pool; 253 286 }; 254 287 … … 268 301 } 269 302 303 _PUBLIC_ int talloc_test_get_magic(void) 304 { 305 return talloc_magic; 306 } 307 270 308 static void (*talloc_log_fn)(const char *message); 271 309 … … 274 312 talloc_log_fn = log_fn; 275 313 } 314 315 #ifdef HAVE_CONSTRUCTOR_ATTRIBUTE 316 void talloc_lib_init(void) __attribute__((constructor)); 317 void talloc_lib_init(void) 318 { 319 uint32_t random_value; 320 #if defined(HAVE_GETAUXVAL) && defined(AT_RANDOM) 321 uint8_t *p; 322 /* 323 * Use the kernel-provided random values used for 324 * ASLR. This won't change per-exec, which is ideal for us 325 */ 326 p = (uint8_t *) getauxval(AT_RANDOM); 327 if (p) { 328 /* 329 * We get 16 bytes from getauxval. By calling rand(), 330 * a totally insecure PRNG, but one that will 331 * deterministically have a different value when called 332 * twice, we ensure that if two talloc-like libraries 333 * are somehow loaded in the same address space, that 334 * because we choose different bytes, we will keep the 335 * protection against collision of multiple talloc 336 * libs. 337 * 338 * This protection is important because the effects of 339 * passing a talloc pointer from one to the other may 340 * be very hard to determine. 341 */ 342 int offset = rand() % (16 - sizeof(random_value)); 343 memcpy(&random_value, p + offset, sizeof(random_value)); 344 } else 345 #endif 346 { 347 /* 348 * Otherwise, hope the location we are loaded in 349 * memory is randomised by someone else 350 */ 351 random_value = ((uintptr_t)talloc_lib_init & 0xFFFFFFFF); 352 } 353 talloc_magic = random_value & ~TALLOC_FLAG_MASK; 354 } 355 #else 356 #warning "No __attribute__((constructor)) support found on this platform, additional talloc security measures not available" 357 #endif 276 358 277 359 static void talloc_log(const char *fmt, ...) PRINTF_ATTRIBUTE(1,2); … … 323 405 static void talloc_abort_magic(unsigned magic) 324 406 { 325 unsigned striped = magic - TALLOC_MAGIC_BASE;326 unsigned major = (striped & 0xFFFFF000) >> 12;327 unsigned minor = (striped & 0x00000FF0) >> 4;328 talloc_log("Bad talloc magic[0x%08X/%u/%u] expected[0x%08X/%u/%u]\n",329 magic, major, minor,330 TALLOC_MAGIC, TALLOC_VERSION_MAJOR, TALLOC_VERSION_MINOR);331 407 talloc_abort("Bad talloc magic value - wrong talloc version used/mixed"); 332 408 } … … 347 423 const char *pp = (const char *)ptr; 348 424 struct talloc_chunk *tc = discard_const_p(struct talloc_chunk, pp - TC_HDR_SIZE); 349 if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~ 0xF)) != TALLOC_MAGIC)) {350 if ((tc->flags & (~0xF FF)) == TALLOC_MAGIC_BASE) {351 talloc_abort_magic(tc->flags & (~ 0xF));425 if (unlikely((tc->flags & (TALLOC_FLAG_FREE | ~TALLOC_FLAG_MASK)) != talloc_magic)) { 426 if ((tc->flags & (~0xF)) == talloc_magic) { 427 talloc_abort_magic(tc->flags & (~TALLOC_FLAG_MASK)); 352 428 return NULL; 353 429 } … … 438 514 */ 439 515 440 #define TALLOC_POOL_HDR_SIZE 16 441 442 #define TC_POOL_SPACE_LEFT(_pool_tc) \ 443 PTR_DIFF(TC_HDR_SIZE + (_pool_tc)->size + (char *)(_pool_tc), \ 444 (_pool_tc)->pool) 445 446 #define TC_POOL_FIRST_CHUNK(_pool_tc) \ 447 ((void *)(TC_HDR_SIZE + TALLOC_POOL_HDR_SIZE + (char *)(_pool_tc))) 448 449 #define TC_POOLMEM_CHUNK_SIZE(_tc) \ 450 TC_ALIGN16(TC_HDR_SIZE + (_tc)->size) 451 452 #define TC_POOLMEM_NEXT_CHUNK(_tc) \ 453 ((void *)(TC_POOLMEM_CHUNK_SIZE(tc) + (char*)(_tc))) 516 struct talloc_pool_hdr { 517 void *end; 518 unsigned int object_count; 519 size_t poolsize; 520 }; 521 522 #define TP_HDR_SIZE TC_ALIGN16(sizeof(struct talloc_pool_hdr)) 523 524 static inline struct talloc_pool_hdr *talloc_pool_from_chunk(struct talloc_chunk *c) 525 { 526 return (struct talloc_pool_hdr *)((char *)c - TP_HDR_SIZE); 527 } 528 529 static inline struct talloc_chunk *talloc_chunk_from_pool(struct talloc_pool_hdr *h) 530 { 531 return (struct talloc_chunk *)((char *)h + TP_HDR_SIZE); 532 } 533 534 static inline void *tc_pool_end(struct talloc_pool_hdr *pool_hdr) 535 { 536 struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr); 537 return (char *)tc + TC_HDR_SIZE + pool_hdr->poolsize; 538 } 539 540 static inline size_t tc_pool_space_left(struct talloc_pool_hdr *pool_hdr) 541 { 542 return (char *)tc_pool_end(pool_hdr) - (char *)pool_hdr->end; 543 } 544 545 /* If tc is inside a pool, this gives the next neighbour. */ 546 static inline void *tc_next_chunk(struct talloc_chunk *tc) 547 { 548 return (char *)tc + TC_ALIGN16(TC_HDR_SIZE + tc->size); 549 } 550 551 static inline void *tc_pool_first_chunk(struct talloc_pool_hdr *pool_hdr) 552 { 553 struct talloc_chunk *tc = talloc_chunk_from_pool(pool_hdr); 554 return tc_next_chunk(tc); 555 } 454 556 455 557 /* Mark the whole remaining pool as not accessable */ 456 #define TC_INVALIDATE_FILL_POOL(_pool_tc) do { \ 457 if (unlikely(talloc_fill.enabled)) { \ 458 size_t _flen = TC_POOL_SPACE_LEFT(_pool_tc); \459 char *_fptr = (char *)(_pool_tc)->pool; \ 460 memset(_fptr, talloc_fill.fill_value, _flen); \461 } \462 } while(0) 558 static inline void tc_invalidate_pool(struct talloc_pool_hdr *pool_hdr) 559 { 560 size_t flen = tc_pool_space_left(pool_hdr); 561 562 if (unlikely(talloc_fill.enabled)) { 563 memset(pool_hdr->end, talloc_fill.fill_value, flen); 564 } 463 565 464 566 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_NOACCESS) 465 /* Mark the whole remaining pool as not accessable */ 466 #define TC_INVALIDATE_VALGRIND_POOL(_pool_tc) do { \ 467 size_t _flen = TC_POOL_SPACE_LEFT(_pool_tc); \ 468 char *_fptr = (char *)(_pool_tc)->pool; \ 469 VALGRIND_MAKE_MEM_NOACCESS(_fptr, _flen); \ 470 } while(0) 471 #else 472 #define TC_INVALIDATE_VALGRIND_POOL(_pool_tc) do { } while (0) 473 #endif 474 475 #define TC_INVALIDATE_POOL(_pool_tc) do { \ 476 TC_INVALIDATE_FILL_POOL(_pool_tc); \ 477 TC_INVALIDATE_VALGRIND_POOL(_pool_tc); \ 478 } while (0) 479 480 static unsigned int *talloc_pool_objectcount(struct talloc_chunk *tc) 481 { 482 return (unsigned int *)((char *)tc + TC_HDR_SIZE); 567 VALGRIND_MAKE_MEM_NOACCESS(pool_hdr->end, flen); 568 #endif 483 569 } 484 570 … … 487 573 */ 488 574 489 static struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent,490 size_t size)491 { 492 struct talloc_ chunk *pool_ctx= NULL;575 static inline struct talloc_chunk *talloc_alloc_pool(struct talloc_chunk *parent, 576 size_t size, size_t prefix_len) 577 { 578 struct talloc_pool_hdr *pool_hdr = NULL; 493 579 size_t space_left; 494 580 struct talloc_chunk *result; … … 500 586 501 587 if (parent->flags & TALLOC_FLAG_POOL) { 502 pool_ ctx = parent;588 pool_hdr = talloc_pool_from_chunk(parent); 503 589 } 504 590 else if (parent->flags & TALLOC_FLAG_POOLMEM) { 505 pool_ ctx = (struct talloc_chunk *)parent->pool;506 } 507 508 if (pool_ ctx== NULL) {591 pool_hdr = parent->pool; 592 } 593 594 if (pool_hdr == NULL) { 509 595 return NULL; 510 596 } 511 597 512 space_left = TC_POOL_SPACE_LEFT(pool_ctx);598 space_left = tc_pool_space_left(pool_hdr); 513 599 514 600 /* 515 601 * Align size to 16 bytes 516 602 */ 517 chunk_size = TC_ALIGN16(size );603 chunk_size = TC_ALIGN16(size + prefix_len); 518 604 519 605 if (space_left < chunk_size) { … … 521 607 } 522 608 523 result = (struct talloc_chunk *) pool_ctx->pool;609 result = (struct talloc_chunk *)((char *)pool_hdr->end + prefix_len); 524 610 525 611 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) 526 VALGRIND_MAKE_MEM_UNDEFINED( result,size);527 #endif 528 529 pool_ ctx->pool = (void *)((char *)result+ chunk_size);530 531 result->flags = TALLOC_MAGIC| TALLOC_FLAG_POOLMEM;532 result->pool = pool_ ctx;533 534 *talloc_pool_objectcount(pool_ctx) += 1;612 VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, chunk_size); 613 #endif 614 615 pool_hdr->end = (void *)((char *)pool_hdr->end + chunk_size); 616 617 result->flags = talloc_magic | TALLOC_FLAG_POOLMEM; 618 result->pool = pool_hdr; 619 620 pool_hdr->object_count++; 535 621 536 622 return result; 537 623 } 538 624 539 /* 625 /* 540 626 Allocate a bit of memory as a child of an existing pointer 541 627 */ 542 static inline void *__talloc(const void *context, size_t size) 628 static inline void *__talloc_with_prefix(const void *context, size_t size, 629 size_t prefix_len) 543 630 { 544 631 struct talloc_chunk *tc = NULL; 632 struct talloc_memlimit *limit = NULL; 633 size_t total_len = TC_HDR_SIZE + size + prefix_len; 545 634 546 635 if (unlikely(context == NULL)) { … … 552 641 } 553 642 643 if (unlikely(total_len < TC_HDR_SIZE)) { 644 return NULL; 645 } 646 554 647 if (context != NULL) { 555 tc = talloc_alloc_pool(talloc_chunk_from_ptr(context), 556 TC_HDR_SIZE+size); 648 struct talloc_chunk *ptc = talloc_chunk_from_ptr(context); 649 650 if (ptc->limit != NULL) { 651 limit = ptc->limit; 652 } 653 654 tc = talloc_alloc_pool(ptc, TC_HDR_SIZE+size, prefix_len); 557 655 } 558 656 559 657 if (tc == NULL) { 560 tc = (struct talloc_chunk *)malloc(TC_HDR_SIZE+size); 561 if (unlikely(tc == NULL)) return NULL; 562 tc->flags = TALLOC_MAGIC; 658 char *ptr; 659 660 /* 661 * Only do the memlimit check/update on actual allocation. 662 */ 663 if (!talloc_memlimit_check(limit, total_len)) { 664 errno = ENOMEM; 665 return NULL; 666 } 667 668 ptr = malloc(total_len); 669 if (unlikely(ptr == NULL)) { 670 return NULL; 671 } 672 tc = (struct talloc_chunk *)(ptr + prefix_len); 673 tc->flags = talloc_magic; 563 674 tc->pool = NULL; 564 } 565 675 676 talloc_memlimit_grow(limit, total_len); 677 } 678 679 tc->limit = limit; 566 680 tc->size = size; 567 681 tc->destructor = NULL; … … 590 704 } 591 705 706 static inline void *__talloc(const void *context, size_t size) 707 { 708 return __talloc_with_prefix(context, size, 0); 709 } 710 592 711 /* 593 712 * Create a talloc pool 594 713 */ 595 714 596 _PUBLIC_ void *talloc_pool(const void *context, size_t size) 597 { 598 void *result = __talloc(context, size + TALLOC_POOL_HDR_SIZE); 715 static inline void *_talloc_pool(const void *context, size_t size) 716 { 599 717 struct talloc_chunk *tc; 718 struct talloc_pool_hdr *pool_hdr; 719 void *result; 720 721 result = __talloc_with_prefix(context, size, TP_HDR_SIZE); 600 722 601 723 if (unlikely(result == NULL)) { … … 604 726 605 727 tc = talloc_chunk_from_ptr(result); 728 pool_hdr = talloc_pool_from_chunk(tc); 606 729 607 730 tc->flags |= TALLOC_FLAG_POOL; 608 tc->pool = TC_POOL_FIRST_CHUNK(tc); 609 610 *talloc_pool_objectcount(tc) = 1; 611 612 TC_INVALIDATE_POOL(tc); 731 tc->size = 0; 732 733 pool_hdr->object_count = 1; 734 pool_hdr->end = result; 735 pool_hdr->poolsize = size; 736 737 tc_invalidate_pool(pool_hdr); 613 738 614 739 return result; 740 } 741 742 _PUBLIC_ void *talloc_pool(const void *context, size_t size) 743 { 744 return _talloc_pool(context, size); 745 } 746 747 /* 748 * Create a talloc pool correctly sized for a basic size plus 749 * a number of subobjects whose total size is given. Essentially 750 * a custom allocator for talloc to reduce fragmentation. 751 */ 752 753 _PUBLIC_ void *_talloc_pooled_object(const void *ctx, 754 size_t type_size, 755 const char *type_name, 756 unsigned num_subobjects, 757 size_t total_subobjects_size) 758 { 759 size_t poolsize, subobjects_slack, tmp; 760 struct talloc_chunk *tc; 761 struct talloc_pool_hdr *pool_hdr; 762 void *ret; 763 764 poolsize = type_size + total_subobjects_size; 765 766 if ((poolsize < type_size) || (poolsize < total_subobjects_size)) { 767 goto overflow; 768 } 769 770 if (num_subobjects == UINT_MAX) { 771 goto overflow; 772 } 773 num_subobjects += 1; /* the object body itself */ 774 775 /* 776 * Alignment can increase the pool size by at most 15 bytes per object 777 * plus alignment for the object itself 778 */ 779 subobjects_slack = (TC_HDR_SIZE + TP_HDR_SIZE + 15) * num_subobjects; 780 if (subobjects_slack < num_subobjects) { 781 goto overflow; 782 } 783 784 tmp = poolsize + subobjects_slack; 785 if ((tmp < poolsize) || (tmp < subobjects_slack)) { 786 goto overflow; 787 } 788 poolsize = tmp; 789 790 ret = _talloc_pool(ctx, poolsize); 791 if (ret == NULL) { 792 return NULL; 793 } 794 795 tc = talloc_chunk_from_ptr(ret); 796 tc->size = type_size; 797 798 pool_hdr = talloc_pool_from_chunk(tc); 799 800 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) 801 VALGRIND_MAKE_MEM_UNDEFINED(pool_hdr->end, type_size); 802 #endif 803 804 pool_hdr->end = ((char *)pool_hdr->end + TC_ALIGN16(type_size)); 805 806 _talloc_set_name_const(ret, type_name); 807 return ret; 808 809 overflow: 810 return NULL; 615 811 } 616 812 … … 628 824 629 825 /* 630 increase the reference count on a piece of memory. 826 increase the reference count on a piece of memory. 631 827 */ 632 828 _PUBLIC_ int talloc_increase_ref_count(const void *ptr) … … 651 847 652 848 /* 653 more efficient way to add a name to a pointer - the name must point to a 849 more efficient way to add a name to a pointer - the name must point to a 654 850 true string constant 655 851 */ … … 681 877 the pointer remains valid until both the original caller and this given 682 878 context are freed. 683 684 the major use for this is when two different structures need to reference the 879 880 the major use for this is when two different structures need to reference the 685 881 same underlying data, and you want to be able to free the two instances separately, 686 882 and in either order … … 713 909 const char *location) 714 910 { 715 struct talloc_chunk *pool; 911 struct talloc_pool_hdr *pool; 912 struct talloc_chunk *pool_tc; 716 913 void *next_tc; 717 unsigned int *pool_object_count; 718 719 pool = (struct talloc_chunk *)tc->pool;720 next_tc = TC_POOLMEM_NEXT_CHUNK(tc);914 915 pool = tc->pool; 916 pool_tc = talloc_chunk_from_pool(pool); 917 next_tc = tc_next_chunk(tc); 721 918 722 919 tc->flags |= TALLOC_FLAG_FREE; … … 730 927 TC_INVALIDATE_FULL_CHUNK(tc); 731 928 732 pool_object_count = talloc_pool_objectcount(pool); 733 734 if (unlikely(*pool_object_count == 0)) { 929 if (unlikely(pool->object_count == 0)) { 735 930 talloc_abort("Pool object count zero!"); 736 931 return; 737 932 } 738 933 739 *pool_object_count -= 1; 740 741 if (unlikely(*pool_object_count == 1 && !(pool->flags & TALLOC_FLAG_FREE))) { 934 pool->object_count--; 935 936 if (unlikely(pool->object_count == 1 937 && !(pool_tc->flags & TALLOC_FLAG_FREE))) { 742 938 /* 743 939 * if there is just one object left in the pool … … 747 943 * again. 748 944 */ 749 pool->pool = TC_POOL_FIRST_CHUNK(pool); 750 TC_INVALIDATE_POOL(pool); 751 } else if (unlikely(*pool_object_count == 0)) { 945 pool->end = tc_pool_first_chunk(pool); 946 tc_invalidate_pool(pool); 947 return; 948 } 949 950 if (unlikely(pool->object_count == 0)) { 752 951 /* 753 952 * we mark the freed memory with where we called the free … … 755 954 * the first free came from 756 955 */ 757 pool->name = location; 758 759 TC_INVALIDATE_FULL_CHUNK(pool); 760 free(pool); 761 } else if (pool->pool == next_tc) { 956 pool_tc->name = location; 957 958 if (pool_tc->flags & TALLOC_FLAG_POOLMEM) { 959 _talloc_free_poolmem(pool_tc, location); 960 } else { 961 /* 962 * The talloc_memlimit_update_on_free() 963 * call takes into account the 964 * prefix TP_HDR_SIZE allocated before 965 * the pool talloc_chunk. 966 */ 967 talloc_memlimit_update_on_free(pool_tc); 968 TC_INVALIDATE_FULL_CHUNK(pool_tc); 969 free(pool); 970 } 971 return; 972 } 973 974 if (pool->end == next_tc) { 762 975 /* 763 976 * if pool->pool still points to end of … … 765 978 * we can reclaim the memory of 'tc'. 766 979 */ 767 pool->pool = tc; 768 } 980 pool->end = tc; 981 return; 982 } 983 984 /* 985 * Do nothing. The memory is just "wasted", waiting for the pool 986 * itself to be freed. 987 */ 769 988 } 770 989 … … 773 992 const char *location); 774 993 775 /* 994 /* 776 995 internal talloc_free call 777 996 */ … … 779 998 { 780 999 struct talloc_chunk *tc; 1000 void *ptr_to_free; 781 1001 782 1002 if (unlikely(ptr == NULL)) { … … 825 1045 tc->destructor = (talloc_destructor_t)-1; 826 1046 if (d(ptr) == -1) { 827 tc->destructor = d; 1047 /* 1048 * Only replace the destructor pointer if 1049 * calling the destructor didn't modify it. 1050 */ 1051 if (tc->destructor == (talloc_destructor_t)-1) { 1052 tc->destructor = d; 1053 } 828 1054 return -1; 829 1055 } … … 850 1076 /* we mark the freed memory with where we called the free 851 1077 * from. This means on a double free error we can report where 852 * the first free came from 853 */ 1078 * the first free came from 1079 */ 854 1080 tc->name = location; 855 1081 856 1082 if (tc->flags & TALLOC_FLAG_POOL) { 857 unsigned int *pool_object_count;858 859 pool _object_count = talloc_pool_objectcount(tc);860 861 if (unlikely( *pool_object_count == 0)) {1083 struct talloc_pool_hdr *pool; 1084 1085 pool = talloc_pool_from_chunk(tc); 1086 1087 if (unlikely(pool->object_count == 0)) { 862 1088 talloc_abort("Pool object count zero!"); 863 1089 return 0; 864 1090 } 865 1091 866 *pool_object_count -= 1; 867 868 if (unlikely(*pool_object_count == 0)) { 869 TC_INVALIDATE_FULL_CHUNK(tc); 870 free(tc); 871 } 872 } else if (tc->flags & TALLOC_FLAG_POOLMEM) { 1092 pool->object_count--; 1093 1094 if (likely(pool->object_count != 0)) { 1095 return 0; 1096 } 1097 1098 /* 1099 * With object_count==0, a pool becomes a normal piece of 1100 * memory to free. If it's allocated inside a pool, it needs 1101 * to be freed as poolmem, else it needs to be just freed. 1102 */ 1103 ptr_to_free = pool; 1104 } else { 1105 ptr_to_free = tc; 1106 } 1107 1108 if (tc->flags & TALLOC_FLAG_POOLMEM) { 873 1109 _talloc_free_poolmem(tc, location); 874 } else { 875 TC_INVALIDATE_FULL_CHUNK(tc); 876 free(tc); 877 } 1110 return 0; 1111 } 1112 1113 talloc_memlimit_update_on_free(tc); 1114 1115 TC_INVALIDATE_FULL_CHUNK(tc); 1116 free(ptr_to_free); 878 1117 return 0; 879 1118 } 880 1119 881 /* 1120 static inline size_t _talloc_total_limit_size(const void *ptr, 1121 struct talloc_memlimit *old_limit, 1122 struct talloc_memlimit *new_limit); 1123 1124 /* 882 1125 move a lump of memory from one talloc context to another return the 883 1126 ptr on success, or NULL if it could not be transferred. … … 887 1130 { 888 1131 struct talloc_chunk *tc, *new_tc; 1132 size_t ctx_size = 0; 889 1133 890 1134 if (unlikely(!ptr)) { … … 897 1141 898 1142 tc = talloc_chunk_from_ptr(ptr); 1143 1144 if (tc->limit != NULL) { 1145 1146 ctx_size = _talloc_total_limit_size(ptr, NULL, NULL); 1147 1148 /* Decrement the memory limit from the source .. */ 1149 talloc_memlimit_shrink(tc->limit->upper, ctx_size); 1150 1151 if (tc->limit->parent == tc) { 1152 tc->limit->upper = NULL; 1153 } else { 1154 tc->limit = NULL; 1155 } 1156 } 899 1157 900 1158 if (unlikely(new_ctx == NULL)) { … … 908 1166 if (tc->next) tc->next->prev = tc->prev; 909 1167 } 910 1168 911 1169 tc->parent = tc->next = tc->prev = NULL; 912 1170 return discard_const_p(void, ptr); … … 934 1192 _TLIST_ADD(new_tc->child, tc); 935 1193 1194 if (tc->limit || new_tc->limit) { 1195 ctx_size = _talloc_total_limit_size(ptr, tc->limit, 1196 new_tc->limit); 1197 /* .. and increment it in the destination. */ 1198 if (new_tc->limit) { 1199 talloc_memlimit_grow(new_tc->limit, ctx_size); 1200 } 1201 } 1202 936 1203 return discard_const_p(void, ptr); 937 1204 } 938 1205 939 /* 1206 /* 940 1207 move a lump of memory from one talloc context to another return the 941 1208 ptr on success, or NULL if it could not be transferred. … … 949 1216 return NULL; 950 1217 } 951 1218 952 1219 tc = talloc_chunk_from_ptr(ptr); 953 1220 954 1221 if (unlikely(tc->refs != NULL) && talloc_parent(ptr) != new_ctx) { 955 1222 struct talloc_reference_handle *h; … … 971 1238 } 972 1239 #endif 973 1240 974 1241 return _talloc_steal_internal(new_ctx, ptr); 975 1242 } 976 1243 977 /* 1244 /* 978 1245 this is like a talloc_steal(), but you must supply the old 979 1246 parent. This resolves the ambiguity in a talloc_steal() which is … … 1003 1270 return discard_const_p(void, ptr); 1004 1271 } 1005 } 1272 } 1006 1273 1007 1274 /* it wasn't a parent */ … … 1040 1307 /* 1041 1308 remove a specific parent context from a pointer. This is a more 1042 controlled vari ent of talloc_free()1309 controlled variant of talloc_free() 1043 1310 */ 1044 1311 _PUBLIC_ int talloc_unlink(const void *context, void *ptr) 1045 1312 { 1046 struct talloc_chunk *tc_p, *new_p ;1313 struct talloc_chunk *tc_p, *new_p, *tc_c; 1047 1314 void *new_parent; 1048 1315 … … 1059 1326 } 1060 1327 1061 if (context == NULL) { 1062 if (talloc_parent_chunk(ptr) != NULL) { 1063 return -1; 1064 } 1328 if (context != NULL) { 1329 tc_c = talloc_chunk_from_ptr(context); 1065 1330 } else { 1066 if (talloc_chunk_from_ptr(context) != talloc_parent_chunk(ptr)) { 1067 return -1; 1068 } 1069 } 1070 1331 tc_c = NULL; 1332 } 1333 if (tc_c != talloc_parent_chunk(ptr)) { 1334 return -1; 1335 } 1336 1071 1337 tc_p = talloc_chunk_from_ptr(ptr); 1072 1338 … … 1149 1415 return the name of a talloc ptr, or "UNNAMED" 1150 1416 */ 1151 _PUBLIC_ const char *talloc_get_name(const void *ptr)1417 static inline const char *__talloc_get_name(const void *ptr) 1152 1418 { 1153 1419 struct talloc_chunk *tc = talloc_chunk_from_ptr(ptr); … … 1161 1427 } 1162 1428 1429 _PUBLIC_ const char *talloc_get_name(const void *ptr) 1430 { 1431 return __talloc_get_name(ptr); 1432 } 1163 1433 1164 1434 /* … … 1170 1440 const char *pname; 1171 1441 if (unlikely(ptr == NULL)) return NULL; 1172 pname = talloc_get_name(ptr);1442 pname = __talloc_get_name(ptr); 1173 1443 if (likely(pname == name || strcmp(pname, name) == 0)) { 1174 1444 return discard_const_p(void, ptr); … … 1177 1447 } 1178 1448 1179 static void talloc_abort_type_mis smatch(const char *location,1449 static void talloc_abort_type_mismatch(const char *location, 1180 1450 const char *name, 1181 1451 const char *expected) … … 1200 1470 1201 1471 if (unlikely(ptr == NULL)) { 1202 talloc_abort_type_mis smatch(location, NULL, name);1472 talloc_abort_type_mismatch(location, NULL, name); 1203 1473 return NULL; 1204 1474 } 1205 1475 1206 pname = talloc_get_name(ptr);1476 pname = __talloc_get_name(ptr); 1207 1477 if (likely(pname == name || strcmp(pname, name) == 0)) { 1208 1478 return discard_const_p(void, ptr); 1209 1479 } 1210 1480 1211 talloc_abort_type_mis smatch(location, pname, name);1481 talloc_abort_type_mismatch(location, pname, name); 1212 1482 return NULL; 1213 1483 } … … 1249 1519 void *child = TC_PTR_FROM_CHUNK(tc->child); 1250 1520 const void *new_parent = null_context; 1251 struct talloc_chunk *old_parent = NULL;1252 1521 if (unlikely(tc->child->refs)) { 1253 1522 struct talloc_chunk *p = talloc_parent_chunk(tc->child->refs); … … 1255 1524 } 1256 1525 if (unlikely(_talloc_free_internal(child, location) == -1)) { 1526 if (talloc_parent_chunk(child) != tc) { 1527 /* 1528 * Destructor already reparented this child. 1529 * No further reparenting needed. 1530 */ 1531 return; 1532 } 1257 1533 if (new_parent == null_context) { 1258 1534 struct talloc_chunk *p = talloc_parent_chunk(ptr); … … 1305 1581 } 1306 1582 1307 /* 1583 /* 1308 1584 Allocate a bit of memory as a child of an existing pointer 1309 1585 */ … … 1331 1607 } 1332 1608 1333 /* 1334 free a talloc pointer. This also frees all child pointers of this 1609 /* 1610 free a talloc pointer. This also frees all child pointers of this 1335 1611 pointer recursively 1336 1612 … … 1346 1622 return -1; 1347 1623 } 1348 1624 1349 1625 tc = talloc_chunk_from_ptr(ptr); 1350 1626 1351 1627 if (unlikely(tc->refs != NULL)) { 1352 1628 struct talloc_reference_handle *h; … … 1368 1644 return -1; 1369 1645 } 1370 1646 1371 1647 return _talloc_free_internal(ptr, location); 1372 1648 } … … 1383 1659 void *new_ptr; 1384 1660 bool malloced = false; 1385 struct talloc_chunk *pool_tc = NULL; 1661 struct talloc_pool_hdr *pool_hdr = NULL; 1662 size_t old_size = 0; 1663 size_t new_size = 0; 1386 1664 1387 1665 /* size zero is equivalent to free() */ … … 1412 1690 } 1413 1691 1414 /* don't let anybody try to realloc a talloc_pool */ 1692 if (tc->limit && (size > tc->size)) { 1693 if (!talloc_memlimit_check(tc->limit, (size - tc->size))) { 1694 errno = ENOMEM; 1695 return NULL; 1696 } 1697 } 1698 1699 /* handle realloc inside a talloc_pool */ 1415 1700 if (unlikely(tc->flags & TALLOC_FLAG_POOLMEM)) { 1416 pool_ tc = (struct talloc_chunk *)tc->pool;1701 pool_hdr = tc->pool; 1417 1702 } 1418 1703 1419 1704 #if (ALWAYS_REALLOC == 0) 1420 1705 /* don't shrink if we have less than 1k to gain */ 1421 if (size < tc->size ) {1422 if (pool_ tc) {1423 void *next_tc = TC_POOLMEM_NEXT_CHUNK(tc);1706 if (size < tc->size && tc->limit == NULL) { 1707 if (pool_hdr) { 1708 void *next_tc = tc_next_chunk(tc); 1424 1709 TC_INVALIDATE_SHRINK_CHUNK(tc, size); 1425 1710 tc->size = size; 1426 if (next_tc == pool_tc->pool) { 1427 pool_tc->pool = TC_POOLMEM_NEXT_CHUNK(tc); 1711 if (next_tc == pool_hdr->end) { 1712 /* note: tc->size has changed, so this works */ 1713 pool_hdr->end = tc_next_chunk(tc); 1428 1714 } 1429 1715 return ptr; … … 1456 1742 1457 1743 #if ALWAYS_REALLOC 1458 if (pool_ tc) {1459 new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE );1460 *talloc_pool_objectcount(pool_tc) -= 1;1744 if (pool_hdr) { 1745 new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE, 0); 1746 pool_hdr->object_count--; 1461 1747 1462 1748 if (new_ptr == NULL) { 1463 1749 new_ptr = malloc(TC_HDR_SIZE+size); 1464 1750 malloced = true; 1751 new_size = size; 1465 1752 } 1466 1753 … … 1470 1757 } 1471 1758 } else { 1759 /* We're doing malloc then free here, so record the difference. */ 1760 old_size = tc->size; 1761 new_size = size; 1472 1762 new_ptr = malloc(size + TC_HDR_SIZE); 1473 1763 if (new_ptr) { … … 1477 1767 } 1478 1768 #else 1479 if (pool_tc) { 1480 void *next_tc = TC_POOLMEM_NEXT_CHUNK(tc); 1481 size_t old_chunk_size = TC_POOLMEM_CHUNK_SIZE(tc); 1769 if (pool_hdr) { 1770 struct talloc_chunk *pool_tc; 1771 void *next_tc = tc_next_chunk(tc); 1772 size_t old_chunk_size = TC_ALIGN16(TC_HDR_SIZE + tc->size); 1482 1773 size_t new_chunk_size = TC_ALIGN16(TC_HDR_SIZE + size); 1483 1774 size_t space_needed; 1484 1775 size_t space_left; 1485 unsigned int chunk_count = *talloc_pool_objectcount(pool_tc); 1486 1776 unsigned int chunk_count = pool_hdr->object_count; 1777 1778 pool_tc = talloc_chunk_from_pool(pool_hdr); 1487 1779 if (!(pool_tc->flags & TALLOC_FLAG_FREE)) { 1488 1780 chunk_count -= 1; … … 1494 1786 * chunk in the pool. 1495 1787 */ 1788 char *start = tc_pool_first_chunk(pool_hdr); 1496 1789 space_needed = new_chunk_size; 1497 space_left = pool_tc->size - TALLOC_POOL_HDR_SIZE;1790 space_left = (char *)tc_pool_end(pool_hdr) - start; 1498 1791 1499 1792 if (space_left >= space_needed) { 1500 1793 size_t old_used = TC_HDR_SIZE + tc->size; 1501 1794 size_t new_used = TC_HDR_SIZE + size; 1502 pool_tc->pool = TC_POOL_FIRST_CHUNK(pool_tc); 1795 new_ptr = start; 1796 1503 1797 #if defined(DEVELOPER) && defined(VALGRIND_MAKE_MEM_UNDEFINED) 1504 /*1505 * we need to prepare the memmove into1506 * the unaccessable area.1507 */1508 1798 { 1509 size_t diff = PTR_DIFF(tc, pool_tc->pool); 1510 size_t flen = MIN(diff, old_used); 1511 char *fptr = (char *)pool_tc->pool; 1512 VALGRIND_MAKE_MEM_UNDEFINED(fptr, flen); 1799 /* 1800 * The area from 1801 * start -> tc may have 1802 * been freed and thus been marked as 1803 * VALGRIND_MEM_NOACCESS. Set it to 1804 * VALGRIND_MEM_UNDEFINED so we can 1805 * copy into it without valgrind errors. 1806 * We can't just mark 1807 * new_ptr -> new_ptr + old_used 1808 * as this may overlap on top of tc, 1809 * (which is why we use memmove, not 1810 * memcpy below) hence the MIN. 1811 */ 1812 size_t undef_len = MIN((((char *)tc) - ((char *)new_ptr)),old_used); 1813 VALGRIND_MAKE_MEM_UNDEFINED(new_ptr, undef_len); 1513 1814 } 1514 1815 #endif 1515 memmove(pool_tc->pool, tc, old_used); 1516 new_ptr = pool_tc->pool;1816 1817 memmove(new_ptr, tc, old_used); 1517 1818 1518 1819 tc = (struct talloc_chunk *)new_ptr; … … 1524 1825 * too. 1525 1826 */ 1526 pool_ tc->pool= new_used + (char *)new_ptr;1527 TC_INVALIDATE_POOL(pool_tc);1827 pool_hdr->end = new_used + (char *)new_ptr; 1828 tc_invalidate_pool(pool_hdr); 1528 1829 1529 1830 /* now the aligned pointer */ 1530 pool_ tc->pool= new_chunk_size + (char *)new_ptr;1831 pool_hdr->end = new_chunk_size + (char *)new_ptr; 1531 1832 goto got_new_ptr; 1532 1833 } … … 1542 1843 } 1543 1844 1544 if (next_tc == pool_ tc->pool) {1845 if (next_tc == pool_hdr->end) { 1545 1846 /* 1546 1847 * optimize for the case where 'tc' is the last … … 1548 1849 */ 1549 1850 space_needed = new_chunk_size - old_chunk_size; 1550 space_left = TC_POOL_SPACE_LEFT(pool_tc);1851 space_left = tc_pool_space_left(pool_hdr); 1551 1852 1552 1853 if (space_left >= space_needed) { … … 1554 1855 tc->flags &= ~TALLOC_FLAG_FREE; 1555 1856 tc->size = size; 1556 pool_ tc->pool = TC_POOLMEM_NEXT_CHUNK(tc);1857 pool_hdr->end = tc_next_chunk(tc); 1557 1858 return ptr; 1558 1859 } 1559 1860 } 1560 1861 1561 new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE );1862 new_ptr = talloc_alloc_pool(tc, size + TC_HDR_SIZE, 0); 1562 1863 1563 1864 if (new_ptr == NULL) { 1564 1865 new_ptr = malloc(TC_HDR_SIZE+size); 1565 1866 malloced = true; 1867 new_size = size; 1566 1868 } 1567 1869 … … 1573 1875 } 1574 1876 else { 1877 /* We're doing realloc here, so record the difference. */ 1878 old_size = tc->size; 1879 new_size = size; 1575 1880 new_ptr = realloc(tc, size + TC_HDR_SIZE); 1576 1881 } 1577 1882 got_new_ptr: 1578 1883 #endif 1579 if (unlikely(!new_ptr)) { 1580 tc->flags &= ~TALLOC_FLAG_FREE; 1581 return NULL; 1884 if (unlikely(!new_ptr)) { 1885 tc->flags &= ~TALLOC_FLAG_FREE; 1886 return NULL; 1582 1887 } 1583 1888 … … 1601 1906 } 1602 1907 1908 if (new_size > old_size) { 1909 talloc_memlimit_grow(tc->limit, new_size - old_size); 1910 } else if (new_size < old_size) { 1911 talloc_memlimit_shrink(tc->limit, old_size - new_size); 1912 } 1913 1603 1914 tc->size = size; 1604 1915 _talloc_set_name_const(TC_PTR_FROM_CHUNK(tc), name); … … 1619 1930 } 1620 1931 1621 /* 1622 return the total size of a talloc pool (subtree) 1623 */ 1624 _PUBLIC_ size_t talloc_total_size(const void *ptr) 1932 enum talloc_mem_count_type { 1933 TOTAL_MEM_SIZE, 1934 TOTAL_MEM_BLOCKS, 1935 TOTAL_MEM_LIMIT, 1936 }; 1937 1938 static inline size_t _talloc_total_mem_internal(const void *ptr, 1939 enum talloc_mem_count_type type, 1940 struct talloc_memlimit *old_limit, 1941 struct talloc_memlimit *new_limit) 1625 1942 { 1626 1943 size_t total = 0; … … 1636 1953 tc = talloc_chunk_from_ptr(ptr); 1637 1954 1955 if (old_limit || new_limit) { 1956 if (tc->limit && tc->limit->upper == old_limit) { 1957 tc->limit->upper = new_limit; 1958 } 1959 } 1960 1961 /* optimize in the memlimits case */ 1962 if (type == TOTAL_MEM_LIMIT && 1963 tc->limit != NULL && 1964 tc->limit != old_limit && 1965 tc->limit->parent == tc) { 1966 return tc->limit->cur_size; 1967 } 1968 1638 1969 if (tc->flags & TALLOC_FLAG_LOOP) { 1639 1970 return 0; … … 1642 1973 tc->flags |= TALLOC_FLAG_LOOP; 1643 1974 1644 if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { 1645 total = tc->size; 1646 } 1647 for (c=tc->child;c;c=c->next) { 1648 total += talloc_total_size(TC_PTR_FROM_CHUNK(c)); 1975 if (old_limit || new_limit) { 1976 if (old_limit == tc->limit) { 1977 tc->limit = new_limit; 1978 } 1979 } 1980 1981 switch (type) { 1982 case TOTAL_MEM_SIZE: 1983 if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { 1984 total = tc->size; 1985 } 1986 break; 1987 case TOTAL_MEM_BLOCKS: 1988 total++; 1989 break; 1990 case TOTAL_MEM_LIMIT: 1991 if (likely(tc->name != TALLOC_MAGIC_REFERENCE)) { 1992 /* 1993 * Don't count memory allocated from a pool 1994 * when calculating limits. Only count the 1995 * pool itself. 1996 */ 1997 if (!(tc->flags & TALLOC_FLAG_POOLMEM)) { 1998 if (tc->flags & TALLOC_FLAG_POOL) { 1999 /* 2000 * If this is a pool, the allocated 2001 * size is in the pool header, and 2002 * remember to add in the prefix 2003 * length. 2004 */ 2005 struct talloc_pool_hdr *pool_hdr 2006 = talloc_pool_from_chunk(tc); 2007 total = pool_hdr->poolsize + 2008 TC_HDR_SIZE + 2009 TP_HDR_SIZE; 2010 } else { 2011 total = tc->size + TC_HDR_SIZE; 2012 } 2013 } 2014 } 2015 break; 2016 } 2017 for (c = tc->child; c; c = c->next) { 2018 total += _talloc_total_mem_internal(TC_PTR_FROM_CHUNK(c), type, 2019 old_limit, new_limit); 1649 2020 } 1650 2021 … … 1655 2026 1656 2027 /* 2028 return the total size of a talloc pool (subtree) 2029 */ 2030 _PUBLIC_ size_t talloc_total_size(const void *ptr) 2031 { 2032 return _talloc_total_mem_internal(ptr, TOTAL_MEM_SIZE, NULL, NULL); 2033 } 2034 2035 /* 1657 2036 return the total number of blocks in a talloc pool (subtree) 1658 2037 */ 1659 2038 _PUBLIC_ size_t talloc_total_blocks(const void *ptr) 1660 2039 { 1661 size_t total = 0; 1662 struct talloc_chunk *c, *tc; 1663 1664 if (ptr == NULL) { 1665 ptr = null_context; 1666 } 1667 if (ptr == NULL) { 1668 return 0; 1669 } 1670 1671 tc = talloc_chunk_from_ptr(ptr); 1672 1673 if (tc->flags & TALLOC_FLAG_LOOP) { 1674 return 0; 1675 } 1676 1677 tc->flags |= TALLOC_FLAG_LOOP; 1678 1679 total++; 1680 for (c=tc->child;c;c=c->next) { 1681 total += talloc_total_blocks(TC_PTR_FROM_CHUNK(c)); 1682 } 1683 1684 tc->flags &= ~TALLOC_FLAG_LOOP; 1685 1686 return total; 2040 return _talloc_total_mem_internal(ptr, TOTAL_MEM_BLOCKS, NULL, NULL); 1687 2041 } 1688 2042 … … 1745 2099 static void talloc_report_depth_FILE_helper(const void *ptr, int depth, int max_depth, int is_ref, void *_f) 1746 2100 { 1747 const char *name = talloc_get_name(ptr); 2101 const char *name = __talloc_get_name(ptr); 2102 struct talloc_chunk *tc; 1748 2103 FILE *f = (FILE *)_f; 1749 2104 … … 1753 2108 } 1754 2109 2110 tc = talloc_chunk_from_ptr(ptr); 2111 if (tc->limit && tc->limit->parent == tc) { 2112 fprintf(f, "%*s%-30s is a memlimit context" 2113 " (max_size = %lu bytes, cur_size = %lu bytes)\n", 2114 depth*4, "", 2115 name, 2116 (unsigned long)tc->limit->max_size, 2117 (unsigned long)tc->limit->cur_size); 2118 } 2119 1755 2120 if (depth == 0) { 1756 fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", 2121 fprintf(f,"%stalloc report on '%s' (total %6lu bytes in %3lu blocks)\n", 1757 2122 (max_depth < 0 ? "full " :""), name, 1758 2123 (unsigned long)talloc_total_size(ptr), … … 1761 2126 } 1762 2127 1763 fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", 2128 fprintf(f, "%*s%-30s contains %6lu bytes in %3lu blocks (ref %d) %p\n", 1764 2129 depth*4, "", 1765 2130 name, … … 1900 2265 } 1901 2266 1902 /* 1903 talloc and zero memory. 2267 /* 2268 talloc and zero memory. 1904 2269 */ 1905 2270 _PUBLIC_ void *_talloc_zero(const void *ctx, size_t size, const char *name) … … 1915 2280 1916 2281 /* 1917 memdup with a talloc. 2282 memdup with a talloc. 1918 2283 */ 1919 2284 _PUBLIC_ void *_talloc_memdup(const void *t, const void *p, size_t size, const char *name) … … 2022 2387 { 2023 2388 if (unlikely(!s)) { 2024 return talloc_str dup(NULL, a);2389 return talloc_strndup(NULL, a, n); 2025 2390 } 2026 2391 … … 2041 2406 2042 2407 if (unlikely(!s)) { 2043 return talloc_str dup(NULL, a);2408 return talloc_strndup(NULL, a, n); 2044 2409 } 2045 2410 … … 2069 2434 char *ret; 2070 2435 va_list ap2; 2071 char c;2436 char buf[1024]; 2072 2437 2073 2438 /* this call looks strange, but it makes it work on older solaris boxes */ 2074 2439 va_copy(ap2, ap); 2075 len = vsnprintf( &c, 1, fmt, ap2);2440 len = vsnprintf(buf, sizeof(buf), fmt, ap2); 2076 2441 va_end(ap2); 2077 2442 if (unlikely(len < 0)) { … … 2082 2447 if (unlikely(!ret)) return NULL; 2083 2448 2084 va_copy(ap2, ap); 2085 vsnprintf(ret, len+1, fmt, ap2); 2086 va_end(ap2); 2449 if (len < sizeof(buf)) { 2450 memcpy(ret, buf, len+1); 2451 } else { 2452 va_copy(ap2, ap); 2453 vsnprintf(ret, len+1, fmt, ap2); 2454 va_end(ap2); 2455 } 2087 2456 2088 2457 _talloc_set_name_const(ret, ret); … … 2330 2699 2331 2700 tc = talloc_chunk_from_ptr(context); 2332 fprintf(file, "talloc parents of '%s'\n", talloc_get_name(context));2701 fprintf(file, "talloc parents of '%s'\n", __talloc_get_name(context)); 2333 2702 while (tc) { 2334 fprintf(file, "\t'%s'\n", talloc_get_name(TC_PTR_FROM_CHUNK(tc)));2703 fprintf(file, "\t'%s'\n", __talloc_get_name(TC_PTR_FROM_CHUNK(tc))); 2335 2704 while (tc && tc->prev) tc = tc->prev; 2336 2705 if (tc) { … … 2353 2722 2354 2723 tc = talloc_chunk_from_ptr(context); 2355 while (tc && depth > 0) { 2724 while (tc) { 2725 if (depth <= 0) { 2726 return 0; 2727 } 2356 2728 if (TC_PTR_FROM_CHUNK(tc) == ptr) return 1; 2357 2729 while (tc && tc->prev) tc = tc->prev; … … 2371 2743 return _talloc_is_parent(context, ptr, TALLOC_MAX_DEPTH); 2372 2744 } 2745 2746 /* 2747 return the total size of memory used by this context and all children 2748 */ 2749 static inline size_t _talloc_total_limit_size(const void *ptr, 2750 struct talloc_memlimit *old_limit, 2751 struct talloc_memlimit *new_limit) 2752 { 2753 return _talloc_total_mem_internal(ptr, TOTAL_MEM_LIMIT, 2754 old_limit, new_limit); 2755 } 2756 2757 static inline bool talloc_memlimit_check(struct talloc_memlimit *limit, size_t size) 2758 { 2759 struct talloc_memlimit *l; 2760 2761 for (l = limit; l != NULL; l = l->upper) { 2762 if (l->max_size != 0 && 2763 ((l->max_size <= l->cur_size) || 2764 (l->max_size - l->cur_size < size))) { 2765 return false; 2766 } 2767 } 2768 2769 return true; 2770 } 2771 2772 /* 2773 Update memory limits when freeing a talloc_chunk. 2774 */ 2775 static void talloc_memlimit_update_on_free(struct talloc_chunk *tc) 2776 { 2777 size_t limit_shrink_size; 2778 2779 if (!tc->limit) { 2780 return; 2781 } 2782 2783 /* 2784 * Pool entries don't count. Only the pools 2785 * themselves are counted as part of the memory 2786 * limits. Note that this also takes care of 2787 * nested pools which have both flags 2788 * TALLOC_FLAG_POOLMEM|TALLOC_FLAG_POOL set. 2789 */ 2790 if (tc->flags & TALLOC_FLAG_POOLMEM) { 2791 return; 2792 } 2793 2794 /* 2795 * If we are part of a memory limited context hierarchy 2796 * we need to subtract the memory used from the counters 2797 */ 2798 2799 limit_shrink_size = tc->size+TC_HDR_SIZE; 2800 2801 /* 2802 * If we're deallocating a pool, take into 2803 * account the prefix size added for the pool. 2804 */ 2805 2806 if (tc->flags & TALLOC_FLAG_POOL) { 2807 limit_shrink_size += TP_HDR_SIZE; 2808 } 2809 2810 talloc_memlimit_shrink(tc->limit, limit_shrink_size); 2811 2812 if (tc->limit->parent == tc) { 2813 free(tc->limit); 2814 } 2815 2816 tc->limit = NULL; 2817 } 2818 2819 /* 2820 Increase memory limit accounting after a malloc/realloc. 2821 */ 2822 static void talloc_memlimit_grow(struct talloc_memlimit *limit, 2823 size_t size) 2824 { 2825 struct talloc_memlimit *l; 2826 2827 for (l = limit; l != NULL; l = l->upper) { 2828 size_t new_cur_size = l->cur_size + size; 2829 if (new_cur_size < l->cur_size) { 2830 talloc_abort("logic error in talloc_memlimit_grow\n"); 2831 return; 2832 } 2833 l->cur_size = new_cur_size; 2834 } 2835 } 2836 2837 /* 2838 Decrease memory limit accounting after a free/realloc. 2839 */ 2840 static void talloc_memlimit_shrink(struct talloc_memlimit *limit, 2841 size_t size) 2842 { 2843 struct talloc_memlimit *l; 2844 2845 for (l = limit; l != NULL; l = l->upper) { 2846 if (l->cur_size < size) { 2847 talloc_abort("logic error in talloc_memlimit_shrink\n"); 2848 return; 2849 } 2850 l->cur_size = l->cur_size - size; 2851 } 2852 } 2853 2854 _PUBLIC_ int talloc_set_memlimit(const void *ctx, size_t max_size) 2855 { 2856 struct talloc_chunk *tc = talloc_chunk_from_ptr(ctx); 2857 struct talloc_memlimit *orig_limit; 2858 struct talloc_memlimit *limit = NULL; 2859 2860 if (tc->limit && tc->limit->parent == tc) { 2861 tc->limit->max_size = max_size; 2862 return 0; 2863 } 2864 orig_limit = tc->limit; 2865 2866 limit = malloc(sizeof(struct talloc_memlimit)); 2867 if (limit == NULL) { 2868 return 1; 2869 } 2870 limit->parent = tc; 2871 limit->max_size = max_size; 2872 limit->cur_size = _talloc_total_limit_size(ctx, tc->limit, limit); 2873 2874 if (orig_limit) { 2875 limit->upper = orig_limit; 2876 } else { 2877 limit->upper = NULL; 2878 } 2879 2880 return 0; 2881 }
Note:
See TracChangeset
for help on using the changeset viewer.