From 1a63323d17fedb05b6962853e821c9d7c6b9853e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefan=20E=C3=9Fer?= Date: Sat, 28 Jan 2023 21:08:43 +0100 Subject: [PATCH] vendor/bc: import version 6.2.2 This is a production release that fixes a bug. The bug was that if an array element was used as a parameter, and then a later parameter had the same name as the array whose element was used, bc would grab the element from the new array parameter, not the actual element from before the function call. --- NEWS.md | 9 ++++ include/lang.h | 6 +++ include/program.h | 9 ---- include/version.h | 2 +- src/program.c | 95 ++++++++++++++----------------------- tests/bc/scripts/all.txt | 1 + tests/bc/scripts/array2.bc | 20 ++++++++ tests/bc/scripts/array2.txt | 2 + 8 files changed, 75 insertions(+), 69 deletions(-) create mode 100644 tests/bc/scripts/array2.bc create mode 100644 tests/bc/scripts/array2.txt diff --git a/NEWS.md b/NEWS.md index 7adabb8cd6b8..36952fdaf582 100644 --- a/NEWS.md +++ b/NEWS.md @@ -1,5 +1,14 @@ # News +## 6.2.2 + +This is a production release that fixes a bug. + +The bug was that if an array element was used as a parameter, and then a later +parameter had the same name as the array whose element was used, `bc` would grab +the element from the new array parameter, not the actual element from before the +function call. + ## 6.2.1 This is a production release with one bug fix for a memory bug in history. diff --git a/include/lang.h b/include/lang.h index 4ad6df88f5ed..2d9776532249 100644 --- a/include/lang.h +++ b/include/lang.h @@ -352,6 +352,12 @@ typedef struct BcLoc /// The index of the var or array. size_t loc; + /// The index of the array or variable in the array stack. This is to + /// prevent a bug with getting the wrong array element or variable after a + /// function call. See the tests/bc/scripts/array.bc test for the array + /// case; the variable case is in various variable tests. + size_t stack_idx; + /// The index of the array element. Only used for array elements. size_t idx; diff --git a/include/program.h b/include/program.h index 3acd5157b127..3a3ea6c9dab7 100644 --- a/include/program.h +++ b/include/program.h @@ -220,20 +220,11 @@ typedef struct BcProgram #if !BC_ENABLED -/// This define disappears the parameter last because for dc only, last is -/// always true. -#define bc_program_copyToVar(p, name, t, last) \ - bc_program_copyToVar_impl(p, name, t) - /// Returns true if the calculator should pop after printing. #define BC_PROGRAM_POP(pop) (pop) #else // !BC_ENABLED -// This is here to quiet a compiler warning. -#define bc_program_copyToVar(p, name, t, last) \ - bc_program_copyToVar_impl(p, name, t, last) - /// Returns true if the calculator should pop after printing. #define BC_PROGRAM_POP(pop) (BC_IS_BC || (pop)) diff --git a/include/version.h b/include/version.h index a9abf5be6c67..e1b72de90eef 100644 --- a/include/version.h +++ b/include/version.h @@ -37,6 +37,6 @@ #define BC_VERSION_H /// The current version. -#define VERSION 6.2.1 +#define VERSION 6.2.2 #endif // BC_VERSION_H diff --git a/src/program.c b/src/program.c index 5424b715a29b..7e2ba8178b61 100644 --- a/src/program.c +++ b/src/program.c @@ -346,7 +346,7 @@ bc_program_num(BcProgram* p, BcResult* r) { size_t idx = r->d.loc.idx; - v = bc_vec_top(v); + v = bc_vec_item(v, r->d.loc.stack_idx); #if BC_ENABLED // If this is true, we have a reference vector, so dereference @@ -376,8 +376,21 @@ bc_program_num(BcProgram* p, BcResult* r) n = bc_vec_item(v, idx); } // This is either a number (for a var) or an array (for an array). - // Because bc_vec_top() returns a void*, we don't need to cast. - else n = bc_vec_top(v); + // Because bc_vec_top() and bc_vec_item() return a void*, we don't + // need to cast. + else + { +#if BC_ENABLED + if (BC_IS_BC) + { + n = bc_vec_item(v, r->d.loc.stack_idx); + } + else +#endif // BC_ENABLED + { + n = bc_vec_top(v); + } + } break; } @@ -1181,18 +1194,12 @@ bc_program_assignStr(BcProgram* p, BcNum* num, BcVec* v, bool push) /** * Copies a value to a variable. This is used for storing in dc as well as to * set function parameters to arguments in bc. - * @param p The program. - * @param idx The index of the variable or array to copy to. - * @param t The type to copy to. This could be a variable or an array. - * @param last Whether to grab the last item on the variable stack or not (for - * bc function parameters). This is important because if a new - * value has been pushed to the variable already, we need to grab - * the value pushed before. This happens when you have a parameter - * named something like "x", and a variable "x" is passed to - * another parameter. + * @param p The program. + * @param idx The index of the variable or array to copy to. + * @param t The type to copy to. This could be a variable or an array. */ static void -bc_program_copyToVar(BcProgram* p, size_t idx, BcType t, bool last) +bc_program_copyToVar(BcProgram* p, size_t idx, BcType t) { BcResult *ptr = NULL, r; BcVec* vec; @@ -1217,13 +1224,6 @@ bc_program_copyToVar(BcProgram* p, size_t idx, BcType t, bool last) { // Type match the result. bc_program_type_match(ptr, t); - - // Get the variable or array, taking care to get the real item. We take - // care of last with arrays later. - if (!last && var) - { - n = bc_vec_item_rev(bc_program_vec(p, ptr->d.loc.loc, t), 1); - } } #endif // BC_ENABLED @@ -1265,19 +1265,8 @@ bc_program_copyToVar(BcProgram* p, size_t idx, BcType t, bool last) if (BC_IS_BC) { - BcVec* parent; bool ref, ref_size; - // We need to figure out if the parameter is a reference or not and - // construct the reference vector, if necessary. So this gets the - // parent stack for the array. - parent = bc_program_vec(p, ptr->d.loc.loc, t); - assert(parent != NULL); - - // This takes care of last for arrays. Mostly. - if (!last) v = bc_vec_item_rev(parent, !last); - assert(v != NULL); - // True if we are using a reference. ref = (v->size == sizeof(BcNum) && t == BC_TYPE_REF); @@ -1297,8 +1286,6 @@ bc_program_copyToVar(BcProgram* p, size_t idx, BcType t, bool last) // If this is true, then we need to construct a reference. if (ref) { - assert(parent->len >= (size_t) (!last + 1)); - // Make sure the pointer was not invalidated. vec = bc_program_vec(p, idx, t); @@ -1306,7 +1293,7 @@ bc_program_copyToVar(BcProgram* p, size_t idx, BcType t, bool last) // care of last; it ensures the reference goes to the right // place. bc_vec_pushIndex(rv, ptr->d.loc.loc); - bc_vec_pushIndex(rv, parent->len - !last - 1); + bc_vec_pushIndex(rv, ptr->d.loc.stack_idx); } // If we get here, we are copying a ref to a ref. Just push a // copy of all of the bytes. @@ -1600,18 +1587,22 @@ bc_program_pushVar(BcProgram* p, const char* restrict code, { BcResult r; size_t idx = bc_program_index(code, bgn); + BcVec* v; // Set the result appropriately. r.t = BC_RESULT_VAR; r.d.loc.loc = idx; + // Get the stack for the variable. This is used in both bc and dc. + v = bc_program_vec(p, idx, BC_TYPE_VAR); + r.d.loc.stack_idx = v->len - 1; + #if DC_ENABLED // If this condition is true, then we have the hard case, where we have to // adjust dc registers. if (BC_IS_DC && (pop || copy)) { - // Get the stack for the variable and the number at the top. - BcVec* v = bc_program_vec(p, idx, BC_TYPE_VAR); + // Get the number at the top at the top of the stack. BcNum* num = bc_vec_top(v); // Ensure there are enough elements on the stack. @@ -1674,10 +1665,17 @@ bc_program_pushArray(BcProgram* p, const char* restrict code, BcResult* operand; BcNum* num; BcBigDig temp; + BcVec* v; // Get the index of the array. r.d.loc.loc = bc_program_index(code, bgn); + // We need the array to get its length. + v = bc_program_vec(p, r.d.loc.loc, BC_TYPE_ARRAY); + assert(v != NULL); + + r.d.loc.stack_idx = v->len - 1; + // Doing an array is easy; just set the result type and finish. if (inst == BC_INST_ARRAY) { @@ -1800,35 +1798,14 @@ bc_program_call(BcProgram* p, const char* restrict code, size_t* restrict bgn) // Push the arguments onto the stacks of their respective parameters. for (i = 0; i < nargs; ++i) { - size_t j; - bool last = true; - arg = bc_vec_top(&p->results); if (BC_ERR(arg->t == BC_RESULT_VOID)) bc_err(BC_ERR_EXEC_VOID_VAL); // Get the corresponding parameter. a = bc_vec_item(&f->autos, nargs - 1 - i); - // If I have already pushed to a var, I need to make sure I - // get the previous version, not the already pushed one. This condition - // must be true for that to even be possible. - if (arg->t == BC_RESULT_VAR || arg->t == BC_RESULT_ARRAY) - { - // Loop through all of the previous parameters. - for (j = 0; j < i && last; ++j) - { - BcAuto* aptr = bc_vec_item(&f->autos, nargs - 1 - j); - - // This condition is true if there is a previous parameter with - // the same name *and* type because variables and arrays do not - // interfere with each other. - last = (arg->d.loc.loc != aptr->idx || - (!aptr->type) != (arg->t == BC_RESULT_VAR)); - } - } - // Actually push the value onto the parameter's stack. - bc_program_copyToVar(p, a->idx, a->type, last); + bc_program_copyToVar(p, a->idx, a->type); } BC_SIG_LOCK; @@ -3650,7 +3627,7 @@ bc_program_exec(BcProgram* p) // clang-format on { idx = bc_program_index(code, &ip->idx); - bc_program_copyToVar(p, idx, BC_TYPE_VAR, true); + bc_program_copyToVar(p, idx, BC_TYPE_VAR); BC_PROG_JUMP(inst, code, ip); } diff --git a/tests/bc/scripts/all.txt b/tests/bc/scripts/all.txt index b4a178783796..e2d2aa320c6f 100644 --- a/tests/bc/scripts/all.txt +++ b/tests/bc/scripts/all.txt @@ -5,6 +5,7 @@ add.bc print.bc parse.bc array.bc +array2.bc atan.bc bessel.bc functions.bc diff --git a/tests/bc/scripts/array2.bc b/tests/bc/scripts/array2.bc new file mode 100644 index 000000000000..34d88c3e276b --- /dev/null +++ b/tests/bc/scripts/array2.bc @@ -0,0 +1,20 @@ +#! /usr/bin/bc -q + +define z(x, a[]) { + return x + a[1] +} + +define y(x, *b[]) { + return x + b[1] +} + +a[0] = 5 +a[1] = 6 + +b[0] = 8 +b[1] = 7 + +z(a[0], b[]) +y(b[0], a[]) + +halt diff --git a/tests/bc/scripts/array2.txt b/tests/bc/scripts/array2.txt new file mode 100644 index 000000000000..76dcb035f907 --- /dev/null +++ b/tests/bc/scripts/array2.txt @@ -0,0 +1,2 @@ +12 +14