320 likes | 427 Views
A Language for Systems not Just Software. Peter Amey Praxis Critical Systems. Static Analysis Overview. Identifying properties of a program without execution style, coding standards, dubious construct detection language subset conformance, wellformedness control flow and complexity
E N D
A Language for Systems not Just Software Peter Amey Praxis Critical Systems
Static Analysis Overview • Identifying properties of a program without execution • style, coding standards, dubious construct detection • language subset conformance, wellformedness • control flow and complexity • data flow analysis • information flow analysis • proof (or formal verification) • An Ada compiler is a powerful static analyser • Analysis: shows that a program should work in all cases • Testing: shows that it does work for certain specific cases
SPARK Goals • Precise static analysis • Early use of static analysis • Facilitated by: • an exact language • removal of ambiguous and erroneous constructs • annotations
Why Annotations? • Annotations strengthen specifications • Ada separation of specifications/implementations too weak • Allows analysis without access to implementations • which can be done early on during development • even before programs are complete or compilable • Allows efficient detection of erroneous constructs
An example procedure Inc (X : inout Integer); --# globalinout Callcount; detection of function side-effect function AddOne (X : Integer) return Integer is XLocal : Integer := X; begin Inc(Xlocal); return XLocal; end AddOne; detection of aliasing Inc (CallCount);
Evolution of Annotations • Initially annotations were about code
Evolution of Annotations package P is procedure Inc (X : inout Integer); --# globalinout CallCount; end P; • Initially annotations were about code
Evolution of Annotations package P is procedure Inc (X : inout Integer); --# globalinout CallCount; end P; --# own CallCount; --# initializes CallCount; • Initially annotations were about code
Evolution of Annotations package P is procedure Inc (X : inout Integer); --# globalinout CallCount; end P; --# own CallCount; --# initializes CallCount; • Initially annotations were about code packagebody P is CallCount : Integer := 0; procedure Inc (X : inout Integer) is begin X := X + 1; CallCount := CallCount + 1; end Inc; endP;
Evolution of Annotations package P is procedure Inc (X : inout Integer); --# globalinout CallCount; end P; --# ownCallCount; --# initializes CallCount; • Initially annotations were about code packagebody P is CallCount : Integer := 0; procedure Inc (X : inout Integer) is begin X := X + 1; CallCount := CallCount + 1; end Inc; endP;
Evolution of Annotations package P is procedure Inc (X : inout Integer); --# globalinout CallCount; end P; --# own CallCount; --# initializes CallCount; • Initially annotations were about code • They evolved better to describe abstractions
package Stack --# own State; is procedure Clear; --# globalout State; --# derives State from ; procedure Push (X : in Integer); --# globalinout State; --# derives State from State, X; procedure Pop (X : out Integer); --# globalinout State; --# derives X, State from State; end Stack; packagebody Stack --# own State is Vector, Ptr; is MaxDepth : constant := 100; type Ptrs isrange 0 .. MaxDepth; subtype Indexes is Ptrs range 1 .. MaxDepth; type Vectors isarray (Indexes) of Integer; Ptr : Ptrs; Vector : Vectors; ... procedure Push (X : in Integer); --# globalinout Ptr, Vector; --# derives Vector from Vector, --# X, Ptr & --# Ptr from Ptr; ... Refinement
package Stack --# ownState; is procedure Clear; --# globalout State; --# derives State from ; procedure Push (X : in Integer); --# globalinout State; --# derives State from State, X; procedure Pop (X : out Integer); --# globalinout State; --# derives X, State from State; end Stack; packagebody Stack --# own State is Vector, Ptr; is MaxDepth : constant := 100; type Ptrs isrange 0 .. MaxDepth; subtype Indexes is Ptrs range 1 .. MaxDepth; type Vectors isarray (Indexes) of Integer; Ptr : Ptrs; Vector : Vectors; ... procedure Push (X : in Integer); --# globalinout Ptr, Vector; --# derives Vector from Vector, --# X, Ptr & --# Ptr from Ptr; ... Refinement
package Stack --# ownState; is procedure Clear; --# globalout State; --# derives State from ; procedure Push (X : in Integer); --# globalinout State; --# derives State from State, X; procedure Pop (X : out Integer); --# globalinout State; --# derives X, State from State; end Stack; packagebody Stack --# own State isVector, Ptr; is MaxDepth : constant := 100; type Ptrs isrange 0 .. MaxDepth; subtype Indexes is Ptrs range 1 .. MaxDepth; type Vectors isarray (Indexes) of Integer; Ptr : Ptrs; Vector : Vectors; ... procedure Push (X : in Integer); --# globalinout Ptr, Vector; --# derives Vector from Vector, --# X, Ptr & --# Ptr from Ptr; ... Refinement
package Stack --# own State; is procedure Clear; --# globalout State; --# derives State from ; procedure Push (X : in Integer); --# globalinout State; --# derives State from State, X; procedure Pop (X : out Integer); --# global in out State; --# derives X, State from State; end Stack; packagebody Stack --# own State is Vector, Ptr; is MaxDepth : constant := 100; type Ptrs isrange 0 .. MaxDepth; subtype Indexes is Ptrs range 1 .. MaxDepth; type Vectors isarray (Indexes) of Integer; Ptr : Ptrs; Vector : Vectors; ... procedure Push (X : in Integer); --# globalinout Ptr, Vector; --# derives Vector from Vector, --# X, Ptr & --# Ptr from Ptr; ... Refinement
Volatility Z : integer; for Z’Address use ... X := Z; Y := Z; does X = Y?
Modelling Volatility package Temperature --# own Inputs; --# initializes Inputs; is procedure Read (X : out Celsius); --# globalinout Inputs; --# derives X from Inputs & --# Inputs from Inputs; end Temperature;
Modelling Volatility package Temperature --# ownin Inputs; --# initializes Inputs; is procedure Read (X : out Celsius); --# globalinout Inputs; --# derives X from Inputs;& --# Inputs from Inputs; end Temperature;
Modelling Volatility package Temperature --# owninInputs; is procedure Read (X : out Celsius); --# globalin Inputs; --# derives X from Inputs; end Temperature;
Sensors package WaterHighSensor --# ownin State; is function IsActive return Boolean; --# global State; end WaterHighSensor; package WaterLowSensor --# ownin State; is function IsActive return Boolean; --# global State; end WaterLowSensor;
package Valve is type T is (Open, Shut); end Valve; with Valve; --# inherit Valve; package FillValve --# ownout State; is procedure SetTo (Setting : in Valve.T); --# globalout State; --# derives State from Setting; end FillValve; Actuators
Fault Integrator Abstract Type package FaultIntegrator is type T islimitedprivate; procedure Init (FI : out T; Threshold : in Positive); --# derives FI from Threshold; procedure Test (FI : inout T; CurrentEvent : in Boolean; IntegratedEvent : out Boolean); --# derives IntegratedEvent, --# FI from FI, CurrentEvent; private --# hide FaultIntegrator; end FaultIntegrator;
procedure Main --# globalin WaterHighSensor.State, --# WaterLowSensor.State; --# out FillValve.State, --# DrainValve.State; --# derives FillValve.State from --# WaterLowSensor.State & --# DrainValve.State from --# WaterHighSensor.State; is HighIntegrator, LowIntegrator : FaultIntegrator.T; HighThreshold : constant Positive := 10; LowThreshold : constant Positive := 10; Main controller
procedure ControlHigh --# globalin WaterHighSensor.State; --# out DrainValve.State; --# inout HighIntegrator; --# derives DrainValve.State, --# HighIntegrator from --# HighIntegrator, --# WaterHighSensor.State; isseparate; procedure ControlLow --# globalin WaterLowSensor.State; --# out FillValve.State; --# inout LowIntegrator; --# derives FillValve.State, --# LowIntegrator from --# LowIntegrator, --# WaterLowSensor.State; isseparate; Main controller
Main controller begin -- Main FaultIntegrator.Init (HighIntegrator, HighThreshold); FaultIntegrator.Init (LowIntegrator, LowThreshold); FillValve.SetTo (Valve.Shut); DrainValve.SetTo (Valve.Shut); loop ControlHigh; ControlLow; endloop; end Main;
separate (Main) procedure ControlHigh is RawFullEvent, TooFull : Boolean; begin RawFullEvent := WaterHighSensor.IsActive; FaultIntegrator.Test (HighIntegrator, RawFullEvent, -- to get TooFull); if TooFull then DrainValve.SetTo (Valve.Open); else DrainValve.SetTo (Valve.Shut); endif; end ControlHigh; Subunits
packagebody WaterHighSensor --# own State isin HighSensorPort; is type Byte ismod 256; ActiveValue : constant Byte := 255; HighSensorPort : Byte; for HighSensorPort'Address use ... function IsActive return Boolean --# global HighSensorPort; is RawVal : Byte; Result : Boolean; begin RawVal := HighSensorPort; if RawVal'Valid then Result := RawVal = ActiveValue; else Result := True; -- show too full on sensor failure endif; return Result; end IsActive; end WaterHighSensor; Device drivers
Low level annotation in implementation terms function IsActive return Boolean --# global HighSensorPort; Traceability and Abstraction --# own State isin HighSensorPort; Refinement hiding implementation detail function IsActive return Boolean; --# global State; Annotation in spec is in abstract terms --# derives FillValve.State from --# WaterLowSensor.State & --# DrainValve.State from --# WaterHighSensor.State; Main controller annotation entirely in abstract terms
Conclusions • SPARK and the Examiner originated from research concerned with reverse engineering of code • SPARK has evolved into something much more concerned with program construction than program analysis • The combination of abstract own variables and modes provides mechanisms for parallel descriptions of systems and implementations that analysis binds together