bc: fix infinite state growth for "yes 1 | bc" case
function old new delta zbc_vm_process 585 672 +87 bc_func_init 50 86 +36 zbc_program_num 990 1022 +32 bc_program_str 17 47 +30 bc_program_current_func - 22 +22 bc_parse_pushNUM 66 87 +21 bc_func_free 27 43 +16 zbc_num_binary 145 147 +2 bc_program_reset 64 61 -3 bc_parse_pushSTR 73 65 -8 ------------------------------------------------------------------------------ (add/remove: 1/0 grow/shrink: 7/2 up/down: 246/-11) Total: 235 bytes text data bss dec hex filename 981393 485 7296 989174 f17f6 busybox_old 981656 485 7296 989437 f18fd busybox_unstripped Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
447dc02c27
commit
5d57bc442d
141
miscutils/bc.c
141
miscutils/bc.c
@ -350,6 +350,8 @@ typedef struct BcFunc {
|
|||||||
BcVec code;
|
BcVec code;
|
||||||
IF_BC(BcVec labels;)
|
IF_BC(BcVec labels;)
|
||||||
IF_BC(BcVec autos;)
|
IF_BC(BcVec autos;)
|
||||||
|
IF_BC(BcVec strs;)
|
||||||
|
IF_BC(BcVec consts;)
|
||||||
IF_BC(size_t nparams;)
|
IF_BC(size_t nparams;)
|
||||||
} BcFunc;
|
} BcFunc;
|
||||||
|
|
||||||
@ -694,8 +696,8 @@ typedef struct BcProgram {
|
|||||||
BcVec arrs;
|
BcVec arrs;
|
||||||
BcVec arr_map;
|
BcVec arr_map;
|
||||||
|
|
||||||
BcVec strs;
|
IF_DC(BcVec strs;)
|
||||||
BcVec consts;
|
IF_DC(BcVec consts;)
|
||||||
|
|
||||||
const char *file;
|
const char *file;
|
||||||
|
|
||||||
@ -1093,6 +1095,7 @@ static void bc_vec_pop_all(BcVec *v)
|
|||||||
bc_vec_npop(v, v->len);
|
bc_vec_npop(v, v->len);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//TODO: return index of pushed data - many callers can use that
|
||||||
static void bc_vec_push(BcVec *v, const void *data)
|
static void bc_vec_push(BcVec *v, const void *data)
|
||||||
{
|
{
|
||||||
if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
|
if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
|
||||||
@ -1160,18 +1163,6 @@ static void *bc_vec_item(const BcVec *v, size_t idx)
|
|||||||
return v->v + v->size * idx;
|
return v->v + v->size * idx;
|
||||||
}
|
}
|
||||||
|
|
||||||
static char** bc_program_str(size_t idx)
|
|
||||||
{
|
|
||||||
return bc_vec_item(&G.prog.strs, idx);
|
|
||||||
}
|
|
||||||
|
|
||||||
static BcFunc* bc_program_func(size_t idx)
|
|
||||||
{
|
|
||||||
return bc_vec_item(&G.prog.fns, idx);
|
|
||||||
}
|
|
||||||
// BC_PROG_MAIN is zeroth element, so:
|
|
||||||
#define bc_program_func_BC_PROG_MAIN() ((BcFunc*)(G.prog.fns.v))
|
|
||||||
|
|
||||||
static void *bc_vec_item_rev(const BcVec *v, size_t idx)
|
static void *bc_vec_item_rev(const BcVec *v, size_t idx)
|
||||||
{
|
{
|
||||||
return v->v + v->size * (v->len - idx - 1);
|
return v->v + v->size * (v->len - idx - 1);
|
||||||
@ -1189,6 +1180,46 @@ static FAST_FUNC void bc_vec_free(void *vec)
|
|||||||
free(v->v);
|
free(v->v);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static BcFunc* bc_program_func(size_t idx)
|
||||||
|
{
|
||||||
|
return bc_vec_item(&G.prog.fns, idx);
|
||||||
|
}
|
||||||
|
// BC_PROG_MAIN is zeroth element, so:
|
||||||
|
#define bc_program_func_BC_PROG_MAIN() ((BcFunc*)(G.prog.fns.v))
|
||||||
|
|
||||||
|
#if ENABLE_BC
|
||||||
|
static BcFunc* bc_program_current_func(void)
|
||||||
|
{
|
||||||
|
BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
|
||||||
|
BcFunc *func = bc_program_func(ip->func);
|
||||||
|
return func;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static char** bc_program_str(size_t idx)
|
||||||
|
{
|
||||||
|
#if ENABLE_BC
|
||||||
|
if (IS_BC) {
|
||||||
|
BcFunc *func = bc_program_current_func();
|
||||||
|
return bc_vec_item(&func->strs, idx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
IF_DC(return bc_vec_item(&G.prog.strs, idx);)
|
||||||
|
}
|
||||||
|
|
||||||
|
static char** bc_program_const(size_t idx)
|
||||||
|
{
|
||||||
|
#if ENABLE_BC
|
||||||
|
if (IS_BC) {
|
||||||
|
BcFunc *func = bc_program_current_func();
|
||||||
|
return bc_vec_item(&func->consts, idx);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
IF_DC(return bc_vec_item(&G.prog.consts, idx);)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
static int bc_id_cmp(const void *e1, const void *e2)
|
static int bc_id_cmp(const void *e1, const void *e2)
|
||||||
{
|
{
|
||||||
return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
|
return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name);
|
||||||
@ -2522,11 +2553,18 @@ static BC_STATUS zbc_func_insert(BcFunc *f, char *name, bool var)
|
|||||||
#define zbc_func_insert(...) (zbc_func_insert(__VA_ARGS__) COMMA_SUCCESS)
|
#define zbc_func_insert(...) (zbc_func_insert(__VA_ARGS__) COMMA_SUCCESS)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static FAST_FUNC void bc_string_free(void *string)
|
||||||
|
{
|
||||||
|
free(*(char**)string);
|
||||||
|
}
|
||||||
|
|
||||||
static void bc_func_init(BcFunc *f)
|
static void bc_func_init(BcFunc *f)
|
||||||
{
|
{
|
||||||
bc_char_vec_init(&f->code);
|
bc_char_vec_init(&f->code);
|
||||||
IF_BC(bc_vec_init(&f->labels, sizeof(size_t), NULL);)
|
IF_BC(bc_vec_init(&f->labels, sizeof(size_t), NULL);)
|
||||||
IF_BC(bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);)
|
IF_BC(bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);)
|
||||||
|
IF_BC(bc_vec_init(&f->strs, sizeof(char *), bc_string_free);)
|
||||||
|
IF_BC(bc_vec_init(&f->consts, sizeof(char *), bc_string_free);)
|
||||||
IF_BC(f->nparams = 0;)
|
IF_BC(f->nparams = 0;)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2536,6 +2574,8 @@ static FAST_FUNC void bc_func_free(void *func)
|
|||||||
bc_vec_free(&f->code);
|
bc_vec_free(&f->code);
|
||||||
IF_BC(bc_vec_free(&f->labels);)
|
IF_BC(bc_vec_free(&f->labels);)
|
||||||
IF_BC(bc_vec_free(&f->autos);)
|
IF_BC(bc_vec_free(&f->autos);)
|
||||||
|
IF_BC(bc_vec_free(&f->strs);)
|
||||||
|
IF_BC(bc_vec_free(&f->consts);)
|
||||||
}
|
}
|
||||||
|
|
||||||
static void bc_array_expand(BcVec *a, size_t len);
|
static void bc_array_expand(BcVec *a, size_t len);
|
||||||
@ -2585,11 +2625,6 @@ static void bc_array_copy(BcVec *d, const BcVec *s)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static FAST_FUNC void bc_string_free(void *string)
|
|
||||||
{
|
|
||||||
free(*((char **) string));
|
|
||||||
}
|
|
||||||
|
|
||||||
#if ENABLE_DC
|
#if ENABLE_DC
|
||||||
static void dc_result_copy(BcResult *d, BcResult *src)
|
static void dc_result_copy(BcResult *d, BcResult *src)
|
||||||
{
|
{
|
||||||
@ -3501,8 +3536,8 @@ static BC_STATUS bc_parse_pushSTR(BcParse *p)
|
|||||||
char *str = xstrdup(p->l.t.v.v);
|
char *str = xstrdup(p->l.t.v.v);
|
||||||
|
|
||||||
bc_parse_push(p, BC_INST_STR);
|
bc_parse_push(p, BC_INST_STR);
|
||||||
bc_parse_pushIndex(p, G.prog.strs.len);
|
bc_parse_pushIndex(p, p->func->strs.len);
|
||||||
bc_vec_push(&G.prog.strs, &str);
|
bc_vec_push(&p->func->strs, &str);
|
||||||
|
|
||||||
RETURN_STATUS(zbc_lex_next(&p->l));
|
RETURN_STATUS(zbc_lex_next(&p->l));
|
||||||
}
|
}
|
||||||
@ -3512,10 +3547,16 @@ static BC_STATUS bc_parse_pushSTR(BcParse *p)
|
|||||||
static void bc_parse_pushNUM(BcParse *p)
|
static void bc_parse_pushNUM(BcParse *p)
|
||||||
{
|
{
|
||||||
char *num = xstrdup(p->l.t.v.v);
|
char *num = xstrdup(p->l.t.v.v);
|
||||||
|
#if ENABLE_BC && ENABLE_DC
|
||||||
|
size_t idx = IS_BC ? p->func->consts.len : G.prog.consts.len;
|
||||||
|
bc_vec_push(IS_BC ? &p->func->consts : &G.prog.consts, &num);
|
||||||
|
#elif ENABLE_BC
|
||||||
|
size_t idx = p->func->consts.len;
|
||||||
|
bc_vec_push(&p->func->consts, &num);
|
||||||
|
#else // DC
|
||||||
size_t idx = G.prog.consts.len;
|
size_t idx = G.prog.consts.len;
|
||||||
|
|
||||||
bc_vec_push(&G.prog.consts, &num);
|
bc_vec_push(&G.prog.consts, &num);
|
||||||
|
#endif
|
||||||
bc_parse_push(p, BC_INST_NUM);
|
bc_parse_push(p, BC_INST_NUM);
|
||||||
bc_parse_pushIndex(p, idx);
|
bc_parse_pushIndex(p, idx);
|
||||||
}
|
}
|
||||||
@ -3556,7 +3597,7 @@ static void bc_program_reset(void)
|
|||||||
bc_vec_npop(&G.prog.exestack, G.prog.exestack.len - 1);
|
bc_vec_npop(&G.prog.exestack, G.prog.exestack.len - 1);
|
||||||
bc_vec_pop_all(&G.prog.results);
|
bc_vec_pop_all(&G.prog.results);
|
||||||
|
|
||||||
f = bc_program_func(0);
|
f = bc_program_func_BC_PROG_MAIN();
|
||||||
ip = bc_vec_top(&G.prog.exestack);
|
ip = bc_vec_top(&G.prog.exestack);
|
||||||
ip->idx = f->code.len;
|
ip->idx = f->code.len;
|
||||||
}
|
}
|
||||||
@ -5027,9 +5068,12 @@ static BC_STATUS zbc_program_num(BcResult *r, BcNum **num, bool hex)
|
|||||||
break;
|
break;
|
||||||
case BC_RESULT_CONSTANT: {
|
case BC_RESULT_CONSTANT: {
|
||||||
BcStatus s;
|
BcStatus s;
|
||||||
char *str = *(char**)bc_vec_item(&G.prog.consts, r->d.id.idx);
|
char *str;
|
||||||
unsigned base_t;
|
unsigned base_t;
|
||||||
size_t len = strlen(str);
|
size_t len;
|
||||||
|
|
||||||
|
str = *bc_program_const(r->d.id.idx);
|
||||||
|
len = strlen(str);
|
||||||
|
|
||||||
bc_num_init(&r->d.n, len);
|
bc_num_init(&r->d.n, len);
|
||||||
|
|
||||||
@ -6667,6 +6711,43 @@ static BC_STATUS zbc_vm_process(const char *text)
|
|||||||
bc_program_reset();
|
bc_program_reset();
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
// bc discards strings, constants and code after each
|
||||||
|
// top-level statement in the "main program".
|
||||||
|
// This prevents "yes 1 | bc" from growing its memory
|
||||||
|
// without bound. This can be done because data stack
|
||||||
|
// is empty and thus can't hold any references to
|
||||||
|
// strings or constants, there is no generated code
|
||||||
|
// which can hold references (after we discard one
|
||||||
|
// we just executed). Code of functions can have references,
|
||||||
|
// but bc stores function strings/constants in per-function
|
||||||
|
// storage.
|
||||||
|
if (IS_BC) {
|
||||||
|
BcFunc *f;
|
||||||
|
BcInstPtr *ip;
|
||||||
|
|
||||||
|
//FIXME: this does not clear up the stack
|
||||||
|
//for(i=1; i<3; i++) {
|
||||||
|
// i
|
||||||
|
// if(i==2) continue
|
||||||
|
// 77
|
||||||
|
//}
|
||||||
|
// if (G.prog.results.len != 0)
|
||||||
|
// bb_error_msg_and_die("data stack not empty: %d slots", G.prog.results.len);
|
||||||
|
|
||||||
|
if (G.prog.exestack.len != 1) // should be empty
|
||||||
|
bb_error_msg_and_die("BUG:call stack");
|
||||||
|
|
||||||
|
ip = (void*)G.prog.exestack.v;
|
||||||
|
if (ip->func != BC_PROG_MAIN)
|
||||||
|
bb_error_msg_and_die("BUG:not MAIN");
|
||||||
|
//bb_error_msg("ip->func:%d >idx:%d >len:%d", ip->func, ip->idx, ip->len);
|
||||||
|
f = bc_program_func_BC_PROG_MAIN();
|
||||||
|
//bb_error_msg("MAIN->code.len:%d >strs.len:%d >consts.len:%d", f->code.len, f->strs.len, f->consts.len); // labels, autos, nparams
|
||||||
|
bc_vec_pop_all(&f->code);
|
||||||
|
ip->idx = 0;
|
||||||
|
IF_BC(bc_vec_pop_all(&f->strs);)
|
||||||
|
IF_BC(bc_vec_pop_all(&f->consts);)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
dbg_lex_done("%s:%d done", __func__, __LINE__);
|
dbg_lex_done("%s:%d done", __func__, __LINE__);
|
||||||
@ -6999,8 +7080,8 @@ static void bc_program_free(void)
|
|||||||
bc_vec_free(&G.prog.var_map);
|
bc_vec_free(&G.prog.var_map);
|
||||||
bc_vec_free(&G.prog.arrs);
|
bc_vec_free(&G.prog.arrs);
|
||||||
bc_vec_free(&G.prog.arr_map);
|
bc_vec_free(&G.prog.arr_map);
|
||||||
bc_vec_free(&G.prog.strs);
|
IF_DC(bc_vec_free(&G.prog.strs);)
|
||||||
bc_vec_free(&G.prog.consts);
|
IF_DC(bc_vec_free(&G.prog.consts);)
|
||||||
bc_vec_free(&G.prog.results);
|
bc_vec_free(&G.prog.results);
|
||||||
bc_vec_free(&G.prog.exestack);
|
bc_vec_free(&G.prog.exestack);
|
||||||
IF_BC(bc_num_free(&G.prog.last);)
|
IF_BC(bc_num_free(&G.prog.last);)
|
||||||
@ -7057,8 +7138,8 @@ static void bc_program_init(void)
|
|||||||
bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
|
bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
|
||||||
bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
|
bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
|
||||||
|
|
||||||
bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);
|
IF_DC(bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);)
|
||||||
bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);
|
IF_DC(bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);)
|
||||||
bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
|
bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
|
||||||
bc_vec_init(&G.prog.exestack, sizeof(BcInstPtr), NULL);
|
bc_vec_init(&G.prog.exestack, sizeof(BcInstPtr), NULL);
|
||||||
bc_vec_push(&G.prog.exestack, &ip);
|
bc_vec_push(&G.prog.exestack, &ip);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user