From 1696ed831a99585c22701953790c5c8e4ef7f8f3 Mon Sep 17 00:00:00 2001 From: Kartik Agaram Date: Tue, 17 Nov 2020 18:14:43 -0800 Subject: 7261 - mu.subx: array bounds-checking done --- 313index-bounds-check.subx | 84 ++++++++++++ apps/mu | Bin 564312 -> 567191 bytes apps/mu.subx | 334 ++++++++++++++++++++++++++++++++------------- mu.md | 2 +- mu_instructions | 20 +-- 5 files changed, 333 insertions(+), 107 deletions(-) create mode 100644 313index-bounds-check.subx diff --git a/313index-bounds-check.subx b/313index-bounds-check.subx new file mode 100644 index 00000000..1349e3d4 --- /dev/null +++ b/313index-bounds-check.subx @@ -0,0 +1,84 @@ +# Helper to check an array's bounds, and to abort if they're violated. +# Really only intended to be called from code generated by mu.subx. + +== code + +__check-mu-array-bounds: # index: int, elem-size: int, arr-size: int, function-name: (addr array byte), array-name: (addr array byte) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + # . not bothering saving ebx; it's only clobbered if we're going to abort + # ecx = arr-size + 8b/-> *(ebp+0x10) 1/r32/ecx + # var overflow/edx: int = 0 + ba/copy-to-edx 0/imm32 + # var offset/eax: int = index * elem-size + 8b/-> *(ebp+8) 0/r32/eax + f7 4/subop/multiply-eax-with *(ebp+0xc) + # check for overflow + 81 7/subop/compare %edx 0/imm32 + 0f 85/jump-if-!= __check-mu-array-bounds:overflow/disp32 + # check bounds + 39/compare %eax 1/r32/ecx + 0f 82/jump-if-unsigned< $__check-mu-array-bounds:end/disp32 # negative index should always abort + # abort if necessary + (write-buffered Stderr "fn ") + (write-buffered Stderr *(ebp+0x14)) + (write-buffered Stderr ": offset ") + (write-int32-hex-buffered Stderr %eax) + (write-buffered Stderr " is too large for array '") + (write-buffered Stderr *(ebp+0x18)) + (write-buffered Stderr "'\n") + (flush Stderr) + # exit(1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 +$__check-mu-array-bounds:end: + # . restore registers + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + +__check-mu-array-bounds:overflow: + # "fn " function-name ": offset to array '" array-name "' overflowed 32 bits\n" + (write-buffered Stderr "fn ") + (write-buffered Stderr *(ebp+0x14)) + (write-buffered Stderr ": offset to array '") + (write-buffered Stderr *(ebp+0x18)) + (write-buffered Stderr "' overflowed 32 bits\n") + (flush Stderr) + # exit(1) + bb/copy-to-ebx 1/imm32 + e8/call syscall_exit/disp32 + +# potential alternative + +#? __bounds-check: # msg: (addr array byte) +#? (write-buffered Stderr "abort: array bounds exceeded in fn ") +#? 8b/-> *(esp+4) 0/r32/eax # we're going to abort, so just clobber away +#? (write-buffered Stderr %eax) +#? (write-buffered Stderr Newline) +#? # exit(1) +#? bb/copy-to-ebx 1/imm32 +#? e8/call syscall_exit/disp32 + +# to be called as follows: +# var/reg <- index arr/rega: (addr array T), idx/regi: int +# | if size-of(T) is 1, 2, 4 or 8 +# => # temporarily save array size to reg to check bounds +# "8b/-> *" rega " " reg "/r32" +# "c1/shift 5/subop/right %" reg " " log2(size-of(T)) "/imm32" +# "3b/compare " reg "/r32 *" rega +# "68/push \"" function "\"/imm32" # pass function name to error message +# "0f 8d/jump-if->= __bounds_check/disp32" +# "81 0/subop/add %esp 4/imm32" # drop function name +# # actually save the index addr in reg +# "8d/copy-address *(" rega "+" regi "<<" log2(size-of(T)) "+4) " reg "/r32" diff --git a/apps/mu b/apps/mu index 62632aa7..4437dab7 100755 Binary files a/apps/mu and b/apps/mu differ diff --git a/apps/mu.subx b/apps/mu.subx index 139e04fa..3ceb5f29 100644 --- a/apps/mu.subx +++ b/apps/mu.subx @@ -5997,15 +5997,16 @@ test-convert-index-into-array: (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array/7") (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array/8") (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array/9") - (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32" "F - test-convert-index-into-array/10") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array/11") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array/12") - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array/13") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array/14") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array/15") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array/16") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array/17") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array/18") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 0x00000004 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array/10") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000002 + 4) 0x00000000/r32" "F - test-convert-index-into-array/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array/13") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array/19") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -6046,15 +6047,16 @@ test-convert-index-into-array-of-bytes: (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-of-bytes/7") (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-of-bytes/8") (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-of-bytes/9") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 0x00000001 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes/10") (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000000 + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes/11") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes/13") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes/14") - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes/15") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes/16") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes/17") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes/18") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes/19") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes/20") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes/13") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes/19") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -6092,15 +6094,16 @@ test-convert-index-into-array-with-literal: (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-with-literal/5") (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-with-literal/6") (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-with-literal/7") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds 2 0x00000004 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-with-literal/8") # 2 * 4 bytes/elem + 4 bytes for size = offset 12 - (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x0000000c) 0x00000000/r32" "F - test-convert-index-into-array-with-literal/8") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-with-literal/9") - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-with-literal/10") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-with-literal/11") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-with-literal/12") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-with-literal/13") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-with-literal/14") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-with-literal/15") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x0000000c) 0x00000000/r32" "F - test-convert-index-into-array-with-literal/9") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-with-literal/10") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-with-literal/11") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-with-literal/12") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-with-literal/13") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-with-literal/14") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-with-literal/15") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-with-literal/16") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -6138,6 +6141,7 @@ test-convert-index-into-array-of-bytes-with-literal: (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:loop:" "F - test-convert-index-into-array-of-bytes-with-literal/5") (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-of-bytes-with-literal/6") (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-index-into-array-of-bytes-with-literal/7") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds 2 0x00000001 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes-with-literal/8") # 2 * 1 byte/elem + 4 bytes for size = offset 6 (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + 0x00000006) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-with-literal/8") (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-with-literal/9") @@ -6189,19 +6193,20 @@ test-convert-index-into-array-on-stack: # var idx (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack/8") (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 2/imm32" "F - test-convert-index-into-array-on-stack/9") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %eax 0x00000004 *(ebp+0xfffffff0) \"foo\" \"arr\")" "F - test-convert-index-into-array-on-stack/10") # var x is at (ebp-0x10) + idx<<2 + 4 = ebp + idx<<2 - 0xc - (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + eax<<0x00000002 + 0xfffffff4) 0x00000000/r32" "F - test-convert-index-into-array-on-stack/10") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + eax<<0x00000002 + 0xfffffff4) 0x00000000/r32" "F - test-convert-index-into-array-on-stack/11") # reclaim idx - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack/11") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack/12") # reclaim arr - (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack/12") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack/13") # - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack/13") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack/14") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack/15") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack/16") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack/17") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack/18") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack/19") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -6242,19 +6247,20 @@ test-convert-index-into-array-on-stack-with-literal: (check-next-stream-line-equal _test-output-stream " 68/push 0x0000000c/imm32" "F - test-convert-index-into-array-on-stack-with-literal/7") # var x (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-on-stack-with-literal/8") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds 2 0x00000004 *(ebp+0xfffffff0) \"foo\" \"arr\")" "F - test-convert-index-into-array-on-stack-with-literal/9") # x is at (ebp-0x10) + 4 + 2*4 = ebp-4 - (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + 0xfffffffc) 0x00000000/r32" "F - test-convert-index-into-array-on-stack-with-literal/9") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + 0xfffffffc) 0x00000000/r32" "F - test-convert-index-into-array-on-stack-with-literal/10") # reclaim x - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack-with-literal/10") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-on-stack-with-literal/11") # reclaim arr - (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack-with-literal/11") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000010/imm32" "F - test-convert-index-into-array-on-stack-with-literal/12") # - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack-with-literal/12") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack-with-literal/13") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack-with-literal/14") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack-with-literal/15") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack-with-literal/16") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack-with-literal/17") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-on-stack-with-literal/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-on-stack-with-literal/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-on-stack-with-literal/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-on-stack-with-literal/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-on-stack-with-literal/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-on-stack-with-literal/18") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -6295,19 +6301,20 @@ test-convert-index-into-array-of-bytes-on-stack-with-literal: (check-next-stream-line-equal _test-output-stream " 68/push 0x00000003/imm32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/7") # var x (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %eax" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/8") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds 2 0x00000001 *(ebp+0xfffffff9) \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/9") # x is at (ebp-7) + 4 + 2 = ebp-1 - (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + 0xffffffff) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/9") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(ebp + 0xffffffff) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/10") # reclaim x - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/10") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/11") # reclaim arr - (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000007/imm32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/11") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000007/imm32" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12") # - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/12") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/16") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/13") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/14") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/15") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/16") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/17") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-on-stack-with-literal/18") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -6350,15 +6357,16 @@ test-convert-index-into-array-using-offset: (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset/8") (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-using-offset/9") (check-next-stream-line-equal _test-output-stream " 69/multiply %ecx 0x00000004/imm32 0x00000001/r32" "F - test-convert-index-into-array-using-offset/10") - (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset/11") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset/12") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset/13") - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset/14") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset/15") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset/16") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset/17") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset/18") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset/19") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-using-offset/11") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset/13") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset/16") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset/17") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset/18") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset/19") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset/20") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -6401,15 +6409,16 @@ test-convert-index-into-array-of-bytes-using-offset: (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-of-bytes-using-offset/8") (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-index-into-array-of-bytes-using-offset/9") (check-next-stream-line-equal _test-output-stream " 69/multiply %ecx 0x00000001/imm32 0x00000001/r32" "F - test-convert-index-into-array-of-bytes-using-offset/10") - (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset/11") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset/12") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset/13") - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset/14") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset/15") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset/16") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset/17") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset/18") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset/19") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes-using-offset/11") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset/13") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset/14") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset/15") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset/16") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset/17") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset/18") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset/19") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset/20") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -6452,16 +6461,17 @@ test-convert-index-into-array-using-offset-on-stack: (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-index-into-array-using-offset-on-stack/8") (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-using-offset-on-stack/9") (check-next-stream-line-equal _test-output-stream " 69/multiply *(ebp+0xfffffff8) 0x00000004/imm32 0x00000001/r32" "F - test-convert-index-into-array-using-offset-on-stack/10") - (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset-on-stack/11") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset-on-stack/12") - (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-using-offset-on-stack/13") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset-on-stack/14") - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset-on-stack/15") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset-on-stack/16") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset-on-stack/17") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset-on-stack/18") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset-on-stack/19") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset-on-stack/20") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-using-offset-on-stack/11") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-using-offset-on-stack/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-using-offset-on-stack/13") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-using-offset-on-stack/14") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-using-offset-on-stack/15") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-using-offset-on-stack/16") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-using-offset-on-stack/17") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-using-offset-on-stack/18") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-using-offset-on-stack/19") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-using-offset-on-stack/20") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-using-offset-on-stack/21") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -6504,16 +6514,17 @@ test-convert-index-into-array-of-bytes-using-offset-on-stack: (check-next-stream-line-equal _test-output-stream " 68/push 0/imm32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/8") (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/9") (check-next-stream-line-equal _test-output-stream " 69/multiply *(ebp+0xfffffff8) 0x00000001/imm32 0x00000001/r32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/10") - (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/11") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/12") - (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/13") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/14") - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/19") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 1 *eax \"foo\" \"arr\")" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/11") + (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx + 4) 0x00000000/r32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/13") + (check-next-stream-line-equal _test-output-stream " 81 0/subop/add %esp 0x00000004/imm32" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/14") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/15") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/16") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/17") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/18") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/19") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/20") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-index-into-array-of-bytes-using-offset-on-stack/21") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -9534,15 +9545,16 @@ test-convert-array-of-user-defined-types: (check-next-stream-line-equal _test-output-stream " b8/copy-to-eax 0/imm32" "F - test-convert-array-of-user-defined-types/7") (check-next-stream-line-equal _test-output-stream " ff 6/subop/push %ecx" "F - test-convert-array-of-user-defined-types/8") (check-next-stream-line-equal _test-output-stream " b9/copy-to-ecx 3/imm32" "F - test-convert-array-of-user-defined-types/9") + (check-next-stream-line-equal _test-output-stream " (__check-mu-array-bounds %ecx 0x00000008 *eax \"foo\" \"arr\")" "F - test-convert-array-of-user-defined-types/10") (check-next-stream-line-equal _test-output-stream " 8d/copy-address *(eax + ecx<<0x00000003 + 4) 0x00000000/r32" "F - test-convert-array-of-user-defined-types/11") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-array-of-user-defined-types/13") - (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-array-of-user-defined-types/14") - (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-array-of-user-defined-types/15") - (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-array-of-user-defined-types/16") - (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-array-of-user-defined-types/17") - (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-array-of-user-defined-types/18") - (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-array-of-user-defined-types/19") - (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-array-of-user-defined-types/20") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %ecx" "F - test-convert-array-of-user-defined-types/12") + (check-next-stream-line-equal _test-output-stream " 8f 0/subop/pop %eax" "F - test-convert-array-of-user-defined-types/13") + (check-next-stream-line-equal _test-output-stream " }" "F - test-convert-array-of-user-defined-types/14") + (check-next-stream-line-equal _test-output-stream "$foo:0x00000001:break:" "F - test-convert-array-of-user-defined-types/15") + (check-next-stream-line-equal _test-output-stream " # . epilogue" "F - test-convert-array-of-user-defined-types/16") + (check-next-stream-line-equal _test-output-stream " 89/<- %esp 5/r32/ebp" "F - test-convert-array-of-user-defined-types/17") + (check-next-stream-line-equal _test-output-stream " 5d/pop-to-ebp" "F - test-convert-array-of-user-defined-types/18") + (check-next-stream-line-equal _test-output-stream " c3/return" "F - test-convert-array-of-user-defined-types/19") # . epilogue 89/<- %esp 5/r32/ebp 5d/pop-to-ebp @@ -24774,6 +24786,11 @@ Curr-local-stack-offset: # (addr int) == code +# We may not need to pass err/ed everywhere here. I think they're relics of Mu +# getting type checks later in life. +# But we do need them for runtime checks, particularly array index bounds checks. +# So perhaps it's not worth taking them out. They're a safety net. + emit-subx: # out: (addr buffered-file), err: (addr buffered-file), ed: (addr exit-descriptor) # . prologue 55/push-ebp @@ -26844,6 +26861,8 @@ translate-mu-index-stmt: # out: (addr buffered-file), stmt: (addr stmt), fn: (a (lookup *(ebx+0xc) *(ebx+0x10)) # Stmt1-inouts Stmt1-inouts => eax (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax 89/<- %ebx 0/r32/eax + # emit bounds-check + (emit-mu-index-bounds-check *(ebp+8) *(ebp+0xc) *(ebp+0x10) *(ebp+0x14) *(ebp+0x18)) # if (var->register) do one thing { 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register @@ -26880,6 +26899,125 @@ $translate-mu-index-stmt:error2: (stop *(ebp+0x18) 1) # never gets here +emit-mu-index-bounds-check: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) + # . prologue + 55/push-ebp + 89/<- %ebp 4/r32/esp + # . save registers + 50/push-eax + 51/push-ecx + 52/push-edx + 53/push-ebx + # ecx = stmt + 8b/-> *(ebp+0xc) 1/r32/ecx + # + (emit-indent *(ebp+8) *Curr-block-depth) + (write-buffered *(ebp+8) "(__check-mu-array-bounds ") +$emit-mu-index-bounds-check:compute-base: + # var base/ebx: (addr var) = inouts[0] + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %ebx 0/r32/eax +$emit-mu-index-bounds-check:emit-index: + # var index/edx: (addr var) = inouts[1] + (lookup *(ecx+0xc) *(ecx+0x10)) # Stmt1-inouts Stmt1-inouts => eax + (lookup *(eax+8) *(eax+0xc)) # Stmt-var-next Stmt-var-next => eax + (lookup *eax *(eax+4)) # Stmt-var-value Stmt-var-value => eax + 89/<- %edx 0/r32/eax + # if index->register, print its code + 81 7/subop/compare *(edx+0x18) 0/imm32 # Var-register + { + 0f 84/jump-if-= break/disp32 +$emit-mu-index-bounds-check:emit-register-index: + (write-buffered *(ebp+8) "%") + (lookup *(edx+0x18) *(edx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + eb/jump $emit-mu-index-bounds-check:index-done/disp8 + } + # otherwise if index is a literal, print it +$emit-mu-index-bounds-check:emit-literal-index: + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 + (lookup *edx *(edx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + } +$emit-mu-index-bounds-check:index-done: + (write-buffered *(ebp+8) " ") +$emit-mu-index-bounds-check:emit-element-size: + # if index is a literal or int, print size of array element + { + { + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 0) # literal => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + (is-simple-mu-type? %eax 1) # int => eax + 3d/compare-eax-and 0/imm32/false + 75/jump-if-!= break/disp8 + eb/jump $emit-mu-index-bounds-check:emit-element-size-offset/disp8 + } +$emit-mu-index-bounds-check:emit-int-register-index: + (array-element-size %ebx *(ebp+0x14) *(ebp+0x18)) # => eax + (write-int32-hex-buffered *(ebp+8) %eax) + e9/jump $emit-mu-index-bounds-check:emit-base/disp32 + } +$emit-mu-index-bounds-check:emit-element-size-offset: + # if index has type (offset ...), print "1" + (lookup *(edx+8) *(edx+0xc)) # Var-type Var-type => eax + 81 7/subop/compare *eax 0/imm32/false # Type-tree-is-atom + { + 75/jump-if-!= break/disp8 + (lookup *(eax+4) *(eax+8)) # Type-tree-left Type-tree-left => eax + (is-simple-mu-type? %eax 7) # => eax + 3d/compare-eax-and 0/imm32/false + { + 0f 84/jump-if-= break/disp32 +$emit-mu-index-bounds-check:emit-offset-register-index: + (write-buffered *(ebp+8) "1") + } + } +$emit-mu-index-bounds-check:emit-base: + # if base is in a register, print " *" base->register + 81 7/subop/compare *(ebx+0x18) 0/imm32 # Var-register + { + 74/jump-if-= break/disp8 + (write-buffered *(ebp+8) " *") + (lookup *(ebx+0x18) *(ebx+0x1c)) # Var-register Var-register => eax + (write-buffered *(ebp+8) %eax) + e9/jump $emit-mu-index-bounds-check:emit-function-name/disp32 + } + # otherwise print " *(ebp+" base->offset ")" + (write-buffered *(ebp+8) " *(ebp+") + (write-int32-hex-buffered *(ebp+8) *(ebx+0x14)) # Var-offset + (write-buffered *(ebp+8) ")") +$emit-mu-index-bounds-check:emit-function-name: + # " \"" function-name "\"" + (write-buffered *(ebp+8) " \"") + 8b/-> *(ebp+0x10) 1/r32/ecx + (lookup *ecx *(ecx+4)) # Function-name Function-name => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "\"") +$emit-mu-index-bounds-check:emit-array-name: + # " \"" base->name "\"" + (write-buffered *(ebp+8) " \"") + (lookup *ebx *(ebx+4)) # Var-name Var-name => eax + (write-buffered *(ebp+8) %eax) + (write-buffered *(ebp+8) "\")\n") +$emit-mu-index-bounds-check:end: + # . restore registers + 5b/pop-to-ebx + 5a/pop-to-edx + 59/pop-to-ecx + 58/pop-to-eax + # . epilogue + 89/<- %esp 5/r32/ebp + 5d/pop-to-ebp + c3/return + translate-mu-index-stmt-with-array-in-register: # out: (addr buffered-file), stmt: (addr stmt), err: (addr buffered-file), ed: (addr exit-descriptor) # . prologue 55/push-ebp diff --git a/mu.md b/mu.md index 8c5975e7..ba0c8b66 100644 --- a/mu.md +++ b/mu.md @@ -681,7 +681,7 @@ populate x, 3 # array of 3 T's I said at the start that most instructions map 1:1 to x86 machine code. To enforce type- and memory-safety, I was forced to carve out a few exceptions: -* the `index` instruction on arrays, for bounds-checking (not yet implemented) +* the `index` instruction on arrays, for bounds-checking * the `length` instruction on arrays, for translating the array size in bytes into the number of elements. * the `lookup` instruction on handles, for validating fat-pointer metadata diff --git a/mu_instructions b/mu_instructions index f487d29a..bd00e7a4 100644 --- a/mu_instructions +++ b/mu_instructions @@ -312,24 +312,28 @@ var/reg: (addr T) <- address var2: T => "8d/copy-address *(ebp+" var2.stack-offset ") " reg "/r32" # Array operations -(TODO: bounds-checking) var/reg <- index arr/rega: (addr array T), idx/regi: int - | if size-of(T) is 4 or 8 - => "8d/copy-address *(" rega "+" regi "<<" log2(size-of(T)) "+4) " reg "/r32" + | if size-of(T) is 1, 2, 4 or 8 + => "(__check-mu-array-bounds *" rega " %" regi " " size-of(T) ")" + "8d/copy-address *(" rega "+" regi "<<" log2(size-of(T)) "+4) " reg "/r32" var/reg <- index arr: (array T len), idx/regi: int - => "8d/copy-address *(ebp+" regi "<<" log2(size-of(T)) "+" (arr.stack-offset + 4) ") " reg "/r32" + => "(__check-mu-array-bounds *(ebp+" arr.stack-offset ") %" regi " " size-of(T) ")" + "8d/copy-address *(ebp+" regi "<<" log2(size-of(T)) "+" (arr.stack-offset + 4) ") " reg "/r32" var/reg <- index arr/rega: (addr array T), n - => "8d/copy-address *(" rega "+" (n*size-of(T)+4) ") " reg "/r32" + => "(__check-mu-array-bounds *" rega " " n " " size-of(T) ")" + "8d/copy-address *(" rega "+" (n*size-of(T)+4) ") " reg "/r32" var/reg <- index arr: (array T len), n - => "8d/copy-address *(ebp+" (arr.stack-offset+4+n*size-of(T)) ") " reg "/r32" + => "(__check-mu-array-bounds *(ebp+" arr.stack-offset ") " n " " size-of(T) ")" + "8d/copy-address *(ebp+" (arr.stack-offset+4+n*size-of(T)) ") " reg "/r32" var/reg: (offset T) <- compute-offset arr: (addr array T), idx/regi: int # arr can be in reg or mem => "69/multiply %" regi " " size-of(T) "/imm32 " reg "/r32" var/reg: (offset T) <- compute-offset arr: (addr array T), idx: int # arr can be in reg or mem => "69/multiply *(ebp+" idx.stack-offset ") " size-of(T) "/imm32 " reg "/r32" -var/reg <- index arr/rega: (addr array T), o/rego: offset - => "8d/copy-address *(" rega "+" rego "+4) " reg "/r32" +var/reg <- index arr/rega: (addr array T), o/rego: (offset T) + => "(__check-mu-array-bounds %" rega " %" rego " 1 \"" function-name "\")" + "8d/copy-address *(" rega "+" rego "+4) " reg "/r32" Computing the length of an array is complex. -- cgit 1.4.1-2-gfad0