about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik Agaram <vc@akkartik.com>2018-06-24 10:23:27 -0700
committerKartik Agaram <vc@akkartik.com>2018-06-24 10:23:27 -0700
commit3ecee22a8a440b5f299729cbe49aede7e270c67c (patch)
tree2a756da343d10cc5e533cea3aa64d7574fa036d8
parentd82c16098e4f7454b79ee4cad6393949d6f32b18 (diff)
downloadmu-3ecee22a8a440b5f299729cbe49aede7e270c67c.tar.gz
4269 - start validating alloc-ids on lookup
Seems incredible that this is all it took. Needs more testing.

I also need to rethink how we organize our layers about addresses.
Alloc-id stuff is scattered everywhere. The space for alloc-ids is
perhaps unavoidably scattered. Just assume the layout from the start.
But it seems bad that the scenario testing the lookup-time validation is
in the 'abandon' layer when the code is in the 'lookup' layer.
-rw-r--r--034address.cc24
-rw-r--r--035lookup.cc1
-rw-r--r--037abandon.cc38
3 files changed, 58 insertions, 5 deletions
diff --git a/034address.cc b/034address.cc
index 6c4bdda4..a71f5194 100644
--- a/034address.cc
+++ b/034address.cc
@@ -255,19 +255,24 @@ put(Recipe_ordinal, "allocate", ALLOCATE);
 case ALLOCATE: {
   // compute the space we need
   int size = ingredients.at(0).at(0);
+  int alloc_id = Next_alloc_id;
+  Next_alloc_id++;
   if (SIZE(ingredients) > 1) {
     // array allocation
     trace("mem") << "array length is " << ingredients.at(1).at(0) << end();
     size = /*space for length*/1 + size*ingredients.at(1).at(0);
   }
   int result = allocate(size);
+  // initialize alloc-id in payload
+  trace("mem") << "storing alloc-id " << alloc_id << " in location " << result << end();
+  put(Memory, result, alloc_id);
   if (SIZE(current_instruction().ingredients) > 1) {
     // initialize array length
     trace("mem") << "storing array length " << ingredients.at(1).at(0) << " in location " << result+/*skip alloc id*/1 << end();
     put(Memory, result+/*skip alloc id*/1, ingredients.at(1).at(0));
   }
   products.resize(1);
-  products.at(0).push_back(/*alloc id*/0);
+  products.at(0).push_back(alloc_id);
   products.at(0).push_back(result);
   break;
 }
@@ -331,6 +336,23 @@ def main [
   1:&:num <- new num:type
 ]
 +mem: storing 0 in location 10
++mem: storing 0 in location 11
++mem: storing 10 in location 2
+
+:(scenario new_initializes_alloc_id)
+% Memory_allocated_until = 10;
+% put(Memory, Memory_allocated_until, 1);
+% Next_alloc_id = 23;
+def main [
+  1:&:num <- new num:type
+]
+# initialize memory
++mem: storing 0 in location 10
++mem: storing 0 in location 11
+# alloc-id in payload
++mem: storing alloc-id 23 in location 10
+# alloc-id in address
++mem: storing 23 in location 1
 
 :(scenario new_size)
 def main [
diff --git a/035lookup.cc b/035lookup.cc
index 3b9ae6a2..02c2ab3f 100644
--- a/035lookup.cc
+++ b/035lookup.cc
@@ -102,6 +102,7 @@ void lookup_memory_core(reagent& x, bool check_for_null) {
   // validate alloc-id
   double alloc_id_in_address = get_or_insert(Memory, x.value);
   double alloc_id_in_payload = get_or_insert(Memory, new_value);
+//?   cerr << x.value << ": " << alloc_id_in_address << " vs " << new_value << ": " << alloc_id_in_payload << '\n';
   if (alloc_id_in_address != alloc_id_in_payload) {
       raise << maybe(current_recipe_name()) << "address is already abandoned in '" << to_original_string(current_instruction()) << "'\n" << end();
       dump_callstack();
diff --git a/037abandon.cc b/037abandon.cc
index ca7c242c..c2b9125e 100644
--- a/037abandon.cc
+++ b/037abandon.cc
@@ -14,6 +14,18 @@ def main [
 
 //: When abandoning addresses we'll save them to a 'free list', segregated by size.
 
+//: Before, suppose variable V contains address A which points to payload P:
+//:   location V contains an alloc-id N
+//:   location V+1 contains A
+//:   location A contains alloc-id N
+//:   location A+1 onwards contains P
+//: Additionally, suppose the head of the free list is initially F.
+//: After abandoning:
+//:   location V contains invalid alloc-id -1
+//:   location V+1 contains 0
+//:   location A contains invalid alloc-id N
+//:   location A+1 contains the previous head of free-list F
+
 :(before "End routine Fields")
 map<int, int> free_list;
 
@@ -40,18 +52,23 @@ case ABANDON: {
     reagent/*copy*/ ingredient = current_instruction().ingredients.at(i);
     canonize(ingredient);
     abandon(get_or_insert(Memory, ingredient.value+/*skip alloc id*/1), payload_size(ingredient));
+//?     cerr << "clear after abandon: " << ingredient.value << '\n';
+    put(Memory, /*alloc id*/ingredient.value, /*invalid*/-1);
+    put(Memory, /*address*/ingredient.value+1, 0);
   }
   break;
 }
 
 :(code)
 void abandon(int address, int payload_size) {
-  // clear memory
-  for (int curr = address;  curr < address+payload_size;  ++curr)
+  put(Memory, address, /*invalid alloc-id*/-1);
+//?   cerr << "abandon: " << address << '\n';
+  // clear rest of payload
+  for (int curr = address+1;  curr < address+payload_size;  ++curr)
     put(Memory, curr, 0);
   // append existing free list to address
   trace("abandon") << "saving " << address << " in free-list of size " << payload_size << end();
-  put(Memory, address, get_or_insert(Current_routine->free_list, payload_size));
+  put(Memory, address+/*skip invalid alloc-id*/1, get_or_insert(Current_routine->free_list, payload_size));
   put(Current_routine->free_list, payload_size, address);
 }
 
@@ -66,8 +83,11 @@ if (get_or_insert(Current_routine->free_list, size)) {
   trace("abandon") << "picking up space from free-list of size " << size << end();
   int result = get_or_insert(Current_routine->free_list, size);
   trace("mem") << "new alloc from free list: " << result << end();
-  put(Current_routine->free_list, size, get_or_insert(Memory, result));
+  put(Current_routine->free_list, size, get_or_insert(Memory, result+/*skip alloc id*/1));
+  // clear 'deleted' tag
   put(Memory, result, 0);
+  // clear next pointer
+  put(Memory, result+/*skip alloc id*/1, 0);
   for (int curr = result;  curr < result+size;  ++curr) {
     if (get_or_insert(Memory, curr) != 0) {
       raise << maybe(current_recipe_name()) << "memory in free list was not zeroed out: " << curr << '/' << result << "; somebody wrote to us after free!!!\n" << end();
@@ -100,3 +120,13 @@ def main [
 ]
 # both calls to new returned identical addresses
 +mem: storing 1 in location 50
+
+:(scenario lookup_of_abandoned_address_raises_error)
+% Hide_errors = true;
+def main [
+  1:&:num <- new num:type
+  3:&:num <- copy 1:&:num
+  abandon 1:&:num
+  5:num/raw <- copy *3:&:num
+]
++error: main: address is already abandoned in '5:num/raw <- copy *3:&:num'