bc: fix for mul overflow in scale calculation in a^b
function old new delta zbc_num_p 516 518 +2 Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
parent
4d983dcdde
commit
e5958f7dda
@ -2152,6 +2152,7 @@ static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size
|
|||||||
BcNum copy;
|
BcNum copy;
|
||||||
unsigned long pow;
|
unsigned long pow;
|
||||||
size_t i, powrdx, resrdx;
|
size_t i, powrdx, resrdx;
|
||||||
|
size_t a_rdx;
|
||||||
bool neg;
|
bool neg;
|
||||||
|
|
||||||
// GNU bc does not allow 2^2.0 - we do
|
// GNU bc does not allow 2^2.0 - we do
|
||||||
@ -2182,16 +2183,30 @@ static FAST_FUNC BC_STATUS zbc_num_p(BcNum *a, BcNum *b, BcNum *restrict c, size
|
|||||||
|
|
||||||
bc_num_init(©, a->len);
|
bc_num_init(©, a->len);
|
||||||
bc_num_copy(©, a);
|
bc_num_copy(©, a);
|
||||||
|
a_rdx = a->rdx; // pull it into a CPU register (hopefully)
|
||||||
|
// a is not used beyond this point
|
||||||
|
|
||||||
if (!neg) {
|
if (!neg) {
|
||||||
if (a->rdx > scale)
|
unsigned long new_scale;
|
||||||
scale = a->rdx;
|
if (a_rdx > scale)
|
||||||
if (a->rdx * pow < scale)
|
scale = a_rdx;
|
||||||
scale = a->rdx * pow;
|
new_scale = a_rdx * pow;
|
||||||
|
// Don't fall for multiplication overflow. Example:
|
||||||
|
// 0.01^2147483648 a_rdx:2 pow:0x80000000, 32bit mul is 0.
|
||||||
|
//not that it matters with current algorithm, it would OOM on such large powers,
|
||||||
|
//but it can be improved to detect zero results etc. Example: with scale=0,
|
||||||
|
//result of 0.01^N for any N>1 is 0: 0.01^2 = 0.0001 ~= 0.00 (trunc to scale)
|
||||||
|
//then this would matter:
|
||||||
|
// if (new_scale >= pow) is false, we had overflow, correct
|
||||||
|
// "new_scale" value is larger than ULONG_MAX, thus larger
|
||||||
|
// than any possible current value of "scale",
|
||||||
|
// thus "scale = new_scale" should not be done:
|
||||||
|
if (new_scale >= pow)
|
||||||
|
if (new_scale < scale)
|
||||||
|
scale = new_scale;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (powrdx = a_rdx; !(pow & 1); pow >>= 1) {
|
||||||
for (powrdx = a->rdx; !(pow & 1); pow >>= 1) {
|
|
||||||
powrdx <<= 1;
|
powrdx <<= 1;
|
||||||
s = zbc_num_mul(©, ©, ©, powrdx);
|
s = zbc_num_mul(©, ©, ©, powrdx);
|
||||||
if (s) goto err;
|
if (s) goto err;
|
||||||
|
Loading…
Reference in New Issue
Block a user