From 639817de90dafbc8cc98a63ff05a7a5ade5dffc1 Mon Sep 17 00:00:00 2001
From: luben <karavelov@spnet.net>
Date: Mon, 16 Aug 2010 18:34:46 +0300
Subject: [PATCH 9/9] Important fixes
* make hash again work with N_BUCKETS(X) != X
* fix memory allocation problems catched by
more strict allocators. libhoard catched some
use-after-free bugs.
* realocate pointers in linear scan - it's faster
---
src/hash.c | 88 ++++++++++++++++++++++++++++++++++--------------------------
1 files changed, 50 insertions(+), 38 deletions(-)
diff --git a/src/hash.c b/src/hash.c
index 07a9b18..145cea5 100644
|
a
|
b
|
|
| 781 | 781 | expand_hash(PARROT_INTERP, ARGMOD(Hash *hash)) |
| 782 | 782 | { |
| 783 | 783 | ASSERT_ARGS(expand_hash) |
| 784 | | HashBucket **old_index, **new_index; |
| 785 | | HashBucket *old_buckets,*new_buckets, *bucket; |
| 786 | | HashBucket * const old_offset = (HashBucket *)((char *)hash + sizeof (Hash)); |
| | 784 | |
| | 785 | HashBucket **new_index, **index; |
| | 786 | HashBucket *new_buckets, *bucket; |
| | 787 | |
| | 788 | HashBucket * const initial_offset = (HashBucket *)((char *)hash + sizeof (Hash)); |
| 787 | 789 | |
| 788 | 790 | void * new_mem; |
| 789 | 791 | void * const old_mem = hash->buckets; |
| 790 | 792 | const UINTVAL old_size = hash->mask + 1; |
| 791 | | const UINTVAL new_size = old_size << 1; /* Double. Right-shift is 2x */ |
| 792 | | const UINTVAL new_mask = new_size - 1 ; |
| | 793 | const UINTVAL new_size = old_size << 1; /* Double. Right-shift is 2x */ |
| | 794 | const UINTVAL new_mask = new_size - 1; |
| 793 | 795 | size_t offset, i; |
| 794 | 796 | |
| 795 | 797 | /* |
| … |
… |
|
| 804 | 806 | */ |
| 805 | 807 | |
| 806 | 808 | /* resize mem */ |
| 807 | | if (old_offset != old_mem) { |
| | 809 | if (initial_offset != old_mem) { |
| 808 | 810 | /* This buffer has been reallocated at least once before. */ |
| 809 | | new_mem = Parrot_gc_reallocate_memory_chunk_with_interior_pointers( |
| 810 | | interp, old_mem, HASH_ALLOC_SIZE(new_size), HASH_ALLOC_SIZE(old_size)); |
| 811 | | } |
| | 811 | new_mem = Parrot_gc_reallocate_memory_chunk_with_interior_pointers( |
| | 812 | interp, old_mem, |
| | 813 | HASH_ALLOC_SIZE(new_size), |
| | 814 | HASH_ALLOC_SIZE(old_size)); |
| | 815 | |
| | 816 | new_buckets = (HashBucket *) new_mem; |
| | 817 | new_index = (HashBucket **)(new_buckets + N_BUCKETS(new_size)); |
| | 818 | |
| | 819 | offset = (char *)new_mem - (char *)old_mem; |
| | 820 | |
| | 821 | /* old index is here */ |
| | 822 | index = (HashBucket **)(new_buckets + N_BUCKETS(old_size)); |
| | 823 | /* reallocate index */ |
| | 824 | mem_sys_memcopy(new_index, index, sizeof(HashBucket *) * old_size); |
| | 825 | |
| | 826 | /* clear second half of the buckets, freed by old the index */ |
| | 827 | memset(new_buckets + N_BUCKETS(old_size), 0, |
| | 828 | sizeof (HashBucket *) * old_size); |
| | 829 | } |
| 812 | 830 | else { |
| 813 | 831 | /* Allocate a new buffer. */ |
| 814 | 832 | new_mem = Parrot_gc_allocate_memory_chunk_with_interior_pointers( |
| 815 | 833 | interp, HASH_ALLOC_SIZE(new_size)); |
| 816 | | memcpy(new_mem, old_mem, HASH_ALLOC_SIZE(old_size)); |
| | 834 | |
| | 835 | new_buckets = (HashBucket *) new_mem; |
| | 836 | new_index = (HashBucket **)(new_buckets + N_BUCKETS(new_size)); |
| | 837 | |
| | 838 | offset = (char *)new_buckets - (char *)hash->buckets; |
| | 839 | |
| | 840 | mem_sys_memcopy(new_buckets, hash->buckets , |
| | 841 | N_BUCKETS(old_size) * sizeof (HashBucket)); |
| | 842 | mem_sys_memcopy(new_index, hash->index, |
| | 843 | sizeof(HashBucket *) * old_size); |
| 817 | 844 | } |
| 818 | 845 | |
| 819 | 846 | /* |
| 820 | 847 | +---+---+---+---+---+---+-+-+-+-+-+-+-+-+ |
| 821 | | | buckets | old_index | new_index | |
| | 848 | | buckets | old_index | new_index | |
| 822 | 849 | +---+---+---+---+---+---+-+-+-+-+-+-+-+-+ |
| 823 | 850 | ^ ^ |
| 824 | 851 | | new_mem | hash->index |
| 825 | 852 | */ |
| 826 | 853 | |
| 827 | | old_buckets = hash->buckets; |
| 828 | | old_index = hash->index; |
| 829 | | |
| 830 | | new_buckets = (HashBucket *) new_mem; |
| 831 | | new_index = (HashBucket **)(new_buckets + N_BUCKETS(new_size)); |
| 832 | | |
| 833 | | /* things can have moved by this offset */ |
| 834 | | offset = (char *)new_buckets - (char *)old_buckets; |
| 835 | | |
| 836 | | /* relocate the bucket index */ |
| 837 | | mem_sys_memmove(new_index, old_index, old_size * sizeof (HashBucket *)); |
| 838 | 854 | |
| 839 | 855 | /* update hash data */ |
| 840 | 856 | hash->index = new_index; |
| 841 | 857 | hash->buckets = new_buckets; |
| 842 | 858 | hash->mask = new_mask; |
| 843 | 859 | |
| 844 | | /* clear freshly allocated bucket index */ |
| 845 | | memset(new_index + old_size, 0, sizeof (HashBucket *) * old_size); |
| 846 | | |
| 847 | 860 | /* |
| 848 | 861 | * reloc pointers - this part would be also needed, if we |
| 849 | 862 | * allocate hash memory from GC movable memory, and then |
| … |
… |
|
| 851 | 864 | * as expand_hash is only called for that case). |
| 852 | 865 | */ |
| 853 | 866 | if (offset) { |
| 854 | | size_t j; |
| 855 | | for (j = 0; j < old_size; ++j) { |
| 856 | | HashBucket **next_p = new_index + j; |
| 857 | | while (*next_p) { |
| 858 | | *next_p = (HashBucket *)((char *)*next_p + offset); |
| 859 | | bucket = *next_p; |
| 860 | | next_p = &bucket->next; |
| | 867 | for (i = 0; i < old_size; ++i) { |
| | 868 | index = new_index + i; |
| | 869 | while (*index) { |
| | 870 | *index = (HashBucket *)((char *)*index + offset); |
| | 871 | bucket = *index; |
| | 872 | index = &bucket->next; |
| 861 | 873 | } |
| 862 | 874 | } |
| 863 | 875 | } |
| 864 | 876 | |
| 865 | 877 | /* recalc bucket index */ |
| 866 | 878 | for (i = 0; i < old_size; ++i) { |
| 867 | | HashBucket **next_p = new_index + i; |
| | 879 | index = new_index + i; |
| 868 | 880 | |
| 869 | | while ((bucket = *next_p) != NULL) { |
| | 881 | while ((bucket = *index) != NULL) { |
| 870 | 882 | /* rehash the bucket */ |
| 871 | 883 | const size_t new_loc = |
| 872 | 884 | get_hash_val(interp, hash, bucket->key) & new_mask; |
| 873 | 885 | |
| 874 | 886 | if (i != new_loc) { |
| 875 | | *next_p = bucket->next; |
| 876 | | bucket->next = new_index[new_loc]; |
| 877 | | new_index[new_loc] = bucket; |
| | 887 | *index = bucket->next; |
| | 888 | bucket->next = new_index[new_loc]; |
| | 889 | new_index[new_loc] = bucket; |
| 878 | 890 | } |
| 879 | 891 | else |
| 880 | | next_p = &bucket->next; |
| | 892 | index = &bucket->next; |
| 881 | 893 | } |
| 882 | 894 | } |
| 883 | 895 | |