✨ 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_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 = "";
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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*);
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue