non-local pointer cannot point to local object - ada

Why does the following behaves like it behaves:
with Interfaces.C;
with Interfaces.C.Strings;
procedure X is
type Integer_Access is access all Integer;
Arr_Access : Interfaces.C.Strings.char_array_access;
Arr : aliased Interfaces.C.char_array := Interfaces.C.To_C ("From");
A : Integer_Access;
I : aliased Integer := 6;
begin
Arr_Access := Arr’Access; -- not OK
A := I’Access; -- OK
end X;
Result:
$ gnatmake x.adb
gcc -c x.adb
x.adb:16:18: non-local pointer cannot point to local object
gnatmake: "x.adb" compilation error
Doesn't Arr and Arr_Access have the same accessibility level?

The accessibility rules are designed (ARM 3.10.2(3))
[to] ensure[s] that the object will live at least as long as the access type, which in turn ensures that the access value cannot later designate an object that no longer exists.
In your case, the access type is declared at library level, but the object being accessed is local; so it would be possible for the access value to outlive Arr_Access (by being passed to a subprogram that stores it, for instance).
The ARM follows this with the statement that you can use ’Unchecked_Access.

Related

Ada complaining that I've added a volatile object in a function call to generic type when not volatile

So I've got the following declaration:
record
String1 : String (1 .. 64);
String2 : String (1 .. 64);
Timestamp : Time;
Int1 : Long_Long_Integer;
String3 : Unbounded_String;
end record;
And it's used in
package My_Vectors is new Vectors (Index_Type => Positive, Element_Type => Object);
which yields the compilation error:
volatile object cannot act as actual in a call (SPARK RM 7.1.3(10))
Now, Clock is volatile which is used. However I've removed the call to Clock and I still get the same result.
Also, I've tried replacing the Object type with a type of Integer and I don't have any complaints from the Ada compiler. Could someone explain this as I can't see how this is putting a volatile object into an actual anywhere please.
Just tried using the following record and I get the same result:
type My_Record is
record
A: Integer;
B: Integer;
C: String(1 .. 64);
end record;
The standard Ada containers are not supported in SPARK (see SPARK RM 14.8).
Use the SPARK compatible container Ada.Containers.Formal_Vectors instead (see also here and here).
Regarding the compiler error: the current implementation of Ada.Containers.Vector uses atomic operations to improve performance (see here and here). These atomic operations operate (in this case) on variables of type System.Atomic_Counters.Atomic_Unsigned (see here). This type is declared as Atomic and therefore volatile (see RM 8(3)).

Memory allocation with storage manager leads to not pure function (RM 13.1(22))

Porting some old code to a newer CentOs Linux machine.
I am using linux gnat with a couple of flags:
Default_Switches ("ada") use ("-fstack-check", "-g", "-gnatVr", "-gnato", "-gnatE", "-gnatwmuv", "-gnata", "-m32");
and I have the gnat version:
gcc-gnat.i686 4.8.5-11.el7
So these are the preconditions.
I have now an for sure working self-written storage manager which is called by
St_Wa.Alloc(StoragePool, BitSize)
So now to my problem and to be honest I do not really get the point why the compiler is failing, so I would be really grateful for a detailed explanation why it is not working!
function AllocMem(StoragePool : in St_Wa.Mem_Pool_Type;
Option: in Option_Type)
return Option_Ref is
subtype New_Type is Option_Type (Option.Kind);
New_Option : New_Type;
for New_Option use at St_Wa.Alloc( StoragePool => StoragePool,
BitSize => New_Type'Size)
begin
Bl_Bl.Move( ... sth happens here ... )
return Pointer(New_Option'Address);
end AllocMem;
Whereas:
type Option_Type ( Kind : Option_Kind_Type := Marker) is
record
Next : Option_Ref;
case Kind is
when First_Procedure => First_Procedure : First_Procedure_Type;
when Sec_Procedure => Sec_Procedure : Sec_Procedure_Type;
end case;
end record;
And I get the following Error:
invalid address clause for initialized object "New_Option"
function "Alloc" is not pure (RM 13.1 (22))
Do I get this error because I have a switch case in the type with conditions and therefore the size is only determined depending on kind? How can I avoid this without rewriting everything?
Do I get this error because I have a switch case in the type with conditions and therefore the size is only determined depending on kind?
No. The paragraph referenced by the error message (RM 13.1 (22)) in the LRM reads:
An implementation need not support representation items containing nonstatic expressions, except that an implementation should support a representation item for a given entity if each nonstatic expression in the representation item is a name that statically denotes a constant declared before the entity.
Now, the representation item here is the call to Alloc since your code:
for New_Option use at St_Wa.Alloc(StoragePool => StoragePool,
BitSize => New_Type'Size);
is Ada83-style for
for New_Option'Address use St_Wa.Alloc(StoragePool => StoragePool,
BitSize => New_Type'Size);
And since Alloc (...) is a function call, it is not a static expression, since static functions are, according to RM 4.9:
a predefined operator whose parameter and result types are all scalar types none of which are descendants of formal scalar types;
a predefined concatenation operator whose result type is a string type;
an enumeration literal;
a language-defined attribute that is a function, if the prefix denotes a static scalar subtype, and if the parameter and result types are scalar.
Since Alloc is none of the above, as RM 13.1 states, the implementation does not need to support it in the representation item. However, the actual error message tells us that "Alloc" is not pure, so GNAT tells it it would support this if Alloc was pure.
So one way to fix this would be to make Alloc pure, which means: Add pragma Pure; to the package St_Wa, which contains Alloc. Whether this is possible depends on the package and it might require additional changes.
If this is not feasible, RM 13.1 (22) hints at another way: A nonstatic expression should be supported if it denotes a constant declared before the entity. Thus, this should work:
My_Address : constant System.Address :=
St_Wa.Alloc(StoragePool => StoragePool, BitSize => New_Type'Size);
New_Option : New_Type;
for New_Option use at My_Address;

Inconsistent argument passing mode

Consider the following code (which compile with GCC 4.7.4):
procedure Main is
procedure Sub_Proc(N : in out Integer) is
M : Integer;
begin
M := N;
end;
procedure Proc(N : out Integer) is
begin
Sub_Proc(N);
end;
N : Integer;
begin
Proc(N);
end Main;
The procedure Proc is supposed to ensure that the argument N which is an out argument will never be read inside his body. But it passes this argument to a procedure Sub_Proc which takes an in out argument, so potentially the previous argument will be read inside this procedure whereas the calling procedure ensured the opposite.
Is it a GCC bug or an Ada standard specificity ?
You’ll have received a warning on the Sub_Proc(N); call: "N" may be referenced before it has a value. So the compiler was trying to help!
In Ada 83, your program would have been illegal: 6.4.1(3) says "for the mode in out, the variable must not be a formal parameter of mode out”. Indeed, using -gnat83, and after a minor rearrangement of the code to allow it to compile, the equivalent to the above warning is the error (Ada 83) illegal reading of out parameter.
In Ada 95 and Ada 2012 it is OK to read the value of an out parameter after it has been assigned; in ARM95 6.4.1(15) we find that the value starts out uninitialized (as indicated by the warning message noted above), so using it is a Bad Idea.
So the answer is, GNAT’s behaviour conforms with the standard.

LOC() for user defined types gives different results depending on the context

I'm trying to debug some code in which members of a user defined object mysteriously change addresses, and while doing that I realized user defined objects do that as well. Here's a small example of querying object address from function that created it and then from its member function:
module foo_module
type foo_type
contains
procedure :: foo
end type foo_type
contains
subroutine foo(this)
class(foo_type) :: this
print *, 'Inside foo this is', loc(this)
end subroutine foo
end module foo_module
program trial
use foo_module
type(foo_type) :: object
print *, 'Object address', loc(object)
call object%foo()
end program trial
A sample output I get is:
Object address 4452052800
Inside foo this is 140734643354880
Why am I getting two different addresses for the same object? Am I doing something wrong? Or is there something with LOC that comes into play I don't understand?
I'm using ifort under osx.
LOC is an extension. Its behaviour is as specified by the compiler vendor.
What the behaviour intended by the vendor here isn't clear, but the difference that you are seeing is that in the main program you get the integer equivalent of the memory address of the non-polymorphic object (what you probably expect), while in the subroutine you get the integer equivalent of the memory address of the polymorphic descriptor for the object (maybe what you want, maybe not).
Using TRANSFER(C_LOC(xxx), 0_C_INTPTR_T) is a more portable way of getting the integer representation of the address of an object (where the C_* things are from the ISO_C_BINDING intrinsic module). C_LOC requires that its argument have the TARGET attribute and be non-polymorphic (use SELECT TYPE).
I'd recommend asking on the relevant Intel Forum if you want further clarification on the intended behaviour of the LOC extension.
I reported the bug to the developers our internal issue ID is DPD200253159. I found that the C_LOC function from ISO_C_BINDING works. For example:
subroutine foo(this)
use, intrinsic :: iso_c_binding
class(foo_type) :: this
print *, 'Inside foo this is', transfer(c_loc(this),0_C_INTPTR_T)
end subroutine foo

The use of IN OUT in Ada

Given below is some code in ada
with TYPE_VECT_B; use TYPE_VECT_B;
Package TEST01 is
procedure TEST01
( In_State : IN VECT_B ;
Out_State : IN OUT VECT_B );
function TEST02
( In_State : IN VECT_B ) return Boolean ;
end TEST01;
The TYPE_VECT_B package specification and body is also defined below
Package TYPE_VECT_B is
type VECT_B is array (INTEGER range <>) OF BOOLEAN ;
rounded_data : float ;
count : integer ;
trace : integer ;
end TYPE_VECT_B;
Package BODY TYPE_VECT_B is
begin
null;
end TYPE_VECT_B;
What does the variable In_State and Out_State actually mean? I think In_State means input variable. I just get confused to what actually Out_State means?
An in parameter can be read but not written by the subprogram. in is the default. Prior to Ada 2012, functions were only allowed to have in parameters. The actual parameter is an expression.
An out parameter implies that the previous value is of no interest. The subprogram is expected to write to the parameter. After writing to the parameter, the subprogram can read back what it has written. On exit the actual parameter receives the value written to it (there are complications in this area!). The actual parameter must be a variable.
An in out parameter is like an out parameter except that the previous value is of interest and can be read by the subprogram before assignment. For example,
procedure Add (V : Integer; To : in out Integer; Limited_To : Integer)
is
begin
-- Check that the result wont be too large. This involves reading
-- the initial value of the 'in out' parameter To, which would be
-- wrong if To was a mere 'out' parameter (it would be
-- uninitialized).
if To + V > Limited_To then
To := Limited_To;
else
To := To + V;
end if;
end Add;
Basically, every parameter to a function or procedure has a direction to it. The options are in, out, in out (both), or access. If you don't see one of those, then it defaults to in.
in means data can go into the subroutine from the caller (via the parameter). You are allowed to read from in parameters inside the routine. out means data can come out of the routine that way, and thus you are allowed to assign values to the parameter inside the routine. In general, how the compiler accomplishes the data passing is up to the compiler, which is in accord with Ada's general philosophy of allowing you to specify what you want done, not how you want it done.
access is a special case, and is roughly like putting a "*" in your parameter definition in Cish languages.
The next question folks usually have is "if I pass something large as an in parameter, is it going to push all that data on the stack or something?" The answer is "no", unless your compiler writers are unconsionably stupid. Every Ada compiler I know of under the hood passes objects larger than fit in a machine register by reference. It is the compiler, not the details of your parameter passing mechanisim, that enforces not writing data back out of the routine. Again, you tell Ada what you want done, it figures out the most efficient way to do it.

Resources