From: Ronan Desplanques <desplanq...@adacore.com>

This patch fixes an integer underflow issue on calls of the form
New_Char_Array (X) with X'Last < X'First - 2. That integer underflow
caused attempts at allocating impossibly large amount of memory in some
cases.

gcc/ada/ChangeLog:

        * libgnat/i-cstrin.adb (Position_Of_Nul): Change specification and
        adjust body accordingly.
        (New_Char_Array): Fix size of allocation.
        (To_Chars_Ptr): Adapt to Position_Of_Nul change.

Tested on x86_64-pc-linux-gnu, committed on master.

---
 gcc/ada/libgnat/i-cstrin.adb | 62 ++++++++++++++++++++----------------
 1 file changed, 35 insertions(+), 27 deletions(-)

diff --git a/gcc/ada/libgnat/i-cstrin.adb b/gcc/ada/libgnat/i-cstrin.adb
index 7bf881f8716..6d329254aff 100644
--- a/gcc/ada/libgnat/i-cstrin.adb
+++ b/gcc/ada/libgnat/i-cstrin.adb
@@ -66,8 +66,11 @@ is
    pragma Inline ("+");
    --  Address arithmetic on chars_ptr value
 
-   function Position_Of_Nul (Into : char_array) return size_t;
-   --  Returns position of the first Nul in Into or Into'Last + 1 if none
+   procedure Position_Of_Nul
+     (Into : char_array; Found : out Boolean; Index : out size_t);
+   --  If into contains a Nul character, Found is set to True and Index
+   --  contains the position of the first Nul character in Into. Otherwise
+   --  Found is set to False and the value of Index is not meaningful.
 
    --  We can't use directly System.Memory because the categorization is not
    --  compatible, so we directly import here the malloc and free routines.
@@ -107,6 +110,7 @@ is
    --------------------
 
    function New_Char_Array (Chars : char_array) return chars_ptr is
+      Found   : Boolean;
       Index   : size_t;
       Pointer : chars_ptr;
 
@@ -114,24 +118,25 @@ is
       --  Get index of position of null. If Index > Chars'Last,
       --  nul is absent and must be added explicitly.
 
-      Index := Position_Of_Nul (Into => Chars);
-      Pointer := Memory_Alloc ((Index - Chars'First + 1));
+      Position_Of_Nul (Into => Chars, Found => Found, Index => Index);
 
       --  If nul is present, transfer string up to and including nul
 
-      if Index <= Chars'Last then
-         Update (Item   => Pointer,
-                 Offset => 0,
-                 Chars  => Chars (Chars'First .. Index),
-                 Check  => False);
+      if Found then
+         Pointer := Memory_Alloc (Index - Chars'First + 1);
+
+         Update
+           (Item   => Pointer,
+            Offset => 0,
+            Chars  => Chars (Chars'First .. Index),
+            Check  => False);
       else
          --  If original string has no nul, transfer whole string and add
          --  terminator explicitly.
 
-         Update (Item   => Pointer,
-                 Offset => 0,
-                 Chars  => Chars,
-                 Check  => False);
+         Pointer := Memory_Alloc (Chars'Length + 1);
+
+         Update (Item => Pointer, Offset => 0, Chars => Chars, Check => False);
          Poke (nul, Into => Pointer + size_t'(Chars'Length));
       end if;
 
@@ -187,19 +192,19 @@ is
    -- Position_Of_Nul --
    ---------------------
 
-   function Position_Of_Nul (Into : char_array) return size_t is
+   procedure Position_Of_Nul
+     (Into : char_array; Found : out Boolean; Index : out size_t) is
    begin
-      pragma Annotate (Gnatcheck, Exempt_On, "Improper_Returns",
-                       "early returns for performance");
+      Found := False;
+      Index := 0;
+
       for J in Into'Range loop
          if Into (J) = nul then
-            return J;
+            Found := True;
+            Index := J;
+            return;
          end if;
       end loop;
-
-      return Into'Last + 1;
-
-      pragma Annotate (Gnatcheck, Exempt_Off, "Improper_Returns");
    end Position_Of_Nul;
 
    ------------
@@ -231,19 +236,22 @@ is
      (Item      : char_array_access;
       Nul_Check : Boolean := False) return chars_ptr
    is
+      Found : Boolean;
+      Index : size_t;
    begin
       pragma Annotate (Gnatcheck, Exempt_On, "Improper_Returns",
                        "early returns for performance");
       if Item = null then
          return Null_Ptr;
-      elsif Nul_Check
-        and then Position_Of_Nul (Into => Item.all) > Item'Last
-      then
-         raise Terminator_Error;
-      else
-         return To_chars_ptr (Item (Item'First)'Address);
+      elsif Nul_Check then
+         Position_Of_Nul (Item.all, Found, Index);
+         if not Found then
+            raise Terminator_Error;
+         end if;
       end if;
 
+      return To_chars_ptr (Item (Item'First)'Address);
+
       pragma Annotate (Gnatcheck, Exempt_Off, "Improper_Returns");
    end To_Chars_Ptr;
 
-- 
2.43.0

Reply via email to