aboutsummaryrefslogtreecommitdiff
path: root/miscutils/bc.c
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 /miscutils/bc.c
parent447dc02c2759e8c965dfcb3280b335b49a8c3a61 (diff)
downloadbusybox-w32-5d57bc442dfebefdd7db37c04fe2c9f1343bd08d.tar.gz
busybox-w32-5d57bc442dfebefdd7db37c04fe2c9f1343bd08d.tar.bz2
busybox-w32-5d57bc442dfebefdd7db37c04fe2c9f1343bd08d.zip
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>
Diffstat (limited to '')
-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 {
350 BcVec code; 350 BcVec code;
351 IF_BC(BcVec labels;) 351 IF_BC(BcVec labels;)
352 IF_BC(BcVec autos;) 352 IF_BC(BcVec autos;)
353 IF_BC(BcVec strs;)
354 IF_BC(BcVec consts;)
353 IF_BC(size_t nparams;) 355 IF_BC(size_t nparams;)
354} BcFunc; 356} BcFunc;
355 357
@@ -694,8 +696,8 @@ typedef struct BcProgram {
694 BcVec arrs; 696 BcVec arrs;
695 BcVec arr_map; 697 BcVec arr_map;
696 698
697 BcVec strs; 699 IF_DC(BcVec strs;)
698 BcVec consts; 700 IF_DC(BcVec consts;)
699 701
700 const char *file; 702 const char *file;
701 703
@@ -1093,6 +1095,7 @@ static void bc_vec_pop_all(BcVec *v)
1093 bc_vec_npop(v, v->len); 1095 bc_vec_npop(v, v->len);
1094} 1096}
1095 1097
1098//TODO: return index of pushed data - many callers can use that
1096static void bc_vec_push(BcVec *v, const void *data) 1099static void bc_vec_push(BcVec *v, const void *data)
1097{ 1100{
1098 if (v->len + 1 > v->cap) bc_vec_grow(v, 1); 1101 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)
1160 return v->v + v->size * idx; 1163 return v->v + v->size * idx;
1161} 1164}
1162 1165
1163static char** bc_program_str(size_t idx) 1166static void *bc_vec_item_rev(const BcVec *v, size_t idx)
1167{
1168 return v->v + v->size * (v->len - idx - 1);
1169}
1170
1171static void *bc_vec_top(const BcVec *v)
1164{ 1172{
1165 return bc_vec_item(&G.prog.strs, idx); 1173 return v->v + v->size * (v->len - 1);
1174}
1175
1176static FAST_FUNC void bc_vec_free(void *vec)
1177{
1178 BcVec *v = (BcVec *) vec;
1179 bc_vec_pop_all(v);
1180 free(v->v);
1166} 1181}
1167 1182
1168static BcFunc* bc_program_func(size_t idx) 1183static BcFunc* bc_program_func(size_t idx)
@@ -1172,23 +1187,39 @@ static BcFunc* bc_program_func(size_t idx)
1172// BC_PROG_MAIN is zeroth element, so: 1187// BC_PROG_MAIN is zeroth element, so:
1173#define bc_program_func_BC_PROG_MAIN() ((BcFunc*)(G.prog.fns.v)) 1188#define bc_program_func_BC_PROG_MAIN() ((BcFunc*)(G.prog.fns.v))
1174 1189
1175static void *bc_vec_item_rev(const BcVec *v, size_t idx) 1190#if ENABLE_BC
1191static BcFunc* bc_program_current_func(void)
1176{ 1192{
1177 return v->v + v->size * (v->len - idx - 1); 1193 BcInstPtr *ip = bc_vec_top(&G.prog.exestack);
1194 BcFunc *func = bc_program_func(ip->func);
1195 return func;
1178} 1196}
1197#endif
1179 1198
1180static void *bc_vec_top(const BcVec *v) 1199static char** bc_program_str(size_t idx)
1181{ 1200{
1182 return v->v + v->size * (v->len - 1); 1201#if ENABLE_BC
1202 if (IS_BC) {
1203 BcFunc *func = bc_program_current_func();
1204 return bc_vec_item(&func->strs, idx);
1205 }
1206#endif
1207 IF_DC(return bc_vec_item(&G.prog.strs, idx);)
1183} 1208}
1184 1209
1185static FAST_FUNC void bc_vec_free(void *vec) 1210static char** bc_program_const(size_t idx)
1186{ 1211{
1187 BcVec *v = (BcVec *) vec; 1212#if ENABLE_BC
1188 bc_vec_pop_all(v); 1213 if (IS_BC) {
1189 free(v->v); 1214 BcFunc *func = bc_program_current_func();
1215 return bc_vec_item(&func->consts, idx);
1216 }
1217#endif
1218 IF_DC(return bc_vec_item(&G.prog.consts, idx);)
1190} 1219}
1191 1220
1221
1222
1192static int bc_id_cmp(const void *e1, const void *e2) 1223static int bc_id_cmp(const void *e1, const void *e2)
1193{ 1224{
1194 return strcmp(((const BcId *) e1)->name, ((const BcId *) e2)->name); 1225 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)
2522#define zbc_func_insert(...) (zbc_func_insert(__VA_ARGS__) COMMA_SUCCESS) 2553#define zbc_func_insert(...) (zbc_func_insert(__VA_ARGS__) COMMA_SUCCESS)
2523#endif 2554#endif
2524 2555
2556static FAST_FUNC void bc_string_free(void *string)
2557{
2558 free(*(char**)string);
2559}
2560
2525static void bc_func_init(BcFunc *f) 2561static void bc_func_init(BcFunc *f)
2526{ 2562{
2527 bc_char_vec_init(&f->code); 2563 bc_char_vec_init(&f->code);
2528 IF_BC(bc_vec_init(&f->labels, sizeof(size_t), NULL);) 2564 IF_BC(bc_vec_init(&f->labels, sizeof(size_t), NULL);)
2529 IF_BC(bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);) 2565 IF_BC(bc_vec_init(&f->autos, sizeof(BcId), bc_id_free);)
2566 IF_BC(bc_vec_init(&f->strs, sizeof(char *), bc_string_free);)
2567 IF_BC(bc_vec_init(&f->consts, sizeof(char *), bc_string_free);)
2530 IF_BC(f->nparams = 0;) 2568 IF_BC(f->nparams = 0;)
2531} 2569}
2532 2570
@@ -2536,6 +2574,8 @@ static FAST_FUNC void bc_func_free(void *func)
2536 bc_vec_free(&f->code); 2574 bc_vec_free(&f->code);
2537 IF_BC(bc_vec_free(&f->labels);) 2575 IF_BC(bc_vec_free(&f->labels);)
2538 IF_BC(bc_vec_free(&f->autos);) 2576 IF_BC(bc_vec_free(&f->autos);)
2577 IF_BC(bc_vec_free(&f->strs);)
2578 IF_BC(bc_vec_free(&f->consts);)
2539} 2579}
2540 2580
2541static void bc_array_expand(BcVec *a, size_t len); 2581static void bc_array_expand(BcVec *a, size_t len);
@@ -2585,11 +2625,6 @@ static void bc_array_copy(BcVec *d, const BcVec *s)
2585 } 2625 }
2586} 2626}
2587 2627
2588static FAST_FUNC void bc_string_free(void *string)
2589{
2590 free(*((char **) string));
2591}
2592
2593#if ENABLE_DC 2628#if ENABLE_DC
2594static void dc_result_copy(BcResult *d, BcResult *src) 2629static void dc_result_copy(BcResult *d, BcResult *src)
2595{ 2630{
@@ -3501,8 +3536,8 @@ static BC_STATUS bc_parse_pushSTR(BcParse *p)
3501 char *str = xstrdup(p->l.t.v.v); 3536 char *str = xstrdup(p->l.t.v.v);
3502 3537
3503 bc_parse_push(p, BC_INST_STR); 3538 bc_parse_push(p, BC_INST_STR);
3504 bc_parse_pushIndex(p, G.prog.strs.len); 3539 bc_parse_pushIndex(p, p->func->strs.len);
3505 bc_vec_push(&G.prog.strs, &str); 3540 bc_vec_push(&p->func->strs, &str);
3506 3541
3507 RETURN_STATUS(zbc_lex_next(&p->l)); 3542 RETURN_STATUS(zbc_lex_next(&p->l));
3508} 3543}
@@ -3512,10 +3547,16 @@ static BC_STATUS bc_parse_pushSTR(BcParse *p)
3512static void bc_parse_pushNUM(BcParse *p) 3547static void bc_parse_pushNUM(BcParse *p)
3513{ 3548{
3514 char *num = xstrdup(p->l.t.v.v); 3549 char *num = xstrdup(p->l.t.v.v);
3550#if ENABLE_BC && ENABLE_DC
3551 size_t idx = IS_BC ? p->func->consts.len : G.prog.consts.len;
3552 bc_vec_push(IS_BC ? &p->func->consts : &G.prog.consts, &num);
3553#elif ENABLE_BC
3554 size_t idx = p->func->consts.len;
3555 bc_vec_push(&p->func->consts, &num);
3556#else // DC
3515 size_t idx = G.prog.consts.len; 3557 size_t idx = G.prog.consts.len;
3516
3517 bc_vec_push(&G.prog.consts, &num); 3558 bc_vec_push(&G.prog.consts, &num);
3518 3559#endif
3519 bc_parse_push(p, BC_INST_NUM); 3560 bc_parse_push(p, BC_INST_NUM);
3520 bc_parse_pushIndex(p, idx); 3561 bc_parse_pushIndex(p, idx);
3521} 3562}
@@ -3556,7 +3597,7 @@ static void bc_program_reset(void)
3556 bc_vec_npop(&G.prog.exestack, G.prog.exestack.len - 1); 3597 bc_vec_npop(&G.prog.exestack, G.prog.exestack.len - 1);
3557 bc_vec_pop_all(&G.prog.results); 3598 bc_vec_pop_all(&G.prog.results);
3558 3599
3559 f = bc_program_func(0); 3600 f = bc_program_func_BC_PROG_MAIN();
3560 ip = bc_vec_top(&G.prog.exestack); 3601 ip = bc_vec_top(&G.prog.exestack);
3561 ip->idx = f->code.len; 3602 ip->idx = f->code.len;
3562} 3603}
@@ -5027,9 +5068,12 @@ static BC_STATUS zbc_program_num(BcResult *r, BcNum **num, bool hex)
5027 break; 5068 break;
5028 case BC_RESULT_CONSTANT: { 5069 case BC_RESULT_CONSTANT: {
5029 BcStatus s; 5070 BcStatus s;
5030 char *str = *(char**)bc_vec_item(&G.prog.consts, r->d.id.idx); 5071 char *str;
5031 unsigned base_t; 5072 unsigned base_t;
5032 size_t len = strlen(str); 5073 size_t len;
5074
5075 str = *bc_program_const(r->d.id.idx);
5076 len = strlen(str);
5033 5077
5034 bc_num_init(&r->d.n, len); 5078 bc_num_init(&r->d.n, len);
5035 5079
@@ -6667,6 +6711,43 @@ static BC_STATUS zbc_vm_process(const char *text)
6667 bc_program_reset(); 6711 bc_program_reset();
6668 break; 6712 break;
6669 } 6713 }
6714 // bc discards strings, constants and code after each
6715 // top-level statement in the "main program".
6716 // This prevents "yes 1 | bc" from growing its memory
6717 // without bound. This can be done because data stack
6718 // is empty and thus can't hold any references to
6719 // strings or constants, there is no generated code
6720 // which can hold references (after we discard one
6721 // we just executed). Code of functions can have references,
6722 // but bc stores function strings/constants in per-function
6723 // storage.
6724 if (IS_BC) {
6725 BcFunc *f;
6726 BcInstPtr *ip;
6727
6728 //FIXME: this does not clear up the stack
6729 //for(i=1; i<3; i++) {
6730 // i
6731 // if(i==2) continue
6732 // 77
6733 //}
6734// if (G.prog.results.len != 0)
6735// bb_error_msg_and_die("data stack not empty: %d slots", G.prog.results.len);
6736
6737 if (G.prog.exestack.len != 1) // should be empty
6738 bb_error_msg_and_die("BUG:call stack");
6739
6740 ip = (void*)G.prog.exestack.v;
6741 if (ip->func != BC_PROG_MAIN)
6742 bb_error_msg_and_die("BUG:not MAIN");
6743//bb_error_msg("ip->func:%d >idx:%d >len:%d", ip->func, ip->idx, ip->len);
6744 f = bc_program_func_BC_PROG_MAIN();
6745//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
6746 bc_vec_pop_all(&f->code);
6747 ip->idx = 0;
6748 IF_BC(bc_vec_pop_all(&f->strs);)
6749 IF_BC(bc_vec_pop_all(&f->consts);)
6750 }
6670 } 6751 }
6671 6752
6672 dbg_lex_done("%s:%d done", __func__, __LINE__); 6753 dbg_lex_done("%s:%d done", __func__, __LINE__);
@@ -6999,8 +7080,8 @@ static void bc_program_free(void)
6999 bc_vec_free(&G.prog.var_map); 7080 bc_vec_free(&G.prog.var_map);
7000 bc_vec_free(&G.prog.arrs); 7081 bc_vec_free(&G.prog.arrs);
7001 bc_vec_free(&G.prog.arr_map); 7082 bc_vec_free(&G.prog.arr_map);
7002 bc_vec_free(&G.prog.strs); 7083 IF_DC(bc_vec_free(&G.prog.strs);)
7003 bc_vec_free(&G.prog.consts); 7084 IF_DC(bc_vec_free(&G.prog.consts);)
7004 bc_vec_free(&G.prog.results); 7085 bc_vec_free(&G.prog.results);
7005 bc_vec_free(&G.prog.exestack); 7086 bc_vec_free(&G.prog.exestack);
7006 IF_BC(bc_num_free(&G.prog.last);) 7087 IF_BC(bc_num_free(&G.prog.last);)
@@ -7057,8 +7138,8 @@ static void bc_program_init(void)
7057 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free); 7138 bc_vec_init(&G.prog.arrs, sizeof(BcVec), bc_vec_free);
7058 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free); 7139 bc_vec_init(&G.prog.arr_map, sizeof(BcId), bc_id_free);
7059 7140
7060 bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free); 7141 IF_DC(bc_vec_init(&G.prog.strs, sizeof(char *), bc_string_free);)
7061 bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free); 7142 IF_DC(bc_vec_init(&G.prog.consts, sizeof(char *), bc_string_free);)
7062 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free); 7143 bc_vec_init(&G.prog.results, sizeof(BcResult), bc_result_free);
7063 bc_vec_init(&G.prog.exestack, sizeof(BcInstPtr), NULL); 7144 bc_vec_init(&G.prog.exestack, sizeof(BcInstPtr), NULL);
7064 bc_vec_push(&G.prog.exestack, &ip); 7145 bc_vec_push(&G.prog.exestack, &ip);