Commit bd5ed03a by Javier Miranda Committed by Pierre-Marie de Rodat

[Ada] Buffer reading overflow in dispatch table initialization

For tagged types not defined at library level that derive from library
level tagged types the compiler may generate code to initialize their
dispatch table of predefined primitives copying from the parent type
data stored in memory after the dispatch table of the parent; that is,
at runtime the initialization of dispatch tables overflows reading the
parent dispatch table.

This problem does not affect the execution of the program since the
target dispatch table always has enough space to store the extra data,
and after such copy the compiler generates code to complete the
initialization of the dispatch table.

The following test must compile and execute without errors.

package pkg_a is
   type Root is tagged null record;
end pkg_a;

with pkg_a;
procedure main is
   type Derived is new pkg_a.Root with null record;  -- Test
begin
   null;
end main;

Command: gnatmake -q main -fsanitize=address; ./main

2019-08-19  Javier Miranda  <miranda@adacore.com>

gcc/ada/

	PR ada/65696
	* exp_atag.ads, exp_atag.adb (Build_Inherit_Predefined_Prims):
	Adding formal to specify how many predefined primitives are
	inherited from the parent type.
	* exp_disp.adb (Number_Of_Predefined_Prims): New subprogram.
	(Make_Secondary_DT): Compute the number of predefined primitives
	of all tagged types (including tagged types not defined at
	library level).  Previously we unconditionally relied on the
	Max_Predef_Prims constant value when building the dispatch
	tables of tagged types not defined at library level (thus
	consuming more memory for their dispatch tables than required).
	(Make_DT): Compute the number of predefined primitives that must
	be inherited from their parent type when building the dispatch
	tables of tagged types not defined at library level. Previously
	we unconditionally relied on the Max_Predef_Prims constant value
	when building the dispatch tables of tagged types not defined at
	library level (thus copying more data than required from the
	parent type).

From-SVN: r274654
parent d403cfad
2019-08-19 Javier Miranda <miranda@adacore.com>
PR ada/65696
* exp_atag.ads, exp_atag.adb (Build_Inherit_Predefined_Prims):
Adding formal to specify how many predefined primitives are
inherited from the parent type.
* exp_disp.adb (Number_Of_Predefined_Prims): New subprogram.
(Make_Secondary_DT): Compute the number of predefined primitives
of all tagged types (including tagged types not defined at
library level). Previously we unconditionally relied on the
Max_Predef_Prims constant value when building the dispatch
tables of tagged types not defined at library level (thus
consuming more memory for their dispatch tables than required).
(Make_DT): Compute the number of predefined primitives that must
be inherited from their parent type when building the dispatch
tables of tagged types not defined at library level. Previously
we unconditionally relied on the Max_Predef_Prims constant value
when building the dispatch tables of tagged types not defined at
library level (thus copying more data than required from the
parent type).
2019-08-19 Bob Duff <duff@adacore.com> 2019-08-19 Bob Duff <duff@adacore.com>
* sem_ch13.adb (Record_Hole_Check): Procedure to check for holes * sem_ch13.adb (Record_Hole_Check): Procedure to check for holes
......
...@@ -744,7 +744,8 @@ package body Exp_Atag is ...@@ -744,7 +744,8 @@ package body Exp_Atag is
function Build_Inherit_Predefined_Prims function Build_Inherit_Predefined_Prims
(Loc : Source_Ptr; (Loc : Source_Ptr;
Old_Tag_Node : Node_Id; Old_Tag_Node : Node_Id;
New_Tag_Node : Node_Id) return Node_Id New_Tag_Node : Node_Id;
Num_Predef_Prims : Int) return Node_Id
is is
begin begin
return return
...@@ -759,7 +760,7 @@ package body Exp_Atag is ...@@ -759,7 +760,7 @@ package body Exp_Atag is
New_Tag_Node)))), New_Tag_Node)))),
Discrete_Range => Make_Range (Loc, Discrete_Range => Make_Range (Loc,
Make_Integer_Literal (Loc, Uint_1), Make_Integer_Literal (Loc, Uint_1),
New_Occurrence_Of (RTE (RE_Max_Predef_Prims), Loc))), Make_Integer_Literal (Loc, Num_Predef_Prims))),
Expression => Expression =>
Make_Slice (Loc, Make_Slice (Loc,
...@@ -772,7 +773,7 @@ package body Exp_Atag is ...@@ -772,7 +773,7 @@ package body Exp_Atag is
Discrete_Range => Discrete_Range =>
Make_Range (Loc, Make_Range (Loc,
Make_Integer_Literal (Loc, 1), Make_Integer_Literal (Loc, 1),
New_Occurrence_Of (RTE (RE_Max_Predef_Prims), Loc)))); Make_Integer_Literal (Loc, Num_Predef_Prims))));
end Build_Inherit_Predefined_Prims; end Build_Inherit_Predefined_Prims;
------------------------- -------------------------
......
...@@ -111,7 +111,8 @@ package Exp_Atag is ...@@ -111,7 +111,8 @@ package Exp_Atag is
function Build_Inherit_Predefined_Prims function Build_Inherit_Predefined_Prims
(Loc : Source_Ptr; (Loc : Source_Ptr;
Old_Tag_Node : Node_Id; Old_Tag_Node : Node_Id;
New_Tag_Node : Node_Id) return Node_Id; New_Tag_Node : Node_Id;
Num_Predef_Prims : Int) return Node_Id;
-- Build code that inherits the predefined primitives of the parent. -- Build code that inherits the predefined primitives of the parent.
-- --
-- Generates: Predefined_DT (New_T).D (All_Predefined_Prims) := -- Generates: Predefined_DT (New_T).D (All_Predefined_Prims) :=
......
...@@ -3817,6 +3817,9 @@ package body Exp_Disp is ...@@ -3817,6 +3817,9 @@ package body Exp_Disp is
-- this secondary dispatch table by Make_Tags when its unique external -- this secondary dispatch table by Make_Tags when its unique external
-- name was generated. -- name was generated.
function Number_Of_Predefined_Prims (Typ : Entity_Id) return Nat;
-- Returns the number of predefined primitives of Typ
------------------------------ ------------------------------
-- Check_Premature_Freezing -- -- Check_Premature_Freezing --
------------------------------ ------------------------------
...@@ -3970,12 +3973,10 @@ package body Exp_Disp is ...@@ -3970,12 +3973,10 @@ package body Exp_Disp is
DT_Constr_List : List_Id; DT_Constr_List : List_Id;
DT_Aggr_List : List_Id; DT_Aggr_List : List_Id;
Empty_DT : Boolean := False; Empty_DT : Boolean := False;
Nb_Predef_Prims : Nat := 0;
Nb_Prim : Nat; Nb_Prim : Nat;
New_Node : Node_Id; New_Node : Node_Id;
OSD : Entity_Id; OSD : Entity_Id;
OSD_Aggr_List : List_Id; OSD_Aggr_List : List_Id;
Pos : Nat;
Prim : Entity_Id; Prim : Entity_Id;
Prim_Elmt : Elmt_Id; Prim_Elmt : Elmt_Id;
Prim_Ops_Aggr_List : List_Id; Prim_Ops_Aggr_List : List_Id;
...@@ -4022,38 +4023,12 @@ package body Exp_Disp is ...@@ -4022,38 +4023,12 @@ package body Exp_Disp is
-- predef-prim-op-thunk-n'address); -- predef-prim-op-thunk-n'address);
-- for Predef_Prims'Alignment use Address'Alignment -- for Predef_Prims'Alignment use Address'Alignment
-- Stage 1: Calculate the number of predefined primitives -- Create the thunks associated with the predefined primitives and
-- save their entity to fill the aggregate.
if not Building_Static_DT (Typ) then
Nb_Predef_Prims := Max_Predef_Prims;
else
Prim_Elmt := First_Elmt (Primitive_Operations (Typ));
while Present (Prim_Elmt) loop
Prim := Node (Prim_Elmt);
if Is_Predefined_Dispatching_Operation (Prim)
and then not Is_Abstract_Subprogram (Prim)
then
Pos := UI_To_Int (DT_Position (Prim));
if Pos > Nb_Predef_Prims then
Nb_Predef_Prims := Pos;
end if;
end if;
Next_Elmt (Prim_Elmt);
end loop;
end if;
if Generate_SCIL then
Nb_Predef_Prims := 0;
end if;
-- Stage 2: Create the thunks associated with the predefined
-- primitives and save their entity to fill the aggregate.
declare declare
Prim_Table : array (Nat range 1 .. Nb_Predef_Prims) of Entity_Id; Nb_P_Prims : constant Nat := Number_Of_Predefined_Prims (Typ);
Prim_Table : array (Nat range 1 .. Nb_P_Prims) of Entity_Id;
Decl : Node_Id; Decl : Node_Id;
Thunk_Id : Entity_Id; Thunk_Id : Entity_Id;
Thunk_Code : Node_Id; Thunk_Code : Node_Id;
...@@ -4525,6 +4500,44 @@ package body Exp_Disp is ...@@ -4525,6 +4500,44 @@ package body Exp_Disp is
Append_Elmt (Iface_DT, DT_Decl); Append_Elmt (Iface_DT, DT_Decl);
end Make_Secondary_DT; end Make_Secondary_DT;
--------------------------------
-- Number_Of_Predefined_Prims --
--------------------------------
function Number_Of_Predefined_Prims (Typ : Entity_Id) return Nat is
Nb_Predef_Prims : Nat := 0;
begin
if not Generate_SCIL then
declare
Prim : Entity_Id;
Prim_Elmt : Elmt_Id;
Pos : Nat;
begin
Prim_Elmt := First_Elmt (Primitive_Operations (Typ));
while Present (Prim_Elmt) loop
Prim := Node (Prim_Elmt);
if Is_Predefined_Dispatching_Operation (Prim)
and then not Is_Abstract_Subprogram (Prim)
then
Pos := UI_To_Int (DT_Position (Prim));
if Pos > Nb_Predef_Prims then
Nb_Predef_Prims := Pos;
end if;
end if;
Next_Elmt (Prim_Elmt);
end loop;
end;
end if;
pragma Assert (Nb_Predef_Prims <= Max_Predef_Prims);
return Nb_Predef_Prims;
end Number_Of_Predefined_Prims;
-- Local variables -- Local variables
Elab_Code : constant List_Id := New_List; Elab_Code : constant List_Id := New_List;
...@@ -4584,7 +4597,6 @@ package body Exp_Disp is ...@@ -4584,7 +4597,6 @@ package body Exp_Disp is
I_Depth : Nat := 0; I_Depth : Nat := 0;
Iface_Table_Node : Node_Id; Iface_Table_Node : Node_Id;
Name_ITable : Name_Id; Name_ITable : Name_Id;
Nb_Predef_Prims : Nat := 0;
Nb_Prim : Nat := 0; Nb_Prim : Nat := 0;
New_Node : Node_Id; New_Node : Node_Id;
Num_Ifaces : Nat := 0; Num_Ifaces : Nat := 0;
...@@ -5924,40 +5936,13 @@ package body Exp_Disp is ...@@ -5924,40 +5936,13 @@ package body Exp_Disp is
else else
declare declare
Pos : Nat; Nb_P_Prims : constant Nat := Number_Of_Predefined_Prims (Typ);
Prim_Table : array (Nat range 1 .. Nb_P_Prims) of Entity_Id;
begin
if not Building_Static_DT (Typ) then
Nb_Predef_Prims := Max_Predef_Prims;
else
Prim_Elmt := First_Elmt (Primitive_Operations (Typ));
while Present (Prim_Elmt) loop
Prim := Node (Prim_Elmt);
if Is_Predefined_Dispatching_Operation (Prim)
and then not Is_Abstract_Subprogram (Prim)
then
Pos := UI_To_Int (DT_Position (Prim));
if Pos > Nb_Predef_Prims then
Nb_Predef_Prims := Pos;
end if;
end if;
Next_Elmt (Prim_Elmt);
end loop;
end if;
declare
Prim_Table : array
(Nat range 1 .. Nb_Predef_Prims) of Entity_Id;
Decl : Node_Id; Decl : Node_Id;
E : Entity_Id; E : Entity_Id;
begin begin
Prim_Ops_Aggr_List := New_List; Prim_Ops_Aggr_List := New_List;
Prim_Table := (others => Empty); Prim_Table := (others => Empty);
if Building_Static_DT (Typ) then if Building_Static_DT (Typ) then
...@@ -5968,6 +5953,7 @@ package body Exp_Disp is ...@@ -5968,6 +5953,7 @@ package body Exp_Disp is
if Is_Predefined_Dispatching_Operation (Prim) if Is_Predefined_Dispatching_Operation (Prim)
and then not Is_Abstract_Subprogram (Prim) and then not Is_Abstract_Subprogram (Prim)
and then not Is_Eliminated (Prim) and then not Is_Eliminated (Prim)
and then not Generate_SCIL
and then not Present (Prim_Table and then not Present (Prim_Table
(UI_To_Int (DT_Position (Prim)))) (UI_To_Int (DT_Position (Prim))))
then then
...@@ -6030,7 +6016,6 @@ package body Exp_Disp is ...@@ -6030,7 +6016,6 @@ package body Exp_Disp is
New_Occurrence_Of (RTE (RE_Integer_Address), Loc), New_Occurrence_Of (RTE (RE_Integer_Address), Loc),
Attribute_Name => Name_Alignment))); Attribute_Name => Name_Alignment)));
end; end;
end;
-- Stage 1: Initialize the discriminant and the record components -- Stage 1: Initialize the discriminant and the record components
...@@ -6301,7 +6286,9 @@ package body Exp_Disp is ...@@ -6301,7 +6286,9 @@ package body Exp_Disp is
(Node (Node
(Next_Elmt (Next_Elmt
(First_Elmt (First_Elmt
(Access_Disp_Table (Typ)))), Loc))); (Access_Disp_Table (Typ)))), Loc),
Num_Predef_Prims =>
Number_Of_Predefined_Prims (Parent_Typ)));
if Nb_Prims /= 0 then if Nb_Prims /= 0 then
Append_To (Elab_Code, Append_To (Elab_Code,
...@@ -6390,7 +6377,10 @@ package body Exp_Disp is ...@@ -6390,7 +6377,10 @@ package body Exp_Disp is
Unchecked_Convert_To (RTE (RE_Tag), Unchecked_Convert_To (RTE (RE_Tag),
New_Occurrence_Of New_Occurrence_Of
(Node (Next_Elmt (Sec_DT_Typ)), (Node (Next_Elmt (Sec_DT_Typ)),
Loc)))); Loc)),
Num_Predef_Prims =>
Number_Of_Predefined_Prims
(Parent_Typ)));
if Num_Prims /= 0 then if Num_Prims /= 0 then
Append_To (Elab_Code, Append_To (Elab_Code,
...@@ -6436,7 +6426,10 @@ package body Exp_Disp is ...@@ -6436,7 +6426,10 @@ package body Exp_Disp is
Unchecked_Convert_To (RTE (RE_Tag), Unchecked_Convert_To (RTE (RE_Tag),
New_Occurrence_Of New_Occurrence_Of
(Node (Next_Elmt (Sec_DT_Typ)), (Node (Next_Elmt (Sec_DT_Typ)),
Loc)))); Loc)),
Num_Predef_Prims =>
Number_Of_Predefined_Prims
(Parent_Typ)));
if Num_Prims /= 0 then if Num_Prims /= 0 then
Append_To (Elab_Code, Append_To (Elab_Code,
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment