From dcdb1db9ec79e4b7de00ec19fce2a2518535ba57 Mon Sep 17 00:00:00 2001 From: Tomasz Sowa Date: Thu, 11 Apr 2019 16:14:04 +0000 Subject: [PATCH] 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 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 --- ttmath/ttmathbig.h | 106 ++++++++++++++++++++++++++------------------- 1 file changed, 62 insertions(+), 44 deletions(-) diff --git a/ttmath/ttmathbig.h b/ttmath/ttmathbig.h index 1425c71..7c006bc 100644 --- a/ttmath/ttmathbig.h +++ b/ttmath/ttmathbig.h @@ -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 ss2, bool round = true, bool adding = true) { bool last_bit_set, rest_zero, do_adding, do_rounding, rounding_up; - Int 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_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 ss2) { + uint c = 0; + if( IsNan() || ss2.IsNan() ) return CheckCarry(1); @@ -1011,20 +1021,20 @@ public: return 0; } - Int exp_offset( exponent ); - Int 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_offset( exponent ); + Int 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 ss2) { + uint c = 0; + if( IsNan() || ss2.IsNan() ) return CheckCarry(1); @@ -1070,21 +1082,23 @@ public: if( ss2.IsZero() ) return 0; - Int exp_offset( exponent ); - Int 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_offset( exponent ); + Int 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 ss2) { + uint c = 0; + if( IsNan() || ss2.IsNan() ) return CheckCarry(1); @@ -1126,21 +1142,23 @@ public: return 0; } - Int exp_offset( exponent ); - Int 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_offset( exponent ); + Int 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 );