summary refs log tree commit diff
path: root/src/rt/rust_obstack.cpp
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2012-02-08 12:55:19 -0800
committerNiko Matsakis <niko@alum.mit.edu>2012-02-08 12:55:19 -0800
commita6dde7766ee9c2a397ef05da5c87c064f9f06118 (patch)
treebe39a1b2683c9d72c5054e2363caa5f906588e24 /src/rt/rust_obstack.cpp
parent5f8e0ddccfe4d9797b1e2b293788d023d9916e31 (diff)
fix bug that causes premature pops from obstack
basically, the alignment step did not check if it walked off
the end of the buffer
Diffstat (limited to 'src/rt/rust_obstack.cpp')
-rw-r--r--src/rt/rust_obstack.cpp30
1 files changed, 21 insertions, 9 deletions
diff --git a/src/rt/rust_obstack.cpp b/src/rt/rust_obstack.cpp
index 554043cf4f1..ec12c8f4554 100644
--- a/src/rt/rust_obstack.cpp
+++ b/src/rt/rust_obstack.cpp
@@ -18,7 +18,7 @@
 #endif
 
 #undef DPRINT
-#define DPRINT(fmt, ...)
+#define DPRINT(fmt, ...) 
 
 const size_t DEFAULT_CHUNK_SIZE = 128;
 const size_t MAX_CHUNK_SIZE = (1024*64);
@@ -38,16 +38,20 @@ struct rust_obstack_alloc {
 
 void *
 rust_obstack_chunk::alloc(size_t len, type_desc *tydesc) {
-    alen = align_to(alen, DEFAULT_ALIGNMENT);
+    DPRINT("alloc(%lu) alen=%lu size=%lu\n", len, alen, size);
 
-    if (sizeof(rust_obstack_alloc) + len > size - alen) {
-        DPRINT("Not enough space, len=%lu!\n", len);
+    size_t aligned_alen = align_to(alen, DEFAULT_ALIGNMENT);
+    size_t end_alen = aligned_alen + sizeof(rust_obstack_alloc) + len;
+    if (end_alen > size) {
+        DPRINT("Not enough space, len=%lu alen=%lu aligned=%lu end=%lu!\n",
+               len, alen, aligned_alen, end_alen);
         return NULL;    // Not enough space.
     }
 
-    rust_obstack_alloc *a = new(data + alen) rust_obstack_alloc(len, tydesc);
-    alen += sizeof(*a) + len;
+    rust_obstack_alloc *a =
+      new(data + aligned_alen) rust_obstack_alloc(len, tydesc);
     memset(a->data, '\0', len); // FIXME: For GC.
+    alen = end_alen;
     return &a->data;
 }
 
@@ -63,7 +67,9 @@ rust_obstack_chunk::free(void *ptr) {
 
 void *
 rust_obstack_chunk::mark() {
-    return data + alen;
+    uint8_t *m = data + alen;
+    assert (m >= data && m <= data+size);
+    return m;
 }
 
 // Allocates the given number of bytes in a new chunk.
@@ -109,7 +115,9 @@ rust_obstack::free(void *ptr) {
 
     assert(chunk);
     while (!chunk->free(ptr)) {
-        DPRINT("deleting chunk at %p\n", chunk);
+        DPRINT("deleting chunk at %p (ptr=%p, data=%p-%p)\n",
+               chunk, ptr,
+               chunk->data, chunk->data + chunk->size);
         rust_obstack_chunk *prev = chunk->prev;
         task->free(chunk);
         chunk = prev;
@@ -119,7 +127,11 @@ rust_obstack::free(void *ptr) {
 
 void *
 rust_obstack::mark() {
-    return chunk ? chunk->mark() : NULL;
+    void *m = chunk ? chunk->mark() : NULL;
+    DPRINT("mark == %p, chunk == %p, data == %p-%p\n", m, chunk,
+           (chunk ? chunk->data : NULL),
+           (chunk ? chunk->data + chunk->size : NULL));
+    return m;
 }