The Reallocate procedures in g-htable.adb and g-dyntab.adb are subject to problems with possible intermediate overflow. This has never been reported to cause problems, but in theory it could cause performance degradation, so it is now fixed. No test, because too much trouble to construct, and we have never had an instance of this reported.
Tested on x86_64-pc-linux-gnu, committed on trunk 2014-05-21 Robert Dewar <de...@adacore.com> * g-table.adb, g-dyntab.adb (Reallocate): Fix possible overflow in computing new table size.
Index: g-table.adb =================================================================== --- g-table.adb (revision 210687) +++ g-table.adb (working copy) @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 1998-2013, AdaCore -- +-- Copyright (C) 1998-2014, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -196,21 +196,25 @@ ---------------- procedure Reallocate is - New_Size : size_t; + New_Size : size_t; + New_Length : Long_Long_Integer; begin if Max < Last_Val then pragma Assert (not Locked); + -- Now increment table length until it is sufficiently large. Use + -- the increment value or 10, which ever is larger (the reason + -- for the use of 10 here is to ensure that the table does really + -- increase in size (which would not be the case for a table of + -- length 10 increased by 3% for instance). Do the intermediate + -- calculation in Long_Long_Integer to avoid overflow. + while Max < Last_Val loop - - -- Increase length using the table increment factor, but make - -- sure that we add at least ten elements (this avoids a loop - -- for silly small increment values) - - Length := Integer'Max - (Length * (100 + Table_Increment) / 100, - Length + 10); + New_Length := + Long_Long_Integer (Length) * + (100 + Long_Long_Integer (Table_Increment)) / 100; + Length := Integer'Max (Integer (New_Length), Length + 10); Max := Min + Length - 1; end loop; end if; Index: g-dyntab.adb =================================================================== --- g-dyntab.adb (revision 210687) +++ g-dyntab.adb (working copy) @@ -6,7 +6,7 @@ -- -- -- B o d y -- -- -- --- Copyright (C) 2000-2013, AdaCore -- +-- Copyright (C) 2000-2014, AdaCore -- -- -- -- GNAT is free software; you can redistribute it and/or modify it under -- -- terms of the GNU General Public License as published by the Free Soft- -- @@ -187,13 +187,24 @@ begin if T.P.Max < T.P.Last_Val then + + -- Now increment table length until it is sufficiently large. Use + -- the increment value or 10, which ever is larger (the reason + -- for the use of 10 here is to ensure that the table does really + -- increase in size (which would not be the case for a table of + -- length 10 increased by 3% for instance). Do the intermediate + -- calculation in Long_Long_Integer to avoid overflow. + while T.P.Max < T.P.Last_Val loop - New_Length := T.P.Length * (100 + Table_Increment) / 100; + New_Length := + Integer + (Long_Long_Integer (T.P.Length) * + (100 + Long_Long_Integer (Table_Increment)) / 100); if New_Length > T.P.Length then T.P.Length := New_Length; else - T.P.Length := T.P.Length + 1; + T.P.Length := T.P.Length + 10; end if; T.P.Max := Min + T.P.Length - 1;