]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.r60] runtime: fix map memory leak
authorRuss Cox <rsc@golang.org>
Mon, 3 Oct 2011 17:34:24 +0000 (13:34 -0400)
committerRuss Cox <rsc@golang.org>
Mon, 3 Oct 2011 17:34:24 +0000 (13:34 -0400)
««« CL 5158045 / aaf8ddb0c780
runtime: fix map memory leak

The map implementation was using the C idiom of using
a pointer just past the end of its table as a limit pointer.
Unfortunately, the garbage collector sees that pointer as
pointing at the block adjacent to the map table, pinning
in memory a block that would otherwise be freed.

Fix by making limit pointer point at last valid entry, not
just past it.

Reviewed by Mike Burrows.

R=golang-dev, bradfitz, lvd, r
CC=golang-dev
https://golang.org/cl/5158045
»»»

R=golang-dev, dsymonds
CC=golang-dev
https://golang.org/cl/5169047

src/cmd/ld/dwarf.c
src/pkg/runtime/hashmap.c
src/pkg/runtime/hashmap.h
src/pkg/runtime/runtime-gdb.py

index 77536018a5c4db64e1c52b5550c11362c8d658b0..373cf5523736b8831dfa10538178d4c139d55b76 100644 (file)
@@ -1356,7 +1356,7 @@ synthesizemaptypes(DWDie *die)
                                getattr(keytype, DW_AT_name)->data,
                                getattr(valtype, DW_AT_name)->data));
                copychildren(dwhs, hash_subtable);
-               substitutetype(dwhs, "end", defptrto(dwhe));
+               substitutetype(dwhs, "last", defptrto(dwhe));
                substitutetype(dwhs, "entry", dwhe);  // todo: []hash_entry with dynamic size
                newattr(dwhs, DW_AT_byte_size, DW_CLS_CONSTANT,
                        getattr(hash_subtable, DW_AT_byte_size)->value, nil);
index 0c0e3e4a2de49553506764705e2253673c89585c..22664b548875705902067f25ba5fa74c95ab7d9b 100644 (file)
@@ -54,7 +54,7 @@ struct hash_subtable {
        uint8 datasize;      /* bytes of client data in an entry */
        uint8 max_probes;    /* max number of probes when searching */
        int16 limit_bytes;         /* max_probes * (datasize+sizeof (hash_hash_t)) */
-       struct hash_entry *end;      /* points just past end of entry[] */
+       struct hash_entry *last;      /* points to last element of entry[] */
        struct hash_entry entry[1];  /* 2**power+max_probes-1 elements of elemsize bytes */
 };
 
@@ -101,7 +101,7 @@ hash_subtable_new (Hmap *h, int32 power, int32 used)
        st->datasize = h->datasize;
        st->max_probes = max_probes;
        st->limit_bytes = limit_bytes;
-       st->end = HASH_OFFSET (st->entry, bytes);
+       st->last = HASH_OFFSET (st->entry, bytes) - 1;
        memset (st->entry, HASH_NIL_MEMSET, bytes);
        return (st);
 }
@@ -160,7 +160,7 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
 {
        int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
        struct hash_entry *src_e = HASH_OFFSET (dst_e, n * elemsize);
-       struct hash_entry *end_e = st->end;
+       struct hash_entry *last_e = st->last;
        int32 shift = HASH_BITS - (st->power + st->used);
        int32 index_mask = (((hash_hash_t)1) << st->power) - 1;
        int32 dst_i = (((byte *) dst_e) - ((byte *) st->entry)) / elemsize;
@@ -170,10 +170,10 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
        int32 bytes;
 
        while (dst_e != src_e) {
-               if (src_e != end_e) {
+               if (src_e <= last_e) {
                        struct hash_entry *cp_e = src_e;
                        int32 save_dst_i = dst_i;
-                       while (cp_e != end_e && (hash = cp_e->hash) != HASH_NIL &&
+                       while (cp_e <= last_e && (hash = cp_e->hash) != HASH_NIL &&
                             ((hash >> shift) & index_mask) <= dst_i) {
                                cp_e = HASH_OFFSET (cp_e, elemsize);
                                dst_i++;
@@ -183,7 +183,7 @@ hash_remove_n (struct hash_subtable *st, struct hash_entry *dst_e, int32 n)
                        dst_e = HASH_OFFSET (dst_e, bytes);
                        src_e = cp_e;
                        src_i += dst_i - save_dst_i;
-                       if (src_e != end_e && (hash = src_e->hash) != HASH_NIL) {
+                       if (src_e <= last_e && (hash = src_e->hash) != HASH_NIL) {
                                skip = ((hash >> shift) & index_mask) - dst_i;
                        } else {
                                skip = src_i - dst_i;
@@ -224,7 +224,7 @@ hash_conv (Hmap *h,
        }
 
        de = e;
-       while (e != st->end &&
+       while (e <= st->last &&
            (e_hash = e->hash) != HASH_NIL &&
            (e_hash & HASH_MASK) != HASH_SUBHASH) {
                struct hash_entry *target_e = HASH_OFFSET (st->entry, ((e_hash >> shift) & index_mask) * elemsize);
@@ -235,14 +235,14 @@ hash_conv (Hmap *h,
                        de = target_e;
                }
                if ((hash & prefix_mask) == current ||
-                  (ne != st->end && (e_hash = ne->hash) != HASH_NIL &&
+                  (ne <= st->last && (e_hash = ne->hash) != HASH_NIL &&
                   (e_hash & prefix_mask) == current)) {
                        struct hash_subtable *new_st = hash_subtable_new (h, 1, HASH_USED (new_flags));
                        int32 rc = hash_insert_internal (&new_st, new_flags, e->hash, h, e->data, &dummy_result);
                        assert (rc == 0);
                        memcpy(dummy_result, e->data, h->datasize);
                        e = ne;
-                       while (e != st->end && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) {
+                       while (e <= st->last && (e_hash = e->hash) != HASH_NIL && (e_hash & prefix_mask) == current) {
                                assert ((e_hash & HASH_MASK) != HASH_SUBHASH);
                                rc = hash_insert_internal (&new_st, new_flags, e_hash, h, e->data, &dummy_result);
                                assert (rc == 0);
@@ -271,13 +271,13 @@ hash_grow (Hmap *h, struct hash_subtable **pst, int32 flags)
        struct hash_subtable *old_st = *pst;
        int32 elemsize = h->datasize + offsetof (struct hash_entry, data[0]);
        *pst = hash_subtable_new (h, old_st->power + 1, HASH_USED (flags));
-       struct hash_entry *end_e = old_st->end;
+       struct hash_entry *last_e = old_st->last;
        struct hash_entry *e;
        void *dummy_result;
        int32 used = 0;
 
        flags |= HASH_REHASH;
-       for (e = old_st->entry; e != end_e; e = HASH_OFFSET (e, elemsize)) {
+       for (e = old_st->entry; e <= last_e; e = HASH_OFFSET (e, elemsize)) {
                hash_hash_t hash = e->hash;
                if (hash != HASH_NIL) {
                        int32 rc = hash_insert_internal (pst, flags, e->hash, h, e->data, &dummy_result);
@@ -428,13 +428,13 @@ hash_insert_internal (struct hash_subtable **pst, int32 flags, hash_hash_t hash,
                        ins_e_hash = 0;
                        /* move ins_e to point at the end of the contiguous block, but
                           stop if any element can't be moved by one up */
-                       while (ins_e != st->end && (ins_e_hash = ins_e->hash) != HASH_NIL &&
+                       while (ins_e <= st->last && (ins_e_hash = ins_e->hash) != HASH_NIL &&
                               ins_i + 1 - ((ins_e_hash >> shift) & index_mask) < st->max_probes &&
                               (ins_e_hash & HASH_MASK) != HASH_SUBHASH) {
                                ins_e = HASH_OFFSET (ins_e, elemsize);
                                ins_i++;
                        }
-                       if (e == end_e || ins_e == st->end || ins_e_hash != HASH_NIL) {
+                       if (e == end_e || ins_e > st->last || ins_e_hash != HASH_NIL) {
                                e = end_e;    /* can't insert; must grow or convert to subtable */
                        } else {              /* make space for element */
                                memmove (HASH_OFFSET (e, elemsize), e, ((byte *) ins_e) - (byte *) e);
@@ -477,17 +477,17 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
        struct hash_entry *e;
        hash_hash_t e_hash;
        struct hash_iter_sub *sub = &it->subtable_state[it->i];
-       struct hash_entry *end;
+       struct hash_entry *last;
 
        for (;;) {
                int32 shift = HASH_BITS - (st->power + used);
                int32 index_mask = (1 << st->power) - 1;
                int32 i = (last_hash >> shift) & index_mask;
 
-               end = st->end;
+               last = st->last;
                e = HASH_OFFSET (st->entry, i * elemsize);
                sub->start = st->entry;
-               sub->end = end;
+               sub->last = last;
 
                if ((e->hash & HASH_MASK) != HASH_SUBHASH) {
                        break;
@@ -497,7 +497,7 @@ iter_restart (struct hash_iter *it, struct hash_subtable *st, int32 used)
                used += st->power;
                st = *(struct hash_subtable **)e->data;
        }
-       while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
+       while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
                e = HASH_OFFSET (e, elemsize);
        }
        sub->e = e;
@@ -509,7 +509,7 @@ hash_next (struct hash_iter *it)
        int32 elemsize = it->elemsize;
        struct hash_iter_sub *sub = &it->subtable_state[it->i];
        struct hash_entry *e = sub->e;
-       struct hash_entry *end = sub->end;
+       struct hash_entry *last = sub->last;
        hash_hash_t e_hash = 0;
 
        if (it->changes != it->h->changes) {    /* hash table's structure changed; recompute */
@@ -518,7 +518,7 @@ hash_next (struct hash_iter *it)
                iter_restart (it, it->h->st, 0);
                sub = &it->subtable_state[it->i];
                e = sub->e;
-               end = sub->end;
+               last = sub->last;
        }
        if (e != sub->start && it->last_hash != HASH_OFFSET (e, -elemsize)->hash) {
                struct hash_entry *start = HASH_OFFSET (e, -(elemsize * it->h->max_probes));
@@ -531,16 +531,16 @@ hash_next (struct hash_iter *it)
                        e = pe;
                        pe = HASH_OFFSET (pe, -elemsize);
                }
-               while (e != end && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
+               while (e <= last && ((e_hash = e->hash) == HASH_NIL || e_hash <= last_hash)) {
                        e = HASH_OFFSET (e, elemsize);
                }
        }
 
        for (;;) {
-               while (e != end && (e_hash = e->hash) == HASH_NIL) {
+               while (e <= last && (e_hash = e->hash) == HASH_NIL) {
                        e = HASH_OFFSET (e, elemsize);
                }
-               if (e == end) {
+               if (e > last) {
                        if (it->i == 0) {
                                it->last_hash = HASH_OFFSET (e, -elemsize)->hash;
                                sub->e = e;
@@ -549,7 +549,7 @@ hash_next (struct hash_iter *it)
                                it->i--;
                                sub = &it->subtable_state[it->i];
                                e = sub->e;
-                               end = sub->end;
+                               last = sub->last;
                        }
                } else if ((e_hash & HASH_MASK) != HASH_SUBHASH) {
                        it->last_hash = e->hash;
@@ -565,7 +565,7 @@ hash_next (struct hash_iter *it)
                        sub = &it->subtable_state[it->i];
                        sub->e = e = st->entry;
                        sub->start = st->entry;
-                       sub->end = end = st->end;
+                       sub->last = last = st->last;
                }
        }
 }
@@ -580,7 +580,7 @@ hash_iter_init (Hmap *h, struct hash_iter *it)
        it->last_hash = 0;
        it->subtable_state[0].e = h->st->entry;
        it->subtable_state[0].start = h->st->entry;
-       it->subtable_state[0].end = h->st->end;
+       it->subtable_state[0].last = h->st->last;
 }
 
 static void
@@ -588,11 +588,11 @@ clean_st (struct hash_subtable *st, int32 *slots, int32 *used)
 {
        int32 elemsize = st->datasize + offsetof (struct hash_entry, data[0]);
        struct hash_entry *e = st->entry;
-       struct hash_entry *end = st->end;
-       int32 lslots = (((byte *) end) - (byte *) e) / elemsize;
+       struct hash_entry *last = st->last;
+       int32 lslots = (((byte *) (last+1)) - (byte *) e) / elemsize;
        int32 lused = 0;
 
-       while (e != end) {
+       while (e <= last) {
                hash_hash_t hash = e->hash;
                if ((hash & HASH_MASK) == HASH_SUBHASH) {
                        clean_st (*(struct hash_subtable **)e->data, slots, used);
@@ -627,7 +627,7 @@ hash_visit_internal (struct hash_subtable *st,
        int32 shift = HASH_BITS - (used + st->power);
        int32 i = 0;
 
-       while (e != st->end) {
+       while (e <= st->last) {
                int32 index = ((e->hash >> (shift - 1)) >> 1) & ((1 << st->power) - 1);
                if ((e->hash & HASH_MASK) == HASH_SUBHASH) {
                          (*data_visit) (arg, level, e->data);
index 19ff41697079b85a1f534267d849020ab85b565e..81b0cff88adf1c956d36980afa14a3099486d97c 100644 (file)
@@ -87,7 +87,7 @@ struct hash_iter {
        struct hash_iter_sub {
                struct hash_entry *e;           /* pointer into subtable */
                struct hash_entry *start;       /* start of subtable */
-               struct hash_entry *end;         /* end of subtable */
+               struct hash_entry *last;                /* last entry in subtable */
        } subtable_state[4];    /* Should be large enough unless the hashing is
                                   so bad that many distinct data values hash
                                   to the same hash value.  */
index a96f3f3828c32e6a84991225bb0310a6fd613cde..b74705e5fbd451a6f75cbf4defcb1f09d0b2a434 100644 (file)
@@ -91,8 +91,8 @@ class MapTypePrinter:
 
        def traverse_hash(self, stab):
                ptr = stab['entry'].address
-               end = stab['end']
-               while ptr < end:
+               last = stab['last']
+               while ptr <= last:
                        v = ptr.dereference()
                        ptr = ptr + 1
                        if v['hash'] == 0: continue