diff options
author | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-21 16:22:26 +0100 |
---|---|---|
committer | Denys Vlasenko <vda.linux@googlemail.com> | 2018-12-21 16:22:26 +0100 |
commit | 5d57bc442dfebefdd7db37c04fe2c9f1343bd08d (patch) | |
tree | 67f834c1ca2d6d1195bf0c3e177ebca24d1e3fd7 /miscutils/bc.c | |
parent | 447dc02c2759e8c965dfcb3280b335b49a8c3a61 (diff) | |
download | busybox-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.c | 137 |
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 | ||
1096 | static void bc_vec_push(BcVec *v, const void *data) | 1099 | static 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 | ||
1163 | static char** bc_program_str(size_t idx) | 1166 | static void *bc_vec_item_rev(const BcVec *v, size_t idx) |
1167 | { | ||
1168 | return v->v + v->size * (v->len - idx - 1); | ||
1169 | } | ||
1170 | |||
1171 | static 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 | |||
1176 | static 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 | ||
1168 | static BcFunc* bc_program_func(size_t idx) | 1183 | static 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 | ||
1175 | static void *bc_vec_item_rev(const BcVec *v, size_t idx) | 1190 | #if ENABLE_BC |
1191 | static 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 | ||
1180 | static void *bc_vec_top(const BcVec *v) | 1199 | static 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 | ||
1185 | static FAST_FUNC void bc_vec_free(void *vec) | 1210 | static 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 | |||
1192 | static int bc_id_cmp(const void *e1, const void *e2) | 1223 | static 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 | ||
2556 | static FAST_FUNC void bc_string_free(void *string) | ||
2557 | { | ||
2558 | free(*(char**)string); | ||
2559 | } | ||
2560 | |||
2525 | static void bc_func_init(BcFunc *f) | 2561 | static 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 | ||
2541 | static void bc_array_expand(BcVec *a, size_t len); | 2581 | static 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 | ||
2588 | static FAST_FUNC void bc_string_free(void *string) | ||
2589 | { | ||
2590 | free(*((char **) string)); | ||
2591 | } | ||
2592 | |||
2593 | #if ENABLE_DC | 2628 | #if ENABLE_DC |
2594 | static void dc_result_copy(BcResult *d, BcResult *src) | 2629 | static 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) | |||
3512 | static void bc_parse_pushNUM(BcParse *p) | 3547 | static 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); |