fixed: a crash in Big::Add() (buffer overflow)

there was an offset calculated from Int type by using Abs() method and a carry was not checked
       (if there is a carry we should not make addition -- the argument is too small)
       this had no impact on calculated values because there was a crash (bus error) immediately

       following program could crash (64bit):
       typedef ttmath::Big<1, 8> MyBig;
       ttmath::Parser<MyBig> parser;
       parser.Parse("2^(2^63) + 1");


fixed: similar problems were in methods Big::BitAnd() Big::BitOr() and Big::BitXor() (bitwise operations)
       and they could return incorrect values



git-svn-id: svn://ttmath.org/publicrep/ttmath/trunk@1189 e52654a7-88a9-db11-a3e9-0013d4bc506e
This commit is contained in:
Tomasz Sowa 2019-04-11 16:14:04 +00:00
parent d93d5ffd74
commit dcdb1db9ec
1 changed files with 62 additions and 44 deletions

View File

@ -5,7 +5,7 @@
*/
/*
* Copyright (c) 2006-2017, Tomasz Sowa
* Copyright (c) 2006-2019, Tomasz Sowa
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
@ -930,7 +930,6 @@ public:
uint Add(Big<exp, man> ss2, bool round = true, bool adding = true)
{
bool last_bit_set, rest_zero, do_adding, do_rounding, rounding_up;
Int<exp> exp_offset( exponent );
uint c = 0;
if( IsNan() || ss2.IsNan() )
@ -939,32 +938,41 @@ public:
if( !adding )
ss2.ChangeSign(); // subtracting
exp_offset.Sub( ss2.exponent );
exp_offset.Abs();
// (1) abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) )
Swap(ss2);
if( ss2.IsZero() )
return 0;
last_bit_set = rest_zero = do_adding = do_rounding = false;
rounding_up = (IsSign() == ss2.IsSign());
Int<exp> exp_offset( exponent );
exp_offset.Sub( ss2.exponent );
AddCheckExponents(ss2, exp_offset, last_bit_set, rest_zero, do_adding, do_rounding);
if( !exp_offset.Abs() )
{
// if there is a carry in Abs it means the value in exp_offset has only the lowest bit set
// so the value is the smallest possible integer
// and its Abs would be greater than mantissa size in bits
// so the method AddCheckExponents would do nothing
if( do_adding )
c += AddMantissas(ss2, last_bit_set, rest_zero);
last_bit_set = rest_zero = do_adding = do_rounding = false;
rounding_up = (IsSign() == ss2.IsSign());
if( !round || !last_bit_set )
do_rounding = false;
AddCheckExponents(ss2, exp_offset, last_bit_set, rest_zero, do_adding, do_rounding);
if( do_rounding )
c += RoundHalfToEven(rest_zero, rounding_up);
if( do_adding )
c += AddMantissas(ss2, last_bit_set, rest_zero);
if( !round || !last_bit_set )
do_rounding = false;
if( do_rounding )
c += RoundHalfToEven(rest_zero, rounding_up);
if( do_adding || do_rounding )
c += Standardizing();
}
if( do_adding || do_rounding )
c += Standardizing();
return CheckCarry(c);
}
@ -993,6 +1001,8 @@ public:
*/
uint BitAnd(Big<exp, man> ss2)
{
uint c = 0;
if( IsNan() || ss2.IsNan() )
return CheckCarry(1);
@ -1011,20 +1021,20 @@ public:
return 0;
}
Int<exp> exp_offset( exponent );
Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT );
uint c = 0;
exp_offset.Sub( ss2.exponent );
exp_offset.Abs();
// abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) )
Swap(ss2);
if( exp_offset >= mantissa_size_in_bits )
Int<exp> exp_offset( exponent );
Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT );
exp_offset.Sub( ss2.exponent );
if( exp_offset.Abs() || exp_offset >= mantissa_size_in_bits )
{
// if there is a carry in Abs it means the value in exp_offset has only the lowest bit set
// so the value is the smallest possible integer
// and its Abs would be greater than mantissa size in bits
// the second value is too small
SetZero();
return 0;
@ -1052,6 +1062,8 @@ public:
*/
uint BitOr(Big<exp, man> ss2)
{
uint c = 0;
if( IsNan() || ss2.IsNan() )
return CheckCarry(1);
@ -1070,21 +1082,23 @@ public:
if( ss2.IsZero() )
return 0;
Int<exp> exp_offset( exponent );
Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT );
uint c = 0;
exp_offset.Sub( ss2.exponent );
exp_offset.Abs();
// abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) )
Swap(ss2);
if( exp_offset >= mantissa_size_in_bits )
Int<exp> exp_offset( exponent );
Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT );
exp_offset.Sub( ss2.exponent );
if( exp_offset.Abs() || exp_offset >= mantissa_size_in_bits )
{
// if there is a carry in Abs it means the value in exp_offset has only the lowest bit set
// so the value is the smallest possible integer
// and its Abs would be greater than mantissa size in bits
// the second value is too small
return 0;
}
// exp_offset < mantissa_size_in_bits, moving 'exp_offset' times
ss2.mantissa.Rcr( exp_offset.ToInt(), 0 );
@ -1108,6 +1122,8 @@ public:
*/
uint BitXor(Big<exp, man> ss2)
{
uint c = 0;
if( IsNan() || ss2.IsNan() )
return CheckCarry(1);
@ -1126,21 +1142,23 @@ public:
return 0;
}
Int<exp> exp_offset( exponent );
Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT );
uint c = 0;
exp_offset.Sub( ss2.exponent );
exp_offset.Abs();
// abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) )
Swap(ss2);
if( exp_offset >= mantissa_size_in_bits )
Int<exp> exp_offset( exponent );
Int<exp> mantissa_size_in_bits( man * TTMATH_BITS_PER_UINT );
exp_offset.Sub( ss2.exponent );
if( exp_offset.Abs() || exp_offset >= mantissa_size_in_bits )
{
// if there is a carry in Abs it means the value in exp_offset has only the lowest bit set
// so the value is the smallest possible integer
// and its Abs would be greater than mantissa size in bits
// the second value is too small
return 0;
}
// exp_offset < mantissa_size_in_bits, moving 'exp_offset' times
ss2.mantissa.Rcr( exp_offset.ToInt(), 0 );