aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDenys Vlasenko <vda.linux@googlemail.com>2018-12-21 16:22:26 +0100
committerDenys Vlasenko <vda.linux@googlemail.com>2018-12-21 16:22:26 +0100
commit5d57bc442dfebefdd7db37c04fe2c9f1343bd08d (patch)
tree67f834c1ca2d6d1195bf0c3e177ebca24d1e3fd7
parent447dc02c2759e8c965dfcb3280b335b49a8c3a61 (diff)
downloadbusybox-5d57bc442dfebefdd7db37c04fe2c9f1343bd08d.tar.gz
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>
-rw-r--r--miscutils/bc.c137
1 files changed, 109 insertions, 28 deletions
diff --git a/miscutils/bc.c b/miscutils/bc.c
index 05dbd62f6..50e5457b9 100644
--- a/miscutils/bc.c
+++ b/miscutils/bc.c
@@ -350,6 +350,8 @@ typedef struct BcFunc {
BcVec code;
IF_BC(BcVec labels;)
IF_BC(BcVec autos;)
+ IF_BC(BcVec strs;)
+ IF_BC(BcVec consts;)
IF_BC(size_t nparams;)
} BcFunc;
@@ -694,8 +696,8 @@ typedef struct BcProgram {
BcVec arrs;
BcVec arr_map;
- BcVec strs;
- BcVec consts;
+ IF_DC(BcVec strs;)
+ IF_DC(BcVec consts;)
const char *file;
@@ -1093,6 +1095,7 @@ static void bc_vec_pop_all(BcVec *v)
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)
{
if (v->len + 1 > v->cap) bc_vec_grow(v, 1);
@@ -1160,9 +1163,21 @@ static void *bc_vec_item(const BcVec *v, size_t idx)
return v->v + v->size * idx;
}
-static char** bc_program_str(size_t idx)
+static void *bc_vec_item_rev(const BcVec *v, size_t idx)
+{
+ return v->v + v->size * (v->len - idx - 1);
+}
+
+static void *bc_vec_top(const BcVec *v)
{
- return bc_vec_item(&G.prog.strs, idx);
+ return v->v + v->size * (v->len - 1);
+}
+
+static FAST_FUNC void bc_vec_free(void *vec)
+{
+ BcVec *v = (BcVec *) vec;
+ bc_vec_pop_all(v);
+ free(v->v);
}
static BcFunc* bc_program_func(size_t idx)
@@ -1172,23 +1187,39 @@ static BcFunc* bc_program_func(size_t 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)
+#if ENABLE_BC
+static BcFunc* bc_program_current_func(void)
{
- return v->v + v->size * (v->len - idx - 1);
+ BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
+ BcFunc *func = bc_program_func(ip->func);
+ return func;
}
+#endif
-static void *bc_vec_top(const BcVec *v)
+static char** bc_program_str(size_t idx)
{
- return v->v + v->size * (v->len - 1);
+#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 FAST_FUNC void bc_vec_free(void *vec)
+static char** bc_program_const(size_t idx)
{
- BcVec *v = (BcVec *) vec;
- bc_vec_pop_all(v);
- free(v->v);
+#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)
{
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)
#endif
+static FAST_FUNC void bc_string_free(void *string)
+{
+ free(*(char**)string);
+}
+
static void bc_func_init(BcFunc *f)
{
bc_char_vec_init(&f->code);
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->strs, sizeof(char *), bc_string_free);)
+ IF_BC(bc_vec_init(&f->consts, sizeof(char *), bc_string_free);)
IF_BC(f->nparams = 0;)
}
@@ -2536,6 +2574,8 @@ static FAST_FUNC void bc_func_free(void *func)
bc_vec_free(&f->code);
IF_BC(bc_vec_free(&f->labels);)
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);
@@ -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
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);
bc_parse_push(p, BC_INST_STR);
- bc_parse_pushIndex(p, G.prog.strs.len);
- bc_vec_push(&G.prog.strs, &str);
+ bc_parse_pushIndex(p, p->func->strs.len);
+ bc_vec_push(&p->func->strs, &str);
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)
{
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;
-
bc_vec_push(&G.prog.consts, &num);
-
+#endif
bc_parse_push(p, BC_INST_NUM);
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_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->idx = f->code.len;
}
@@ -5027,9 +5068,12 @@ static BC_STATUS zbc_program_num(BcResult *r, BcNum **num, bool hex)
break;
case BC_RESULT_CONSTANT: {
BcStatus s;
- char *str = *(char**)bc_vec_item(&G.prog.consts, r->d.id.idx);
+ char *str;
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);
@@ -6667,6 +6711,43 @@ static BC_STATUS zbc_vm_process(const char *text)
bc_program_reset();
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__);
@@ -6999,8 +7080,8 @@ static void bc_program_free(void)
bc_vec_free(&G.prog.var_map);
bc_vec_free(&G.prog.arrs);
bc_vec_free(&G.prog.arr_map);
- bc_vec_free(&G.prog.strs);
- bc_vec_free(&G.prog.consts);
+ IF_DC(bc_vec_free(&G.prog.strs);)
+ IF_DC(bc_vec_free(&G.prog.consts);)
bc_vec_free(&G.prog.results);
bc_vec_free(&G.prog.exestack);
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.arr_map, sizeof(BcId), bc_id_free);
- 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.strs, 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.exestack, sizeof(BcInstPtr), NULL);
bc_vec_push(&G.prog.exestack, &ip);