diff options
author | Kartik K. Agaram <vc@akkartik.com> | 2015-07-17 14:30:17 -0700 |
---|---|---|
committer | Kartik K. Agaram <vc@akkartik.com> | 2015-07-17 14:30:17 -0700 |
commit | 551d155c663a7478efd08fac2db35eda096bef97 (patch) | |
tree | 691273968193068d004d7a4c1c7b82503f048798 | |
parent | 32cd40ec3c9dad33738caf6f55fb742a316bd5be (diff) | |
download | mu-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.cc | 55 | ||||
-rw-r--r-- | 032array.cc | 88 | ||||
-rw-r--r-- | 071print.mu | 62 | ||||
-rw-r--r-- | edit.mu | 18 |
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 |