feat: add infinite loop control args
This commit is contained in:
+1
-1
@@ -36,7 +36,7 @@ typedef struct
|
||||
fzl_vm_t *fzl_mkvm(const char *filepath);
|
||||
|
||||
// Load and run code
|
||||
int fzl_vm_run(fzl_vm_t *vm);
|
||||
int fzl_vm_run(fzl_vm_t *vm, bool allow_infinite, uint64_t max_iter);
|
||||
|
||||
// Get last VM error message
|
||||
char *fzl_vm_geterror();
|
||||
|
||||
+18
-16
@@ -14,10 +14,7 @@
|
||||
#include <vm/fzl_vm_object.h>
|
||||
|
||||
char last_err[256];
|
||||
size_t last_jmp_ip = 0;
|
||||
|
||||
// NOTE: add `--max-iter` option for limit
|
||||
size_t max_iter_limit = 100000;
|
||||
size_t last_jmp_ip = 0;
|
||||
size_t total_jmp_on_same = 0;
|
||||
|
||||
static char *expect_hdr = "FZL\0\1";
|
||||
@@ -279,7 +276,7 @@ void print_err_data(fzl_vm_t *vm)
|
||||
printf("\t> [%zd] %lu\n", i, vm->cstack[i]);
|
||||
}
|
||||
|
||||
int fzl_vm_run(fzl_vm_t *vm)
|
||||
int fzl_vm_run(fzl_vm_t *vm, bool allow_infinite, uint64_t max_iter)
|
||||
{
|
||||
if (!vm)
|
||||
{
|
||||
@@ -673,19 +670,24 @@ int fzl_vm_run(fzl_vm_t *vm)
|
||||
"runtime error - expected JMP addr");
|
||||
return -1;
|
||||
}
|
||||
uint64_t jmp_ip = vm->ops[++vm->ip];
|
||||
if (jmp_ip == last_jmp_ip)
|
||||
total_jmp_on_same++;
|
||||
else
|
||||
total_jmp_on_same = 0;
|
||||
|
||||
if (total_jmp_on_same > max_iter_limit)
|
||||
uint64_t jmp_ip = vm->ops[++vm->ip];
|
||||
if (!allow_infinite)
|
||||
{
|
||||
snprintf(last_err, sizeof(last_err),
|
||||
"runtime error - exceeded max loop jumps (infinite loop?)\n"
|
||||
"If you thinks there's mistake, change jumps limit with "
|
||||
"--max-iter=N");
|
||||
return -1;
|
||||
if (jmp_ip == last_jmp_ip)
|
||||
total_jmp_on_same++;
|
||||
else
|
||||
total_jmp_on_same = 0;
|
||||
|
||||
if (total_jmp_on_same > max_iter)
|
||||
{
|
||||
snprintf(
|
||||
last_err, sizeof(last_err),
|
||||
"runtime error - exceeded max loop jumps (infinite loop?)\n"
|
||||
"If you thinks there's mistake, change jumps limit with "
|
||||
"--max-iter=N");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
vm->ip = jmp_ip - 1;
|
||||
|
||||
+44
-11
@@ -1,5 +1,7 @@
|
||||
#include <common/fzl_colors.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -10,14 +12,18 @@ typedef struct
|
||||
char *filepath;
|
||||
bool help;
|
||||
bool debug;
|
||||
bool allow_infinite;
|
||||
uint64_t max_iter;
|
||||
} run_args_t;
|
||||
|
||||
void print_hint()
|
||||
{
|
||||
printf("Usage: fz [flags] <file path>\n");
|
||||
printf("Flags:\n");
|
||||
printf("\t-h\t--help\tprint usage information\n");
|
||||
printf("\t-d\t--debug\tdisplay program opcodes\n");
|
||||
printf("\t-h\t--help\t\t\tprint usage information\n");
|
||||
printf("\t-d\t--debug\t\t\tdisplay program opcodes\n");
|
||||
printf("\t\t--allow-infinite\tallow infinite loops\n");
|
||||
printf("\t\t--max-iter N\t\trestrict loops to maximum N iterations\n");
|
||||
}
|
||||
|
||||
// Parse passed arguments and build args setup structure
|
||||
@@ -29,10 +35,12 @@ run_args_t *parse_args(int argc, char **argv)
|
||||
return NULL;
|
||||
}
|
||||
|
||||
run_args_t *args = malloc(sizeof(run_args_t));
|
||||
args->filepath = NULL;
|
||||
args->help = false;
|
||||
args->debug = false;
|
||||
run_args_t *args = malloc(sizeof(run_args_t));
|
||||
args->filepath = NULL;
|
||||
args->help = false;
|
||||
args->debug = false;
|
||||
args->allow_infinite = false;
|
||||
args->max_iter = 100000;
|
||||
|
||||
for (int i = 0; i < argc; i++)
|
||||
{
|
||||
@@ -46,9 +54,33 @@ run_args_t *parse_args(int argc, char **argv)
|
||||
}
|
||||
else if (strcmp(argv[i], "-d") == 0 || strcmp(argv[i], "--debug") == 0)
|
||||
args->debug = true;
|
||||
else if (strcmp(argv[i], "--allow-infinite") == 0)
|
||||
args->allow_infinite = true;
|
||||
else if (strcmp(argv[i], "--max-iter") == 0)
|
||||
{
|
||||
char *n = argv[++i];
|
||||
if (!n || argc <= i || !(n[0] >= '0' && n[0] <= '9'))
|
||||
{
|
||||
printf("%sError%s: --max-iter options requires number after it\n",
|
||||
FZL_CERROR, FZL_CRST);
|
||||
free(args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
uint64_t iters = strtol(n, NULL, 10);
|
||||
if (iters < 1)
|
||||
{
|
||||
printf("%sError%s: '--max-iter 0' is not allowed\n", FZL_CERROR,
|
||||
FZL_CRST);
|
||||
free(args);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
args->max_iter = iters;
|
||||
}
|
||||
else
|
||||
{
|
||||
printf("Error: unknown flag '%s'.\n", argv[i]);
|
||||
printf("%sError%s: unknown flag '%s'.\n", FZL_CERROR, FZL_CRST, argv[i]);
|
||||
printf("Use 'fz --help' to read the usage\n");
|
||||
free(args);
|
||||
return NULL;
|
||||
@@ -57,7 +89,8 @@ run_args_t *parse_args(int argc, char **argv)
|
||||
|
||||
if (argv[argc - 1][0] == '-')
|
||||
{
|
||||
printf("Error: last argument MUST be a file path\n");
|
||||
printf("%sError%s: last argument MUST be a file path\n", FZL_CERROR,
|
||||
FZL_CRST);
|
||||
printf("Use 'fz --help' for help\n");
|
||||
free(args);
|
||||
return NULL;
|
||||
@@ -83,7 +116,7 @@ int main(int argc, char **argv)
|
||||
fzl_vm_t *vm = fzl_mkvm(args->filepath);
|
||||
if (!vm)
|
||||
{
|
||||
printf("Error: %s\n", fzl_vm_geterror());
|
||||
printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, fzl_vm_geterror());
|
||||
free(args);
|
||||
return -1;
|
||||
}
|
||||
@@ -92,12 +125,12 @@ int main(int argc, char **argv)
|
||||
fzl_vm_print_ops(vm);
|
||||
else
|
||||
{
|
||||
int result = fzl_vm_run(vm);
|
||||
int result = fzl_vm_run(vm, args->allow_infinite, args->max_iter);
|
||||
if (result != 0)
|
||||
{
|
||||
char *err = fzl_vm_geterror();
|
||||
if (err && err[0])
|
||||
printf("Error: %s\n", err);
|
||||
printf("%sError%s: %s\n", FZL_CERROR, FZL_CRST, err);
|
||||
|
||||
free(args);
|
||||
fzl_freevm(vm);
|
||||
|
||||
Reference in New Issue
Block a user