From b3e6b5784a1b9f2a67dbec034d29d2d7aeb7c5c8 Mon Sep 17 00:00:00 2001 From: ValKmjolnir Date: Wed, 21 Feb 2024 19:55:46 +0800 Subject: [PATCH] :sparkles: add limited execution mode --- src/main.cpp | 8 ++++++-- src/nasal_builtin.cpp | 9 ++++++++- src/nasal_builtin.h | 1 + src/nasal_codegen.cpp | 16 +++++++++++++--- src/nasal_codegen.h | 20 +++++++++++++++++++- src/nasal_import.cpp | 11 +++++++++++ src/nasal_vm.h | 5 +++++ src/repl.cpp | 2 +- 8 files changed, 64 insertions(+), 8 deletions(-) diff --git a/src/main.cpp b/src/main.cpp index d0c6cd3..16435b0 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -30,6 +30,7 @@ const u32 VM_SYMINFO = 1<<7; const u32 VM_PROFILE = 1<<8; const u32 VM_PROF_ALL = 1<<9; const u32 VM_REF_FILE = 1<<10; +const u32 VM_LIMIT = 1<<11; std::ostream& help(std::ostream& out) { out @@ -59,6 +60,7 @@ std::ostream& help(std::ostream& out) { << " --prof | show profiling result, available in debug mode.\n" << " --prof-all | show profiling result of all files," << "available under debug mode.\n" + << " --limit | use limited execution mode." << "file:\n" << " | execute file.\n" << "argv:\n" @@ -155,7 +157,7 @@ void execute( } // code generator gets parser's ast and import file list to generate code - gen.compile(parse, ld, false).chkerr(); + gen.compile(parse, ld, false, cmd&VM_LIMIT).chkerr(); if (cmd&VM_CODE) { gen.print(std::cout); } @@ -171,6 +173,7 @@ void execute( } else if (cmd&VM_TIME || cmd&VM_EXEC) { auto runtime = std::unique_ptr(new nasal::vm); runtime->set_detail_report_info(cmd&VM_DETAIL); + runtime->set_limit_mode_flag(cmd&VM_LIMIT); runtime->run(gen, ld, argv); } @@ -227,7 +230,8 @@ i32 main(i32 argc, const char* argv[]) { {"--prof", VM_PROFILE}, {"--prof-all", VM_PROF_ALL}, {"-f", VM_REF_FILE}, - {"--ref-file", VM_REF_FILE} + {"--ref-file", VM_REF_FILE}, + {"--limit", VM_LIMIT|VM_EXEC} }; u32 cmd = 0; std::string filename = ""; diff --git a/src/nasal_builtin.cpp b/src/nasal_builtin.cpp index 39332bb..58aee78 100644 --- a/src/nasal_builtin.cpp +++ b/src/nasal_builtin.cpp @@ -3,6 +3,13 @@ namespace nasal { +var builtin_unsafe(context* ctx, gc* ngc) { + return nas_err( + "unsafe_redirect", + "you are using unsafe system api under limited mode!" + ); +} + var builtin_print(context* ctx, gc* ngc) { for(auto& i : ctx->localr[1].vec().elems) { std::cout << i; @@ -659,7 +666,7 @@ var builtin_logtime(context* ctx, gc* ngc) { tm* tm_t = localtime(&t); char s[64]; snprintf( - s,64,"%d-%.2d-%.2d %.2d:%.2d:%.2d", + s, 64, "%d-%.2d-%.2d %.2d:%.2d:%.2d", tm_t->tm_year+1900, tm_t->tm_mon+1, tm_t->tm_mday, diff --git a/src/nasal_builtin.h b/src/nasal_builtin.h index d366879..9ca7503 100644 --- a/src/nasal_builtin.h +++ b/src/nasal_builtin.h @@ -29,6 +29,7 @@ namespace nasal { +var builtin_unsafe(context*, gc*); var builtin_print(context*, gc*); var builtin_println(context*, gc*); var builtin_exit(context*, gc*); diff --git a/src/nasal_codegen.cpp b/src/nasal_codegen.cpp index 95a135e..c6328a0 100644 --- a/src/nasal_codegen.cpp +++ b/src/nasal_codegen.cpp @@ -11,12 +11,18 @@ void codegen::init_file_map(const std::vector& file_list) { void codegen::load_native_function_table(nasal_builtin_table* table) { for(usize i = 0; table[i].func; ++i) { + // check confliction if (native_function_mapper.count(table[i].name)) { err.err("code", "\"" + std::string(table[i].name) + "\" conflicts."); continue; } - native_function.push_back(table[i]); + if (flag_limited_mode && unsafe_system_api.count(table[i].name)) { + native_function.push_back({"__unsafe_redirect", builtin_unsafe}); + } else { + native_function.push_back(table[i]); + } auto index = native_function_mapper.size(); + // insert into mapper native_function_mapper[table[i].name] = index; } } @@ -1302,10 +1308,14 @@ void codegen::ret_gen(return_expr* node) { emit(op_ret, 0, node->get_location()); } -const error& codegen::compile(parse& parse, linker& import, bool repl_flag) { +const error& codegen::compile(parse& parse, + linker& import, + bool repl_flag, + bool limit_mode) { + need_repl_output = repl_flag; + flag_limited_mode = limit_mode; init_native_function(); init_file_map(import.get_file_list()); - need_repl_output = repl_flag; in_foreach_loop_level.push_back(0); diff --git a/src/nasal_codegen.h b/src/nasal_codegen.h index 221a0d3..9d8ec7f 100644 --- a/src/nasal_codegen.h +++ b/src/nasal_codegen.h @@ -37,6 +37,24 @@ private: // repl output flag, will generate op_repl to output stack top value if true bool need_repl_output; + // limit mode flag + bool flag_limited_mode; + const std::unordered_set unsafe_system_api = { + // builtin + "__system", "__input", + // io + "__fout", "__open", "__write", "__stat" + // bits + "__fld", "__sfld", "__setfld", + "__buf", + // fg + "__logprint", + // dylib + "__dlopen", "__dlclose", "__dlcallv", "__dlcall", + // unix + "__pipe", "__fork", "__waitpid", "__chdir", + "__environ", "__getcwd", "__getenv" + }; // file mapper for file -> index std::unordered_map file_map; @@ -141,7 +159,7 @@ public: public: codegen() = default; - const error& compile(parse&, linker&, bool); + const error& compile(parse&, linker&, bool, bool); void print(std::ostream&); void symbol_dump(std::ostream&) const; }; diff --git a/src/nasal_import.cpp b/src/nasal_import.cpp index aaa269c..123f956 100644 --- a/src/nasal_import.cpp +++ b/src/nasal_import.cpp @@ -188,6 +188,7 @@ code_block* linker::import_regular_file( check_exist_or_record_file(filename); module_load_stack.push_back(filename); + // avoid stack overflow if (module_load_stack.size()>MAX_RECURSION_DEPTH) { err.err("link", node->get_location(), @@ -258,6 +259,7 @@ code_block* linker::import_nasal_lib() { } std::string linker::generate_module_name(const std::string& file_path) { + // import("...") may trigger this error module name auto error_name = "module@[" + file_path + "]"; if (!file_path.length()) { return error_name; @@ -332,13 +334,19 @@ return_expr* linker::generate_module_return(code_block* block) { } definition_expr* linker::generate_module_definition(code_block* block) { + // generate ast node like this: + // var {module_name} = (func() { + // ... # module itself + // })(); auto def = new definition_expr(block->get_location()); def->set_identifier(new identifier( block->get_location(), generate_module_name(block->get_location().file) )); + // (func() {...})(); auto call = new call_expr(block->get_location()); + // func() {...} auto func = new function(block->get_location()); func->set_code_block(block); func->get_code_block()->add_expression(generate_module_return(block)); @@ -392,8 +400,11 @@ const error& linker::link(parse& parse, bool spath = false) { // then generate a new ast and return to import_ast // dfs load file auto library = import_nasal_lib(); + // load used modules of this file load(parse.tree(), this_file); + // then insert the whole tree into library tree root merge_tree(library, parse.tree()); + // swap tree root, and delete old root delete parse.swap(library); return err; } diff --git a/src/nasal_vm.h b/src/nasal_vm.h index 8653818..8da79d6 100644 --- a/src/nasal_vm.h +++ b/src/nasal_vm.h @@ -45,6 +45,9 @@ protected: bool first_exec_flag = true; bool allow_repl_output = false; + /* limited mode, will not load unsafe system api if switch on */ + bool flag_limited_mode = false; + /* vm initializing function */ void init( const std::vector&, @@ -192,6 +195,8 @@ public: void set_repl_mode_flag(bool flag) {is_repl_mode = flag;} /* set repl output flag */ void set_allow_repl_output_flag(bool flag) {allow_repl_output = flag;} + /* set limit mode flag */ + void set_limit_mode_flag(bool flag) {flag_limited_mode = flag;} }; inline bool vm::cond(var& val) { diff --git a/src/repl.cpp b/src/repl.cpp index 6aa54e6..10860b3 100644 --- a/src/repl.cpp +++ b/src/repl.cpp @@ -97,7 +97,7 @@ bool repl::run() { } nasal_opt->do_optimization(nasal_parser->tree()); - if (nasal_codegen->compile(*nasal_parser, *nasal_linker, true).geterr()) { + if (nasal_codegen->compile(*nasal_parser, *nasal_linker, true, false).geterr()) { return false; }