diff --git a/hera/op.py b/hera/op.py index 569cf88..283fddd 100644 --- a/hera/op.py +++ b/hera/op.py @@ -7,6 +7,7 @@ from contextlib import suppress from typing import Dict, List, Optional +from hera import stdlib from hera.data import Constant, DataLabel, Location, Messages, Token from hera.utils import format_int, from_u16, print_warning, to_u16, to_u32 @@ -936,13 +937,7 @@ class __EVAL(DebuggingOperation): P = (STRING,) def execute(self, vm): - # Rudimentary safeguard to make execution of malicious code harder. Users of - # hera-py should keep in mind that running arbitrary HERA code is no safer than - # running arbitrary code of any kind. - if "import" not in self.args[0]: - bytecode = compile(self.args[0], "", "exec") - exec(bytecode, {}, {"vm": vm}) - + eval(self.args[0], {}, {"stdlib": stdlib, "vm": vm}) vm.pc += 1 diff --git a/hera/stdlib.py b/hera/stdlib.py index 531a1cf..fb83b62 100644 --- a/hera/stdlib.py +++ b/hera/stdlib.py @@ -8,35 +8,72 @@ """ +def tiger_printint_stack(vm): + print(vm.load_memory(vm.registers[14] + 3), end="") + + +def tiger_print_stack(vm): + addr = vm.load_memory(vm.registers[14] + 3) + n = vm.load_memory(addr) + for i in range(n): + print(chr(vm.load_memory(addr + i + 1)), end="") + + +def tiger_println_stack(vm): + addr = vm.load_memory(vm.registers[14] + 3) + n = vm.load_memory(addr) + for i in range(n): + print(chr(vm.load_memory(addr + i + 1)), end="") + print() + + +def tiger_exit(vm): + vm.halted = True + + +def tiger_div_stack(vm): + left = vm.load_memory(vm.registers[14] + 3) + right = vm.load_memory(vm.registers[14] + 4) + result = left // right if right != 0 else 0 + vm.store_memory(vm.registers[14] + 3, result) + + +def tiger_mod_stack(vm): + left = vm.load_memory(vm.registers[14] + 3) + right = vm.load_memory(vm.registers[14] + 4) + result = left % right if right != 0 else 0 + vm.store_memory(vm.registers[14] + 3, result) + + # The standard library with parameters-on-the-stack functions. TIGER_STDLIB_STACK = """ LABEL(printint) - __eval("print(vm.load_memory(vm.registers[14]+3), end='')") + __eval("stdlib.tiger_printint_stack(vm)") RETURN(FP_alt, PC_ret) LABEL(print) - __eval("addr = vm.load_memory(vm.registers[14]+3); n = vm.load_memory(addr)\\nfor i in range(n):\\n print(chr(vm.load_memory(addr+i+1)), end='')") + __eval("stdlib.tiger_print_stack(vm)") RETURN(FP_alt, PC_ret) LABEL(println) - __eval("addr = vm.load_memory(vm.registers[14]+3); n = vm.load_memory(addr)\\nfor i in range(n):\\n print(chr(vm.load_memory(addr+i+1)), end='')\\nprint()") + __eval("stdlib.tiger_println_stack(vm)") RETURN(FP_alt, PC_ret) LABEL(exit) - __eval("vm.pc = float('inf')") + __eval("stdlib.tiger_exit(vm)") RETURN(FP_alt, PC_ret) LABEL(div) - __eval("left = vm.load_memory(vm.registers[14]+3); right = vm.load_memory(vm.registers[14]+4); vm.store_memory(vm.registers[14]+3, left // right if right != 0 else 0)") + __eval("stdlib.tiger_div_stack(vm)") RETURN(FP_alt, PC_ret) LABEL(mod) - __eval("left = vm.load_memory(vm.registers[14]+3); right = vm.load_memory(vm.registers[14]+4); vm.store_memory(vm.registers[14]+3, left % right if right != 0 else 0)") + __eval("stdlib.tiger_mod_stack(vm)") RETURN(FP_alt, PC_ret) diff --git a/test/test_exec/test_debug_ops.py b/test/test_exec/test_debug_ops.py index a0cda1d..00129d7 100644 --- a/test/test_exec/test_debug_ops.py +++ b/test/test_exec/test_debug_ops.py @@ -48,18 +48,12 @@ def test_println_increments_pc(vm): def test___eval(vm): - helper(vm, '__eval("vm.registers[7] = 10")') + helper(vm, '__eval("stdlib.tiger_exit(vm)")') - assert vm.registers[7] == 10 - - -def test___eval_cannot_import_anything(vm, capsys): - helper(vm, "__eval(\"import sys; sys.stdout.write('hi')\")") - - assert capsys.readouterr().out == "" + assert vm.halted is True def test___eval_increments_pc(vm): - helper(vm, '__eval("")') + helper(vm, '__eval("0")') assert vm.pc == 1