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. * All rights reserved.
* *
* Redistribution and use in source and binary forms, with or without * 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) uint Add(Big<exp, man> ss2, bool round = true, bool adding = true)
{ {
bool last_bit_set, rest_zero, do_adding, do_rounding, rounding_up; bool last_bit_set, rest_zero, do_adding, do_rounding, rounding_up;
Int<exp> exp_offset( exponent );
uint c = 0; uint c = 0;
if( IsNan() || ss2.IsNan() ) if( IsNan() || ss2.IsNan() )
@ -939,32 +938,41 @@ public:
if( !adding ) if( !adding )
ss2.ChangeSign(); // subtracting ss2.ChangeSign(); // subtracting
exp_offset.Sub( ss2.exponent );
exp_offset.Abs();
// (1) abs(this) will be >= abs(ss2) // (1) abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) ) if( SmallerWithoutSignThan(ss2) )
Swap(ss2); Swap(ss2);
if( ss2.IsZero() ) if( ss2.IsZero() )
return 0; return 0;
last_bit_set = rest_zero = do_adding = do_rounding = false; Int<exp> exp_offset( exponent );
rounding_up = (IsSign() == ss2.IsSign()); 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 ) last_bit_set = rest_zero = do_adding = do_rounding = false;
c += AddMantissas(ss2, last_bit_set, rest_zero); rounding_up = (IsSign() == ss2.IsSign());
if( !round || !last_bit_set ) AddCheckExponents(ss2, exp_offset, last_bit_set, rest_zero, do_adding, do_rounding);
do_rounding = false;
if( do_rounding ) if( do_adding )
c += RoundHalfToEven(rest_zero, rounding_up); 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); return CheckCarry(c);
} }
@ -993,6 +1001,8 @@ public:
*/ */
uint BitAnd(Big<exp, man> ss2) uint BitAnd(Big<exp, man> ss2)
{ {
uint c = 0;
if( IsNan() || ss2.IsNan() ) if( IsNan() || ss2.IsNan() )
return CheckCarry(1); return CheckCarry(1);
@ -1011,20 +1021,20 @@ public:
return 0; 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) // abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) ) if( SmallerWithoutSignThan(ss2) )
Swap(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 // the second value is too small
SetZero(); SetZero();
return 0; return 0;
@ -1052,6 +1062,8 @@ public:
*/ */
uint BitOr(Big<exp, man> ss2) uint BitOr(Big<exp, man> ss2)
{ {
uint c = 0;
if( IsNan() || ss2.IsNan() ) if( IsNan() || ss2.IsNan() )
return CheckCarry(1); return CheckCarry(1);
@ -1070,21 +1082,23 @@ public:
if( ss2.IsZero() ) if( ss2.IsZero() )
return 0; 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) // abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) ) if( SmallerWithoutSignThan(ss2) )
Swap(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 // the second value is too small
return 0; return 0;
}
// exp_offset < mantissa_size_in_bits, moving 'exp_offset' times // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times
ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); ss2.mantissa.Rcr( exp_offset.ToInt(), 0 );
@ -1108,6 +1122,8 @@ public:
*/ */
uint BitXor(Big<exp, man> ss2) uint BitXor(Big<exp, man> ss2)
{ {
uint c = 0;
if( IsNan() || ss2.IsNan() ) if( IsNan() || ss2.IsNan() )
return CheckCarry(1); return CheckCarry(1);
@ -1126,21 +1142,23 @@ public:
return 0; 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) // abs(this) will be >= abs(ss2)
if( SmallerWithoutSignThan(ss2) ) if( SmallerWithoutSignThan(ss2) )
Swap(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 // the second value is too small
return 0; return 0;
}
// exp_offset < mantissa_size_in_bits, moving 'exp_offset' times // exp_offset < mantissa_size_in_bits, moving 'exp_offset' times
ss2.mantissa.Rcr( exp_offset.ToInt(), 0 ); ss2.mantissa.Rcr( exp_offset.ToInt(), 0 );