Gem #33: Accessibility Checks (Part I: Ada95)
by Ramón Fernández —AdaCore
Let's get started…
Ada is a block-structured language, which means the programmer can nest blocks of code inside other blocks. At the end of a block, all objects declared inside of it go out of scope, meaning they no longer exist, so the language disallows pointers to objects in blocks with a deeper nesting level.
In order to prevent dangling references, every entity is associated with a number, called its "accessibility level", according to a Ada's accessibility rules. When certain references are made to an entity of an access type (Ada's parlance for pointer), the accessibility level of the entity is checked against the level allowed by the context so that no dangling pointers can occur.
Consider the following example:
procedure Static_Check is type Global is access all Integer; X : Global; procedure Init is Y : aliased Integer := 0; begin X := Y'Access; -- Illegal! end Init; begin Init; ... end Static_Check;
The assignment is illegal because when the procedure Init finishes, the object Y no longer exists, thus making X a danging pointer. The compiler will detect this situation and flag the error.
The beauty of the accessibility rules is that most of them can be checked and enforced at compile time, just by using statically known accessibility levels.
However, there are cases when it is not possible to statically determine the accessibility level that an entity will have during program execution. In these cases, the compiler will insert a run-time check to raise an exception if a dangling pointer can be created:
procedure Access_Params is type Integer_Access is access all Integer; Data : Integer_Access; procedure Init_Data (Value : access Integer) is begin Data := Integer_Access (Value); -- this conversion performs a dynamic accessibility check end; X : aliased Integer := 1; begin Init_Data (X'Access); -- This is OK declare Y : aliased Integer := 2; begin Init_Data (Y'Access); -- Trouble! end; -- Y no longer exists! Process (Data); end;
In the example above, we cannot know at compile time the accessibility level of the object that will be passed to Init_Data, so the compiler inserts a run-time check to make sure that the assignment 'Data := ...' does not cause a dangling reference -- and to raise an exception if it would.
In summary, when it comes to dangling references, Ada makes it very hard for you to shoot yourself in the foot!