I need help some help with Ada SPARK.
I would like to save a string like "1" into an integer variable. Background: I would like to read numbers from the command line input and process them as integers and check the program with SPARK Prove.
Here's a minimal example:
with Ada.Strings.Unbounded; use Ada.Strings.Unbounded;
procedure Main is
pragma SPARK_Mode;
test_string : Unbounded_String;
identifier : Integer;
begin
test_string := To_Unbounded_String("1");
identifier := Integer'Value(To_String(test_string));
end Main;
When I execute SPARK Prove I get the following message: "medium: precondition might fail". I already implemented a function which checks whether the test_string consists of characters from 0 - 9, but it didn't solved the issue.
Does anyone has a solution how to fix the problem?
I do not have a definitive answer, but my initial observation is as follows.
The SPARK manuals are a little bit vague on how 'Value is interpreted and what this precondition on the attribute looks like. The SPARK RM 15.2.1 states that the 'Value attribute has an implicit precondition:
Attribute
Allowed in SPARK
Comment
S’Value
Yes
Implicit precondition (Ada RM 3.5(55/3))
What "implicit precondition" means is not explained, but a reference is is given to RM 3.5 (55/3) which in turn points to RM 3.5 (39.12/3). The latter states that:
[...] and if the corresponding numeric value belongs to the base range of the type of S, then that value is the result; otherwise, Constraint_Error is raised. [...].
So, the precondition will likely have to prevent the possible occurrence of a Constraint_Error. But how?
Reading on in the GNATprove developer's guide, section scalar attributes, one can read the following:
Scalar Attributes
Image and Value, they are not interpreted currently: [...]
The term "interpreted" is not defined explicitly (from what I could find), but probably indicates that GNATprove will (at this point in time) just not "reason" about the usage of the 'Value attribute. This seems consistent with the fact that even the simplest usage of the attribute, the conversion of a static string like "1", cannot be proven.
So, based on this, my hypothesis is that, with the current state of SPARK, you simply cannot satisfy the precondition. SPARK allows the usage of the 'Value attribute and will add an "implicit" precondition to ensure that the prover will always fail unless someone had a good look at it, reviewed the code, and signed off the attribute's usage (see also SPARK User's Guide, section 7.3.4.1 on justification annotations):
main.adb
procedure Main with SPARK_Mode is
X : Integer;
begin
X := Integer'Value("1");
pragma Annotate
(GNATprove, False_Positive,
"precondition might fail", "reviewed by DeeDee");
end Main;
output (gnatprove)
$ gnatprove -Pdefault.gpr -j0 -u main.adb --report=all
Phase 1 of 2: generation of Global contracts ...
Phase 2 of 2: flow analysis and proof ...
Summary logged in [...]/obj/gnatprove/gnatprove.out
$ cat ./obj/gnatprove/gnatprove.out
Summary of SPARK analysis
=========================
-----------------------------------------------------------------------------------------
SPARK Analysis results Total Flow CodePeer Provers Justified Unproved
-----------------------------------------------------------------------------------------
Data Dependencies . . . . . .
Flow Dependencies . . . . . .
Initialization . . . . . .
Non-Aliasing . . . . . .
Run-time Checks . . . . . .
Assertions . . . . . .
Functional Contracts 1 . . . 1 .
LSP Verification . . . . . .
Termination . . . . . .
Concurrency . . . . . .
-----------------------------------------------------------------------------------------
Total 1 . . . 1 (100%) .
max steps used for successful proof: 0
Analyzed 1 unit
in unit main, 1 subprograms and packages out of 1 analyzed
Main at main.adb:1 flow analyzed (0 errors, 0 checks and 0 warnings) and proved (0 checks)
suppressed messages:
main.adb:4:16: reviewed by DeeDee
Have you tried adding an assertion before your conversion to an Integer and after checking the characters to ensure they are all in the range of '0' through '9'?
Example:
procedure Main is
pragma SPARK_Mode;
test_string : String := "123";
Number : Integer;
begin
-- pragma assert using a quantified expression
pragma Assert (for all I in test_string'Range => Test_string(I) in '0'..'9');
Number := Integer'Value(Test_String);
end Main;
I don't really see any way to do this. You need to be able to tell the prover that the input string not only contains the image of an integer, but that the value represented is in the range of Integer. Something like
if (for some I in Integer => I'Image = Input) then
-- Use Integer'Value
else
-- Error handling
end if;
which is unworkable.
Related
I've encountered an issue where using modular types in Ada that are not divisible by the system's Storage_Unit ( as defined in the runtime's system.ads ) will raise a Constraint_Error at runtime when accessed. I originally encountered this issue working on an bare-metal system using a minimal runtime while trying to read 12bit values from a buffer by overlaying the 12bit array over the buffer in memory. Does anyone know why this is occurring?
The following minimal example illustrates the issue I'm encountering. I tested this using AdaCore's GNAT 2019, compiled with the included zfp runtime. Using the standard runtime does not reproduce the issue.
with Ada.Text_IO; use Ada.Text_IO;
procedure Main is
----------------------------------------------------------------------------
-- Modular type with standard size divisible by 8.
----------------------------------------------------------------------------
type Type_One is mod 2 ** 16;
type Buffer_Type_One is array (1 .. 128) of Type_One;
----------------------------------------------------------------------------
-- Modular type with non-base 8 size.
----------------------------------------------------------------------------
type Type_Two is mod 2 ** 12;
type Buffer_Type_Two is array (1 .. 128) of Type_Two;
type Buffer is array (1 .. 256) of Character;
----------------------------------------------------------------------------
-- Example buffer.
----------------------------------------------------------------------------
Test_Buffer : Buffer := (others => ' ');
begin
----------------------------------------------------------------------------
-- Will not raise an exception.
----------------------------------------------------------------------------
Test_One :
declare
Buffer_One : Buffer_Type_One
with Import,
Convention => Ada,
Address => Test_Buffer'Address;
begin
Put_Line ("Testing type one");
for I in Natural range 1 .. 16 loop
Put_Line ("Test: " & Buffer_One (I)'Image);
end loop;
end Test_One;
----------------------------------------------------------------------------
-- Will raise a constraint error at runtime.
----------------------------------------------------------------------------
Test_Two :
declare
Buffer_Two : Buffer_Type_Two
with Import,
Convention => Ada,
Address => Test_Buffer'Address;
begin
Put_Line ("Testing type two");
for I in Natural range 1 .. 16 loop
Put_Line ("Test: " & Buffer_Two (I)'Image);
end loop;
exception
when Constraint_Error =>
Put_Line ("Constraint error encountered.");
end Test_Two;
end Main;
Here is the project file I used to compile this example:
project Test is
for Object_Dir use "obj";
for Exec_Dir use "build";
for Create_Missing_Dirs use "True";
for Languages use ("Ada");
package Builder is
for Executable ("main.adb") use "test";
end Builder;
for Main use ("main.adb");
package Compiler is
for Default_Switches ("Ada") use (
"-gnat2012",
"-gnatwadehl",
"-gnatVa",
"-gnaty3abcdefhiklmnoprstux"
);
end Compiler;
for Runtime ("Ada") use "zfp";
end Test;
I can't seem to find anything in the RM that would indicate why this would happen.
EDIT: Simon Wright below has figured out why this is happening. My naive understanding was that an instance of Buffer_Type_Two overlaid at the specified memory address would interpret the memory at this location as a sequence of 12bit values. It appears that this is not the case. It appears as though the compiler is rounding the size of the type up to 16bits, then raising a Constraint_Error when the 16bit value read from the array does not conform to the 12bit type.
If anyone can think of a better way to read a sequence of 12bit values from a location in memory in a sequential way I would greatly appreciate it, thank you.
With recent GNATs, you can achieve the behaviour you want by defining Buffer_Type_Two as
type Buffer_Type_Two is array (1 .. 128) of Type_Two
with Pack;
ARM 13.2(9) warns that this may not do what you want for 13-bit values (recent GNATs do, though).
An alternative would be
type Buffer_Type_Two is array (1 .. 128) of Type_Two
with Component_Size => 12;
The results are
...
Testing type two
Test: 32
Test: 514
Test: 32
Test: 514
...
For 13 bits, with either approach,
...
Testing type two
Test: 32
Test: 257
Test: 2056
Test: 64
Test: 514
Test: 4112
Test: 128
Test: 1028
Test: 32
...
HOWEVER, for an embedded target, you’ll need to use the -full- runtime system; for others, as pointed out by #egilhh above,
ajxs.adb:14:09: packing of 12-bit components not supported by configuration
Considering the compilation warnings, the code didn’t really deserve to work ...
31. Buffer_One : Buffer_Type_One
32. with Import,
33. Convention => Ada,
34. Address => Test_Buffer'Address;
|
>>> warning: specified address for "Buffer_One" may be inconsistent with alignment
>>> warning: program execution may be erroneous (RM 13.3(27))
>>> warning: alignment of "Buffer_One" is 2
>>> warning: alignment of "Test_Buffer" is 1
and
49. Buffer_Two : Buffer_Type_Two
50. with Import,
51. Convention => Ada,
52. Address => Test_Buffer'Address;
|
>>> warning: specified address for "Buffer_Two" may be inconsistent with alignment
>>> warning: program execution may be erroneous (RM 13.3(27))
>>> warning: alignment of "Buffer_Two" is 2
>>> warning: alignment of "Test_Buffer" is 1
but that’s not the problem, as it happens: Type_Two is mod 2**12, i.e. mod 4096, but the value in Buffer_Two(1) is 16#2020# (two space characters), which is 8224 in decimal.
"But why isn’t the stored value automatically masked to the 12 bits I asked for?" you say. For reasons of efficiency, "the size of an object is not necessarily the same as the size of the type of [the] object", GNAT RM 4.43, and GNAT expects the spare 4 bits at the top of the 16-bit word to be zero. On its own, a value of type Type_Two occupies (has ’Object_Size of) 16 bits. You could get the 12-bit size you want by including the Type_Two field in a record and specifying its layout, but that does add complication.
The problem wasn’t detected here without the -gnatVa (turn on all validity checking options).
The physical value of 16#2020# is not in the range of Type_Two so Constraint_Error is expected with -gnatVa.
GNAT CE 2020 raises Constraint_Error.
Uncommenting the exception/when part leads to further information:
raised CONSTRAINT_ERROR : main.adb:51 invalid data
what's the meaning of the following notation in Unix ?
:- or :=
what does the following means
if [ ${path:=0} -eq 1 ]
if [ ${path:-0} -eq 1 ]
The : is a parameter expansion, so if for instance $path is not set, it will fall back to 0 in your example code.
Using a hyphen :- will use the value, and using := will assign the value.
Additional info prompted by comment:
In your example, you are using a variable called $path, so using the := will go like this: if $path is not set, set $path to the value (0 in your case). Any time you use $path afterwards it would be set to your value, 0.
Using :- will simply just use the default value given (again, 0 in your case) and NOT assign it to $path. Any uses of $path afterwards still be not set.
CREATE OR REPLACE PROCEDURE ex9a(n NUMBER ,c CHAR) IS
pi NUMBER(7,4):=3.14;
v_record Areas%rowtype;
BEGIN
IF c='R' THEN
DBMS_OUTPUT.PUT_LINE('CHOICE : R');
v_record.Input_Value:= n;
v_record.Circle_Area:=pi*n*n;
v_record.Square_Area:=null;
v_record.Sphere_Area:=2*pi*n;
v_record.Sphere_Volume:=(3/4)*r*r;
v_record.Cube_Volume:=null;
END IF;``
END;
/
I am getting procedure created with compilation errors.I want to compute area of a circle and insert it into the table .
When I give SHOW ERRORS , it lists the errors as
1) plsql statement
2) 'R' must be declared .
(Even after I gave 'then'. I forgot the line number)
It would help if you would list the errors, and the lines on which they occur.
However, one obvious issue is that your IF statement has no THEN. It should be:
IF c = 'R' THEN
I want to print integers in Ada 83. At present I am just using 'with Text_IO' and 'use Text_IO'. I don't want to print using the Integer'Image option. I want to use Integer_Text_IO in ada83. Please help me out with the syntax.
I am using below code:
with Text_IO;
use Text_IO;
i: INTEGER :=1;
package Int_IO is new Integer_IO(INTEGER);
use Int_IO; put(i);
I am getting 'expect signed integer type in instantiation of "Num" ' error.
The example below, which compiles, should help.
But please, when posting a question on StackOverflow (or anywhere on the Net, really) show us the code you’ve actually tried. The sample you’ve provided doesn’t come close to compiling (it fails at line 3 with compilation unit expected), and that makes it very hard for us to work out how to help you.
You’ll get expect signed integer type in instantiation of “Num” if you try to instantiate Text_IO with the wrong sort of type (for example, Float).
with Text_IO;
procedure Integer_IO_Demo is
package Int_IO is new Text_IO.Integer_IO (Integer);
begin
for J in 5 .. 10 loop
Int_IO.Put (J);
Text_IO.New_Line;
end loop;
end Integer_IO_Demo;
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.