diff --git a/CMakeLists.txt b/CMakeLists.txt index 27e805a..f55220b 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -25,6 +25,7 @@ add_executable(fzc src/compiler/utils/fzl_linked.c src/compiler/utils/fzl_options.c src/compiler/utils/fzl_ctable.c + src/compiler/checkers/fzl_loop_check.c src/compiler/main.c) # Virtual machine diff --git a/src/compiler/checkers/fzl_loop_check.c b/src/compiler/checkers/fzl_loop_check.c new file mode 100644 index 0000000..8958292 --- /dev/null +++ b/src/compiler/checkers/fzl_loop_check.c @@ -0,0 +1,60 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +// Check for infinite loop +bool is_infinite_loop(fzl_walker_t *walker, size_t start_ip, size_t end_ip) +{ + if (!walker) + return false; + + end_ip = (end_ip >= walker->op_count) ? (walker->op_count - 1) : end_ip; + + // Can we determine an init block? + size_t maybe_init_start = start_ip + 1; + size_t maybe_init_end = start_ip + 6; + fzl_const_t *declared = NULL; + for (size_t i = maybe_init_start; i <= maybe_init_end; i++) + { + if (walker->ops[i] != FZL_OPCODE_STORE) + continue; + + declared = &walker->consts->array[walker->ops[i - 1]]; + break; + } + + if (declared) + { + fzl_sym_t sym; + bool found = false; + for (ssize_t i = walker->sym_top - 1; i >= 0; i--) + if ((found = fzl_symt_get(walker->syms[i], + (char *)declared->as.string.chars, &sym))) + break; + + if (!found) + return false; // suspicious + + if (sym.type >= FZL_TYPE_INT8) + { + } + } + + // At least has jump outside + for (size_t i = start_ip; i <= end_ip; i++) + { + if (walker->ops[i] != FZL_OPCODE_JMP) + continue; + + size_t jump_ip = walker->ops[++i]; + if (jump_ip >= end_ip) + return false; + } + + return true; +} diff --git a/src/compiler/fzl_walker.c b/src/compiler/fzl_walker.c index bc269b5..ee6aa64 100644 --- a/src/compiler/fzl_walker.c +++ b/src/compiler/fzl_walker.c @@ -14,6 +14,8 @@ #include #include +extern bool is_infinite_loop(fzl_walker_t *walker, size_t ls, size_t le); + char *null_name = ""; char wlast_err[256]; @@ -271,6 +273,16 @@ fzl_walk_res_t walk(fzl_walker_t *walker, fzl_node_t *node) push_word(walker, start_ip); push_op(walker, FZL_OPCODE_RM_ENVTABLE); + bool is_infinite = + is_infinite_loop(walker, start_ip, walker->op_count - 2); + if (is_infinite) + { + snprintf(wlast_err, sizeof(wlast_err), + "'%s': infinite loop detected at %ld:%ld", + node->token->filename, node->token->ln, node->token->cn); + return (fzl_walk_res_t){.error = true, .error_msg = wlast_err}; + } + for (size_t i = walker->sym_top - 1; i > newctx->initial_env_lvl; i--) fzl_freesymt(walker->syms[--walker->sym_top]);