✨ add limited execution mode
This commit is contained in:
parent
38c6fe2c5c
commit
b3e6b5784a
|
@ -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"
|
||||
<< " <filename> | 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<nasal::vm>(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 = "";
|
||||
|
|
|
@ -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;
|
||||
|
|
|
@ -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*);
|
||||
|
|
|
@ -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) {
|
||||
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;
|
||||
}
|
||||
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);
|
||||
|
||||
|
|
|
@ -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<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
|
||||
std::unordered_map<std::string, usize> 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;
|
||||
};
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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<std::string>&,
|
||||
|
@ -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) {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue