about summary refs log tree commit diff stats
diff options
context:
space:
mode:
authorKartik K. Agaram <vc@akkartik.com>2015-07-17 14:30:17 -0700
committerKartik K. Agaram <vc@akkartik.com>2015-07-17 14:30:17 -0700
commit551d155c663a7478efd08fac2db35eda096bef97 (patch)
tree691273968193068d004d7a4c1c7b82503f048798
parent32cd40ec3c9dad33738caf6f55fb742a316bd5be (diff)
downloadmu-551d155c663a7478efd08fac2db35eda096bef97.tar.gz
1800 - ah, found the bounds-checking bug
I was counting locations when I should have been counting elements.
-rw-r--r--030container.cc55
-rw-r--r--032array.cc88
-rw-r--r--071print.mu62
-rw-r--r--edit.mu18
4 files changed, 168 insertions, 55 deletions
diff --git a/030container.cc b/030container.cc
index 4b013450..f90e92ba 100644
--- a/030container.cc
+++ b/030container.cc
@@ -112,15 +112,17 @@ case GET: {
   assert(is_literal(current_instruction().ingredients.at(1)));
   assert(scalar(ingredients.at(1)));
   long long int offset = ingredients.at(1).at(0);
-  assert(offset >= 0);
-  assert(offset < size_of(base));
   long long int src = base_address;
   for (long long int i = 0; i < offset; ++i) {
     src += size_of(Type[base_type].elements.at(i));
   }
   trace(Primitive_recipe_depth, "run") << "address to copy is " << src;
   assert(Type[base_type].kind == container);
-  assert(SIZE(Type[base_type].elements) > offset);
+  if (offset < 0 || offset >= SIZE(Type[base_type].elements)) {
+    raise << current_recipe_name() << ": invalid offset " << offset << " for " << Type[base_type].name << '\n';
+    products.resize(1);
+    break;
+  }
   type_ordinal src_type = Type[base_type].elements.at(offset).at(0);
   trace(Primitive_recipe_depth, "run") << "its type is " << Type[src_type].name;
   reagent tmp;
@@ -149,6 +151,26 @@ recipe main [
 ]
 +mem: storing 13 in location 15
 
+:(scenario get_out_of_bounds)
+% Hide_warnings = true;
+recipe main [
+  12:number <- copy 34:literal
+  13:number <- copy 35:literal
+  14:number <- copy 36:literal
+  get 12:point-number/raw, 2:offset  # point-number occupies 3 locations but has only 2 fields; out of bounds
+]
++warn: main: invalid offset 2 for point-number
+
+:(scenario get_out_of_bounds2)
+% Hide_warnings = true;
+recipe main [
+  12:number <- copy 34:literal
+  13:number <- copy 35:literal
+  14:number <- copy 36:literal
+  get 12:point-number/raw, -1:offset
+]
++warn: main: invalid offset -1 for point-number
+
 :(before "End Primitive Recipe Declarations")
 GET_ADDRESS,
 :(before "End Primitive Recipe Numbers")
@@ -163,8 +185,11 @@ case GET_ADDRESS: {
   assert(is_literal(current_instruction().ingredients.at(1)));
   assert(scalar(ingredients.at(1)));
   long long int offset = ingredients.at(1).at(0);
-  assert(offset >= 0);
-  assert(offset < size_of(base));
+  if (offset < 0 || offset >= SIZE(Type[base_type].elements)) {
+    raise << "invalid offset " << offset << " for " << Type[base_type].name << '\n';
+    products.resize(1);
+    break;
+  }
   long long int result = base_address;
   for (long long int i = 0; i < offset; ++i) {
     result += size_of(Type[base_type].elements.at(i));
@@ -175,6 +200,26 @@ case GET_ADDRESS: {
   break;
 }
 
+:(scenario get_address_out_of_bounds)
+% Hide_warnings = true;
+recipe main [
+  12:number <- copy 34:literal
+  13:number <- copy 35:literal
+  14:number <- copy 36:literal
+  get-address 12:point-number/raw, 2:offset  # point-number occupies 3 locations but has only 2 fields; out of bounds
+]
++warn: invalid offset 2 for point-number
+
+:(scenario get_address_out_of_bounds2)
+% Hide_warnings = true;
+recipe main [
+  12:number <- copy 34:literal
+  13:number <- copy 35:literal
+  14:number <- copy 36:literal
+  get-address 12:point-number/raw, -1:offset
+]
++warn: invalid offset -1 for point-number
+
 //:: Allow containers to be defined in mu code.
 
 :(scenarios load)
diff --git a/032array.cc b/032array.cc
index 20cba6fe..e9aef14c 100644
--- a/032array.cc
+++ b/032array.cc
@@ -87,8 +87,11 @@ case INDEX: {
   vector<type_ordinal> element_type = array_element(base.types);
 //?   trace(Primitive_recipe_depth, "run") << "offset: " << offset_val.at(0); //? 1
 //?   trace(Primitive_recipe_depth, "run") << "size of elements: " << size_of(element_type); //? 1
-  assert(offset_val.at(0) >= 0);
-  assert(offset_val.at(0) < Memory[base_address]*size_of(element_type) + 1);
+  if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
+    raise << current_recipe_name() << ": invalid index " << offset_val.at(0) << '\n';
+    products.resize(1);
+    break;
+  }
   long long int src = base_address + 1 + offset_val.at(0)*size_of(element_type);
   trace(Primitive_recipe_depth, "run") << "address to copy is " << src;
   trace(Primitive_recipe_depth, "run") << "its type is " << Type[element_type.at(0)].name;
@@ -104,28 +107,58 @@ vector<type_ordinal> array_element(const vector<type_ordinal>& types) {
   return vector<type_ordinal>(++types.begin(), types.end());
 }
 
-:(scenario index_address)
+:(scenario index_indirect)
 recipe main [
   1:number <- copy 3:literal  # length
   2:number <- copy 14:literal
   3:number <- copy 15:literal
   4:number <- copy 16:literal
-  5:number <- index-address 1:array:number/raw, 0:literal  # unsafe
+  5:address:array:number <- copy 1:literal
+  6:number <- index 5:address:array:number/deref, 1:literal
 ]
-+mem: storing 2 in location 5
++mem: storing 15 in location 6
+
+:(scenario index_out_of_bounds)
+% Hide_warnings = true;
+recipe main [
+  1:number <- copy 3:literal  # 3 points
+  2:number <- copy 14:literal
+  3:number <- copy 15:literal
+  4:number <- copy 16:literal
+  5:number <- copy 14:literal
+  6:number <- copy 15:literal
+  7:number <- copy 16:literal
+  8:address:array:point <- copy 1:literal
+  index 8:address:array:point/deref, 4:literal  # less than size of array in locations, but larger than its length in elements
+]
++warn: main: invalid index 4
+
+:(scenario index_out_of_bounds2)
+% Hide_warnings = true;
+recipe main [
+  1:number <- copy 3:literal  # 3 points
+  2:number <- copy 14:literal
+  3:number <- copy 15:literal
+  4:number <- copy 16:literal
+  5:number <- copy 14:literal
+  6:number <- copy 15:literal
+  7:number <- copy 16:literal
+  8:address:array:point <- copy 1:literal
+  index 8:address:array:point/deref, -1:literal
+]
++warn: main: invalid index -1
 
 //:: To write to elements of containers, you need their address.
 
-:(scenario index_indirect)
+:(scenario index_address)
 recipe main [
   1:number <- copy 3:literal  # length
   2:number <- copy 14:literal
   3:number <- copy 15:literal
   4:number <- copy 16:literal
-  5:address:array:number <- copy 1:literal
-  6:number <- index 5:address:array:number/deref, 1:literal
+  5:number <- index-address 1:array:number/raw, 0:literal  # unsafe
 ]
-+mem: storing 15 in location 6
++mem: storing 2 in location 5
 
 :(before "End Primitive Recipe Declarations")
 INDEX_ADDRESS,
@@ -139,14 +172,47 @@ case INDEX_ADDRESS: {
   reagent offset = canonize(current_instruction().ingredients.at(1));
   vector<double> offset_val(read_memory(offset));
   vector<type_ordinal> element_type = array_element(base.types);
-  assert(offset_val.at(0) >= 0);
-  assert(offset_val.at(0) < Memory[base_address]*size_of(element_type) + 1);
+  if (offset_val.at(0) < 0 || offset_val.at(0) >= Memory[base_address]) {
+    raise << current_recipe_name() << ": invalid index " << offset_val.at(0) << '\n';
+    products.resize(1);
+    break;
+  }
   long long int result = base_address + 1 + offset_val.at(0)*size_of(element_type);
   products.resize(1);
   products.at(0).push_back(result);
   break;
 }
 
+:(scenario index_address_out_of_bounds)
+% Hide_warnings = true;
+recipe main [
+  1:number <- copy 3:literal  # 3 points
+  2:number <- copy 14:literal
+  3:number <- copy 15:literal
+  4:number <- copy 16:literal
+  5:number <- copy 14:literal
+  6:number <- copy 15:literal
+  7:number <- copy 16:literal
+  8:address:array:point <- copy 1:literal
+  index-address 8:address:array:point/deref, 4:literal  # less than size of array in locations, but larger than its length in elements
+]
++warn: main: invalid index 4
+
+:(scenario index_address_out_of_bounds2)
+% Hide_warnings = true;
+recipe main [
+  1:number <- copy 3:literal  # 3 points
+  2:number <- copy 14:literal
+  3:number <- copy 15:literal
+  4:number <- copy 16:literal
+  5:number <- copy 14:literal
+  6:number <- copy 15:literal
+  7:number <- copy 16:literal
+  8:address:array:point <- copy 1:literal
+  index-address 8:address:array:point/deref, -1:literal
+]
++warn: main: invalid index -1
+
 //:: compute the length of an array
 
 :(scenario array_length)
diff --git a/071print.mu b/071print.mu
index e8071b6e..c68f1e55 100644
--- a/071print.mu
+++ b/071print.mu
@@ -91,6 +91,8 @@ recipe fake-screen-is-clear? [
 
 recipe print-character [
   local-scope
+#?   $print [--- #? 1
+#? ] #? 1
   x:address:screen <- next-ingredient
   c:character <- next-ingredient
   color:number, color-found?:boolean <- next-ingredient
@@ -105,8 +107,6 @@ recipe print-character [
     break-if bg-color-found?:boolean
     bg-color:number <- copy 0:literal/black
   }
-  screen-width:number <- screen-width x:address:screen
-  screen-height:number <- screen-height x:address:screen
 #?   $print [eee ] #? 1
 #?   $foo #? 1
 #?   trace [app], [print character] #? 1
@@ -114,23 +114,18 @@ recipe print-character [
     # if x exists
     # (handle special cases exactly like in the real screen)
     break-unless x:address:screen
-    row:address:number <- get-address x:address:screen/deref, cursor-row:offset
-#?     $dump row:address:number/deref
-    legal?:boolean <- greater-or-equal row:address:number/deref, 0:literal
-    reply-unless legal?:boolean, x:address:screen
-    assert legal?:boolean, [row too small in print-character]
-    legal?:boolean <- lesser-than row:address:number/deref, screen-height:number
-    reply-unless legal?:boolean, x:address:screen
-    assert legal?:boolean, [row too large in print-character]
-    column:address:number <- get-address x:address:screen/deref, cursor-column:offset
-    legal?:boolean <- greater-or-equal column:address:number/deref, 0:literal
-    reply-unless legal?:boolean, x:address:screen
-    assert legal?:boolean, [column too small in print-character]
-    legal?:boolean <- lesser-than column:address:number/deref, screen-width:number
-    reply-unless legal?:boolean, x:address:screen
-    assert legal?:boolean, [column too large in print-character]
     width:number <- get x:address:screen/deref, num-columns:offset
     height:number <- get x:address:screen/deref, num-rows:offset
+    row:address:number <- get-address x:address:screen/deref, cursor-row:offset
+#?     legal?:boolean <- greater-or-equal row:address:number/deref, 0:literal
+#?     reply-unless legal?:boolean, x:address:screen
+#?     legal?:boolean <- lesser-than row:address:number/deref, height:number
+#?     reply-unless legal?:boolean, x:address:screen
+    column:address:number <- get-address x:address:screen/deref, cursor-column:offset
+#?     legal?:boolean <- greater-or-equal column:address:number/deref, 0:literal
+#?     reply-unless legal?:boolean, x:address:screen
+#?     legal?:boolean <- lesser-than column:address:number/deref, width:number
+#?     reply-unless legal?:boolean, x:address:screen
 #?   $print [fff ] #? 1
 #?   $foo #? 1
     # special-case: newline
@@ -163,6 +158,7 @@ recipe print-character [
     {
       backspace?:boolean <- equal c:character, 8:literal
       break-unless backspace?:boolean
+#?       $print [$$$]  # shouldn't come here #? 1
       {
         # unless cursor is already at left margin
         at-left?:boolean <- lesser-or-equal column:address:number/deref, 0:literal
@@ -183,29 +179,31 @@ recipe print-character [
 #?     $print [saving character ], c:character, [ to fake screen ], cursor:address/screen, [ 
 #? ] #? 1
     cursor:address:screen-cell <- index-address buf:address:array:screen-cell/deref, index:number
+#?     $dump cursor:address:screen-cell #? 1
 #?     $print [iii ] #? 1
 #?     $foo #? 1
     cursor-contents:address:character <- get-address cursor:address:screen-cell/deref, contents:offset
+#?     $dump cursor-contents:address:character #? 1
 #?     $print [jjj ] #? 1
 #?     $foo #? 1
     cursor-color:address:number <- get-address cursor:address:screen-cell/deref, color:offset
-#?     $print [kkk ] #? 1
-#?     $foo #? 1
-#?   $dump cursor-contents:address:character
+#?     $print [kkk ] #? 2
+#?     $foo #? 2
+#?     $dump cursor-color:address:character #? 1
     cursor-contents:address:character/deref <- copy c:character
-#?     $print [lll ] #? 1
-#?     $foo #? 1
-#?     $dump x:address:screen
-#?     $dump buf:address:array:screen-cell
-#?     $dump height:number
-#?     $dump width:number
-#?     $dump row:address:number/deref
-#?     $dump column:address:number/deref
-#?     $dump index:number
-#?     $dump len:number
+#?     $print [lll ] #? 2
+#?     $foo #? 2
+#?     $dump x:address:screen #? 1
+#?     $dump buf:address:array:screen-cell #? 1
+#?     $dump height:number #? 1
+#?     $dump width:number #? 1
+#?     $dump row:address:number/deref #? 1
+#?     $dump column:address:number/deref #? 1
+#?     $dump index:number #? 1
+#?     $dump len:number #? 1
     cursor-color:address:number/deref <- copy color:number
-#?     $print [mmm ] #? 1
-#?     $foo #? 1
+#?     $print [mmm ] #? 2
+#?     $foo #? 2
     # increment column unless it's already all the way to the right
     {
       right:number <- subtract width:number, 1:literal
diff --git a/edit.mu b/edit.mu
index 4bbf47b5..6ede1e4e 100644
--- a/edit.mu
+++ b/edit.mu
@@ -369,6 +369,7 @@ recipe render-screen [
     done?:boolean <- greater-or-equal row:number, screen-height:number
     break-if done?:boolean
     column:number <- copy left:number
+    $dump row:number
     move-cursor screen:address, row:number, column:number
     # initial leader for each row: two spaces and a '.'
     print-character screen:address, 32:literal/space, 245:literal/grey
@@ -1112,6 +1113,7 @@ recipe render-sandboxes [
   screen-height:number <- screen-height screen:address:screen
   at-bottom?:boolean <- greater-or-equal row:number screen-height:number
   reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
+  $dump row:number
   # render sandbox contents
   sandbox-data:address:array:character <- get sandbox:address:sandbox-data/deref, data:offset
   row:number, screen:address:screen <- render-string screen:address:screen, sandbox-data:address:array:character, left:number, right:number, 7:literal/white, row:number
@@ -1129,26 +1131,28 @@ recipe render-sandboxes [
   }
   # render sandbox screen if necessary
   at-bottom?:boolean <- greater-or-equal row:number screen-height:number
-  reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
+#?   reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
+  $dump row:number
   {
     empty-screen?:boolean <- fake-screen-is-clear? sandbox-screen:address:screen
     break-if empty-screen?:boolean
     row:number, screen:address:screen <- render-screen screen:address:screen, sandbox-screen:address:screen, left:number, right:number, row:number
   }
   at-bottom?:boolean <- greater-or-equal row:number screen-height:number
-  reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
+#?   reply-if at-bottom?:boolean, row:number/same-as-ingredient:4, screen:address:screen/same-as-ingredient:0
+  $dump row:number
   # draw solid line after sandbox
-#?   $print [aaa ]
-#?   $dump screen:address:screen
+  $print [aaa ]
+  $dump screen:address:screen
 #?   $dump right:number
-#?   $foo screen:address:screen
+  $foo screen:address:screen
 #?   xxx:address:array:screen-cell <- get screen:address:screen/deref, data:offset
 #?   $dump xxx:address:array:screen-cell
 #?   yyy:number <- length xxx:address:array:screen-cell/deref
 #?   $dump yyy:number
   draw-horizontal screen:address:screen, row:number, left:number, right:number, 9473:literal/horizontal-double
-#?   $print [zzz ]
-#?   $dump screen:address:screen
+  $print [zzz ]
+  $dump screen:address:screen
   # draw next sandbox
   next-sandbox:address:sandbox-data <- get sandbox:address:sandbox-data/deref, next-sandbox:offset
   row:number, screen:address:screen <- render-sandboxes screen:address:screen, next-sandbox:address:sandbox-data, left:number, right:number, row:number