aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2011-10-03 13:34:24 -0400
committerRuss Cox <rsc@golang.org>2011-10-03 13:34:24 -0400
commitaf68419ab264f48275563674729109d551185355 (patch)
tree56b58fb26adf9e3a0122f78e6b0bdd8139ee2591
parent4af7136fcf874e212d66c72178a68db969918b25 (diff)
downloadgo-af68419ab264f48275563674729109d551185355.tar.gz
go-af68419ab264f48275563674729109d551185355.zip
[release-branch.r60] runtime: fix map memory leak
««« 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
-rw-r--r--src/cmd/ld/dwarf.c2
-rw-r--r--src/pkg/runtime/hashmap.c58
-rw-r--r--src/pkg/runtime/hashmap.h2
-rw-r--r--src/pkg/runtime/runtime-gdb.py4
4 files changed, 33 insertions, 33 deletions
diff --git a/src/cmd/ld/dwarf.c b/src/cmd/ld/dwarf.c
index 77536018a5..373cf55237 100644
--- a/src/cmd/ld/dwarf.c
+++ b/src/cmd/ld/dwarf.c
@@ -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);
diff --git a/src/pkg/runtime/hashmap.c b/src/pkg/runtime/hashmap.c
index 0c0e3e4a2d..22664b5488 100644
--- a/src/pkg/runtime/hashmap.c
+++ b/src/pkg/runtime/hashmap.c
@@ -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);
diff --git a/src/pkg/runtime/hashmap.h b/src/pkg/runtime/hashmap.h
index 19ff416970..81b0cff88a 100644
--- a/src/pkg/runtime/hashmap.h
+++ b/src/pkg/runtime/hashmap.h
@@ -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. */
diff --git a/src/pkg/runtime/runtime-gdb.py b/src/pkg/runtime/runtime-gdb.py
index a96f3f3828..b74705e5fb 100644
--- a/src/pkg/runtime/runtime-gdb.py
+++ b/src/pkg/runtime/runtime-gdb.py
@@ -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