[Ada] Avoid overflow in Write_Int

Arnaud Charlet charlet@adacore.com
Tue Oct 20 09:48:00 GMT 2015


This patch avoids an overflow on the most-negative number in Output.Write_Int.
No simple test available.

Tested on x86_64-pc-linux-gnu, committed on trunk

2015-10-20  Bob Duff  <duff@adacore.com>

	* output.adb (Write_Int): Work with negative numbers in order to avoid
	negating Int'First and thereby causing overflow.

-------------- next part --------------
Index: output.adb
===================================================================
--- output.adb	(revision 229023)
+++ output.adb	(working copy)
@@ -6,7 +6,7 @@
 --                                                                          --
 --                                 B o d y                                  --
 --                                                                          --
---          Copyright (C) 1992-2013, Free Software Foundation, Inc.         --
+--          Copyright (C) 1992-2015, Free Software Foundation, Inc.         --
 --                                                                          --
 -- 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- --
@@ -350,6 +350,7 @@
 
    procedure Write_Char (C : Character) is
    begin
+      pragma Assert (Next_Col in Buffer'Range);
       if Next_Col = Buffer'Length then
          Write_Eol;
       end if;
@@ -406,17 +407,29 @@
    ---------------
 
    procedure Write_Int (Val : Int) is
+      --  Type Int has one extra negative number (i.e. two's complement), so we
+      --  work with negative numbers here. Otherwise, negating Int'First will
+      --  overflow.
+
+      subtype Nonpositive is Int range Int'First .. 0;
+      procedure Write_Abs (Val : Nonpositive);
+      --  Write out the absolute value of Val
+
+      procedure Write_Abs (Val : Nonpositive) is
+      begin
+         if Val < -9 then
+            Write_Abs (Val / 10); -- Recursively write higher digits
+         end if;
+
+         Write_Char (Character'Val (-(Val rem 10) + Character'Pos ('0')));
+      end Write_Abs;
+
    begin
       if Val < 0 then
          Write_Char ('-');
-         Write_Int (-Val);
-
+         Write_Abs (Val);
       else
-         if Val > 9 then
-            Write_Int (Val / 10);
-         end if;
-
-         Write_Char (Character'Val ((Val mod 10) + Character'Pos ('0')));
+         Write_Abs (-Val);
       end if;
    end Write_Int;
 


More information about the Gcc-patches mailing list