Sanity check on accessibility rules interpretation

This came up when when I was reading the section of RM22 on accessibility levels (3.10.2) and then trying to use GNAT to confirm my understanding. GNAT does not agree with my understanding, however I believe this is a GNAT bug rather than a hole in my understanding or a hole in the RM. I’d appreciate if someone more familiar with the rules in 3.10.2 could check that my reasoning here is correct. @sttaft perhaps as the only ARG member that is active here as far as I know.

Take the below program:

with Ada.Text_IO; use Ada.Text_IO;
with Ada.Containers.Ordered_Maps;

procedure Example is
   type R is record
      X : aliased Integer;
   end record;

   package R_Maps is new Ada.Containers.Ordered_Maps (Positive, R);
   M : R_Maps.Map := [1 => (X => 1)];

   type Integer_Access is access all Integer;
   A : Integer_Access := M (1).X'Access;
   --  An explicit `.Element` also triggers the bug.
begin
   Put_Line (A.all'Image);
   M.Clear;
   Put_Line (A.all'Image);
   M.Insert (1, R'(X => 2));
   Put_Line (A.all'Image);
end Example;

This will show a use-after-free when running with Valgrind. Notably this program is accepted both when using No_Dynamic_Accessibility_Checks and when not using it.

This program should not be accepted by a conforming Ada compiler for the following reasons:

RM22 7.6.1(3/5) states that “… in the case of the execution of a master construct: a body other than a package_body; a statement; or an expression …”

The initialiser for A here is an expression.

RM22 3.10.2(18/5) states that “For a master construct that is statically nested within another master construct, the accessibility level of the inner master construct is statically deeper than that of the outer master construct.”

This means that the accessibility level of initialiser for A is deeper than the declarative region of Example.

RM22 3.10.2(12.5/3) states that “The accessibility level of the anonymous access type of an access discriminant in any other context is that of the enclosing object.”

The enclosing object here is the temporary Reference_Type object created within the initialiser of A, therefore the accessibility level of the temporary Reference_Type object is that of the initialiser of A.

RM22 4.1.5(6/3) states that “A generalized_reference denotes a view equivalent to that of a dereference of the reference discriminant of the reference object.”

RM22 3.10.2(28/3) states in regards to X’Access that “The accessibility level of the view shall not be statically deeper than that of the access type A.”

Therefore the assignment should be invalid.

You do not have an access discriminant or a generalized_reference in your example, so most of what you’re quoting is irrelevant. ARG members have stated publicly that no one understands 3.10.2, so that includes you and me and those who write the ARM and those who write Ada compilers.

Reference_Type (which Reference returns) is defined as a type with an access discriminant by the RM. generalized_reference is present when we do .X without .Element first.

I guess this calls RM A.18.6(16.4/5) Reference, which returns a reference type.
But for you actual question - also I do not know the answer.

Sorry, I meant to reply to this, but evidently never did.

I see that you are referring to the code for the map, while I was referring to your code. You are correct that user-defined indexing uses access discriminants, but since you say

and Element does not involve an access discriminant, I presume that is not the issue.

Element is the name of the access discriminant. I mean M (1).Element.X'Access, not M.Element (1).X'Access. I assume the latter would be correctly rejected.