add limited execution mode

This commit is contained in:
ValKmjolnir 2024-02-21 19:55:46 +08:00
parent 38c6fe2c5c
commit b3e6b5784a
8 changed files with 64 additions and 8 deletions

View File

@ -30,6 +30,7 @@ const u32 VM_SYMINFO = 1<<7;
const u32 VM_PROFILE = 1<<8; const u32 VM_PROFILE = 1<<8;
const u32 VM_PROF_ALL = 1<<9; const u32 VM_PROF_ALL = 1<<9;
const u32 VM_REF_FILE = 1<<10; const u32 VM_REF_FILE = 1<<10;
const u32 VM_LIMIT = 1<<11;
std::ostream& help(std::ostream& out) { std::ostream& help(std::ostream& out) {
out out
@ -59,6 +60,7 @@ std::ostream& help(std::ostream& out) {
<< " --prof | show profiling result, available in debug mode.\n" << " --prof | show profiling result, available in debug mode.\n"
<< " --prof-all | show profiling result of all files," << " --prof-all | show profiling result of all files,"
<< "available under debug mode.\n" << "available under debug mode.\n"
<< " --limit | use limited execution mode."
<< "file:\n" << "file:\n"
<< " <filename> | execute file.\n" << " <filename> | execute file.\n"
<< "argv:\n" << "argv:\n"
@ -155,7 +157,7 @@ void execute(
} }
// code generator gets parser's ast and import file list to generate code // 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) { if (cmd&VM_CODE) {
gen.print(std::cout); gen.print(std::cout);
} }
@ -171,6 +173,7 @@ void execute(
} else if (cmd&VM_TIME || cmd&VM_EXEC) { } else if (cmd&VM_TIME || cmd&VM_EXEC) {
auto runtime = std::unique_ptr<nasal::vm>(new nasal::vm); auto runtime = std::unique_ptr<nasal::vm>(new nasal::vm);
runtime->set_detail_report_info(cmd&VM_DETAIL); runtime->set_detail_report_info(cmd&VM_DETAIL);
runtime->set_limit_mode_flag(cmd&VM_LIMIT);
runtime->run(gen, ld, argv); runtime->run(gen, ld, argv);
} }
@ -227,7 +230,8 @@ i32 main(i32 argc, const char* argv[]) {
{"--prof", VM_PROFILE}, {"--prof", VM_PROFILE},
{"--prof-all", VM_PROF_ALL}, {"--prof-all", VM_PROF_ALL},
{"-f", VM_REF_FILE}, {"-f", VM_REF_FILE},
{"--ref-file", VM_REF_FILE} {"--ref-file", VM_REF_FILE},
{"--limit", VM_LIMIT|VM_EXEC}
}; };
u32 cmd = 0; u32 cmd = 0;
std::string filename = ""; std::string filename = "";

View File

@ -3,6 +3,13 @@
namespace nasal { 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) { var builtin_print(context* ctx, gc* ngc) {
for(auto& i : ctx->localr[1].vec().elems) { for(auto& i : ctx->localr[1].vec().elems) {
std::cout << i; std::cout << i;
@ -659,7 +666,7 @@ var builtin_logtime(context* ctx, gc* ngc) {
tm* tm_t = localtime(&t); tm* tm_t = localtime(&t);
char s[64]; char s[64];
snprintf( 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_year+1900,
tm_t->tm_mon+1, tm_t->tm_mon+1,
tm_t->tm_mday, tm_t->tm_mday,

View File

@ -29,6 +29,7 @@
namespace nasal { namespace nasal {
var builtin_unsafe(context*, gc*);
var builtin_print(context*, gc*); var builtin_print(context*, gc*);
var builtin_println(context*, gc*); var builtin_println(context*, gc*);
var builtin_exit(context*, gc*); var builtin_exit(context*, gc*);

View File

@ -11,12 +11,18 @@ void codegen::init_file_map(const std::vector<std::string>& file_list) {
void codegen::load_native_function_table(nasal_builtin_table* table) { void codegen::load_native_function_table(nasal_builtin_table* table) {
for(usize i = 0; table[i].func; ++i) { for(usize i = 0; table[i].func; ++i) {
// check confliction
if (native_function_mapper.count(table[i].name)) { if (native_function_mapper.count(table[i].name)) {
err.err("code", "\"" + std::string(table[i].name) + "\" conflicts."); err.err("code", "\"" + std::string(table[i].name) + "\" conflicts.");
continue; 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(); auto index = native_function_mapper.size();
// insert into mapper
native_function_mapper[table[i].name] = index; 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()); 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_native_function();
init_file_map(import.get_file_list()); init_file_map(import.get_file_list());
need_repl_output = repl_flag;
in_foreach_loop_level.push_back(0); in_foreach_loop_level.push_back(0);

View File

@ -37,6 +37,24 @@ private:
// repl output flag, will generate op_repl to output stack top value if true // repl output flag, will generate op_repl to output stack top value if true
bool need_repl_output; bool need_repl_output;
// limit mode flag
bool flag_limited_mode;
const std::unordered_set<std::string> 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 // file mapper for file -> index
std::unordered_map<std::string, usize> file_map; std::unordered_map<std::string, usize> file_map;
@ -141,7 +159,7 @@ public:
public: public:
codegen() = default; codegen() = default;
const error& compile(parse&, linker&, bool); const error& compile(parse&, linker&, bool, bool);
void print(std::ostream&); void print(std::ostream&);
void symbol_dump(std::ostream&) const; void symbol_dump(std::ostream&) const;
}; };

View File

@ -188,6 +188,7 @@ code_block* linker::import_regular_file(
check_exist_or_record_file(filename); check_exist_or_record_file(filename);
module_load_stack.push_back(filename); module_load_stack.push_back(filename);
// avoid stack overflow
if (module_load_stack.size()>MAX_RECURSION_DEPTH) { if (module_load_stack.size()>MAX_RECURSION_DEPTH) {
err.err("link", err.err("link",
node->get_location(), node->get_location(),
@ -258,6 +259,7 @@ code_block* linker::import_nasal_lib() {
} }
std::string linker::generate_module_name(const std::string& file_path) { std::string linker::generate_module_name(const std::string& file_path) {
// import("...") may trigger this error module name
auto error_name = "module@[" + file_path + "]"; auto error_name = "module@[" + file_path + "]";
if (!file_path.length()) { if (!file_path.length()) {
return error_name; 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) { 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()); auto def = new definition_expr(block->get_location());
def->set_identifier(new identifier( def->set_identifier(new identifier(
block->get_location(), block->get_location(),
generate_module_name(block->get_location().file) generate_module_name(block->get_location().file)
)); ));
// (func() {...})();
auto call = new call_expr(block->get_location()); auto call = new call_expr(block->get_location());
// func() {...}
auto func = new function(block->get_location()); auto func = new function(block->get_location());
func->set_code_block(block); func->set_code_block(block);
func->get_code_block()->add_expression(generate_module_return(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 // then generate a new ast and return to import_ast
// dfs load file // dfs load file
auto library = import_nasal_lib(); auto library = import_nasal_lib();
// load used modules of this file
load(parse.tree(), this_file); load(parse.tree(), this_file);
// then insert the whole tree into library tree root
merge_tree(library, parse.tree()); merge_tree(library, parse.tree());
// swap tree root, and delete old root
delete parse.swap(library); delete parse.swap(library);
return err; return err;
} }

View File

@ -45,6 +45,9 @@ protected:
bool first_exec_flag = true; bool first_exec_flag = true;
bool allow_repl_output = false; bool allow_repl_output = false;
/* limited mode, will not load unsafe system api if switch on */
bool flag_limited_mode = false;
/* vm initializing function */ /* vm initializing function */
void init( void init(
const std::vector<std::string>&, const std::vector<std::string>&,
@ -192,6 +195,8 @@ public:
void set_repl_mode_flag(bool flag) {is_repl_mode = flag;} void set_repl_mode_flag(bool flag) {is_repl_mode = flag;}
/* set repl output flag */ /* set repl output flag */
void set_allow_repl_output_flag(bool flag) {allow_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) { inline bool vm::cond(var& val) {

View File

@ -97,7 +97,7 @@ bool repl::run() {
} }
nasal_opt->do_optimization(nasal_parser->tree()); 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; return false;
} }