7.6. How to Write Package Contracts

Like for subprogram contracts, GNATprove can generate default package contracts when not specified by a user. By default, GNATprove does not require the user to write any package contracts.

The default state abstraction generated by GNATprove maps every internal global variable to a different internal abstract state (which is not really abstract as a result).

The default package initialization generated by GNATprove lists all variables initialized either at declaration or in the package body statements. The generated Initializes aspect is an over-approximation of the actual Initializes aspect. All outputs are considered to be initialized from all inputs. For example, consider package Init_Data which initializes all its global variables during elaboration, from either constants or variables:

1package External_Data with
2  SPARK_Mode
3is
4   Val : Integer with Import;
5end External_Data;
 1with External_Data;
 2pragma Elaborate_All(External_Data);
 3
 4package Init_Data with
 5  SPARK_Mode
 6is
 7   pragma Elaborate_Body;
 8   Start_From_Zero     : Integer := 0;
 9   Start_From_Val      : Integer := External_Data.Val;
10   Start_From_Zero_Bis : Integer;
11   Start_From_Val_Bis  : Integer;
12end Init_Data;
1package body Init_Data with
2  SPARK_Mode
3is
4begin
5   Start_From_Zero_Bis := 0;
6   Start_From_Val_Bis  := External_Data.Val;
7end Init_Data;

GNATprove generates a package initialization contract on package Init_Data which is equivalent to:

Initializes => (Start_From_Zero     => External_Data.Val,
                Start_From_Zero_Bis => External_Data.Val,
                Start_From_Val      => External_Data.Val,
                Start_From_Val_Bis  => External_Data.Val)

As a result, GNATprove can check that global variables are properly initialized when calling the main procedure Main_Proc, and it does not issue any message when analyzing this code:

 1with Init_Data;
 2procedure Main_Proc with
 3  SPARK_Mode
 4is
 5   Tmp : Integer;
 6begin
 7   Tmp := Init_Data.Start_From_Zero;
 8   Tmp := Init_Data.Start_From_Val;
 9   Tmp := Init_Data.Start_From_Zero_Bis;
10   Tmp := Init_Data.Start_From_Val_Bis;
11end Main_Proc;

The user may specify explicitly package contracts to:

  • name explicitly the parts of state abstraction that can be used in subprogram dependency contracts, in order to Address Data and Control Coupling; or

  • improve scalability and running time of GNATprove’s analysis, as a single explicit abstract state may be mapped to hundreds of concrete global variables, which would otherwise be considered separately in the analysis; or

  • check that initialization of global data at elaboration is as specified in the specified package initialization contracts.