Astrée Proving the Absence of Runtime Errors Dr. Daniel Kästner AbsInt Angewandte Informatik GmbH 2011 2 AbsInt Angewandte Informatik GmbH Provides advanced development tools for embedded systems, and tools for validation, verification, and certification of safety-critical software. Founded in February 1998 by six researchers of Saarland University, Germany, from the group of programming languages and compiler construction of Prof. Dr. Dr. hc. mult R. Wilhelm. Privately held by the founders. Selected customers: 3 Astrée Overview Static Analyzer based on Abstract Interpretation to prove the absence of runtime errors in C programs (C99 standard). Originates from École Normale Supérieure, Paris. Licensed, developed, distributed by AbsInt. Polyspace Verifier originates from the same lab (Alain Deutsch), but is 10 years older. Advantages: Low number of false alarms by high analysis precision. Sophisticated analysis domains: decision-tree /memory/octagon/trace-partitioning domain, … Special support for real-time systems, digital filters, TargetLink CTO computations, … Floating-point rounding errors taken into account. Low effort for alarm analysis. High analysis speed. High reliability. No alarms shadowed by "green follows orange“. Formal specification of interface and environment information by Astrée directives. No code modification required. Flexible licensing models. Flexible Lizensierungsmodelle. Astrée is actively developed, also in projects with end customers (MBAT,FORTE,…) Qualified tool support (CET) and analysis service. Reference customer: Airbus flight control software (DO-178B, Level A). No false alarm on >700.000 LOC, analysis duration: 6h. 4 The Static Analyzer Astrée Crashes or undefined behavior due to runtime errors are bad and too many false alarms are bad. Astrée detects all runtime errors with few false alarms: Array index out of bounds Integer division by 0 Invalid pointer dereferences Arithmetic overflows and wrap-arounds Floating point overflows and invalid operations (IEEE floating values Inf and NaN) + User-defined assertions, unreachable code, uninitialized variables recommended: C programs without dynamic memory allocation and recursion ALARM: invalid dereference: dereferencing 1 byte(s) at offset(s) 10 may overflow the variable ArrayBlock of byte-size 10 at […] 5 Types of Runtime Errors (1) Runtime Errors causing undefined behavior (with unpredictable results) Modifications through out-of-bounds array accesses, dangling pointers, … Integer divisions by zero, floating-point exceptions, … Example: int main() { int n, T[1]; n = 2147483647; printf("n = %i, T[n] = %i\n", n, T[n]); } PPC MAC: n=2147483647,T[n]=2147483647 32-bit Intel: n=2147483647,T[n]=-135294988 Intel MAC: n=2147483647,T[n]=-1208492044 64-bit Intel: Bus error Astrée reaction: reports alarm (type A/B) in order to signal a potential runtime error, continues analysis for scenarios where the runtime error did not occur. Alarm type A: contexts without continuation are pruned Astrée reports an error and reports: Analysis stopped for this context. Alarm type B: no contexts without continuation. 6 Types of Runtime Errors (2) Runtime Errors causing unspecified, but predictable behavior: Integer overflow Invalid shifts <<,>>, or casts, … Astrée reaction: reports alarm (type C) in order to signal potential runtime error and continues analysis with an overapproximation of all possible results. No artificial restrictions on value ranges, so results are always safe. volatile short x,y; __ASTREE_volatile_input((x, [-1,1])); __ASTREE_volatile_input((y, [-1,1])); void main() { short z; z = (short)((unsigned short)x + (unsigned short)y); __ASTREE_assert((-2<=z && z<=2)); } "Compute-through-overflow" arithmetics. Overflow detected in signed short -> unsigned short conversions. Nevertheless: precise range for z on two's complement hardware (configurable). 7 The Zero Alarm Goal With zero alarms, absence of runtime errors is automatically proven by the analysis run, without additional reasoning. Design features of Astrée: Precise and extensible analysis engine, combining powerful abstract domains (intervals, octagons, digital filters, decision trees, …) Support for precise alarm investigation Source code views/editors for original/preprocessed code Alarms and error messages are linked: jump to location per click. Detailed alarm reporting: precise location and context, call stack, etc. Understanding alarms Fixing true runtime errors + Eliminating false alarms The more precise the analysis is, the fewer false alarms there are. Astrée supports improving precision by parametrization: local tuning of analysis precision making external knowledge available to Astrée specialization: adaptation to software class and target hardware 8 Adapting Astrée Target configuration and analysis options: ABI: endianness, alignment, data type sizes Auto-initialization of global variables, 2's complement hardware, Handling of div by zero, Handling of volatile variables, etc. Semantical Hypotheses __ASTREE_volatile_input((V, [0,9])); __ASTREE_assert((B)); __ASTREE_known_fact((B)); Parametrization of abstract domains: array smashing, variable folding, semantic loop unrolling, trace partitioning… Precision can be tuned to software under analysis: higher precision in critical parts, higher speed in less relevant parts. Specialization: Astrée can be enhanced by incorporating new abstract domains. 9 Adapting Astrée Parametrization of abstract domains Array smashing and variable folding, Semantic loop unrolling, Trace partitioning /value partitioning, etc. Semantic loop unrolling: Distinguish between different loop iteration to improve precision. Semantically unrolling a loop n times means analyzing the loop as: if (cond) { body; } ... while(cond) { if (cond) { body; } body; } while(cond) { body; } n times 10 Semantic Loop Unrolling int main() { static int init = 0; int i=0; float x=0.0, div=0.0; while (i<10) { if (init) { x+=x/div; } else { init = 1; x = 1.0; div = 2.0; } i++; } unroll=0: One invariant for all loop iterations: i [0,9]; init [0,1]; div [0.0,2.0] false alarm: potential runtime error in line 8: floating-point division by 0. unroll=1: One invariant for first loop iteration: at entry: i {0}; init {0} One invariant for all other loop iterations: i [1,9]; init 1; div 2.0 No alarms reported. Astrée default: unroll=3 + Automatic context-sensitive unrolling + Local control 11 Array Smashing Arrays whose element number is above a specified threshold are automatically smashed. 0 1 2 3 4 5 6 7 8 9 A[0] A[1] A[2] A[3] A[4] A[5] A[6] A[7] A[8] A[9] {0,1,…9} A[*] The directive __ASTREE_smash_variable((V,n)) indicates that all the arrays with n or more elements in the variable V should be folded. struct { Example: int nb; int tab[10]; struct { int x; int tab2[30]; } tab3[2]; } a; __ASTREE_smash_variable((a,4)); The arrays tab and tab2 will be folded, but not tab3. Variable a will be abstracted using the following 6 abstract fields: a.nb a.tab[*] a.tab3[0].x, a.tab3[0].tab2[*] a.tab3[1].x, a.tab3[1].tab2[*] 12 Partitioning typedef enum {FALSE = 0, TRUE = 1} BOOLEAN; void main () { int X; BOOLEAN B; __ASTREE_known_fact (( B == FALSE || B == TRUE )); __ASTREE_partition_control // alternatively __ASTREE_partition_begin((B)); if (B) { X = 1; } else { X = 2; } if (B) { X = X - 1; } else { X = X - 2; } __ASTREE_assert (( X == 0 )); /* proving this requires partitioning*/ __ASTREE_partition_merge (( ));/* optional at end of function */ } 13 Analysis Process Preprocess the code by adapting the build process, or from the built-in Astrée preprocessor Define appropriate analysis options Run the analysis Investigate the alarms Fix true errors Insert directives to fine-tune the analyzer Generate final reports 14 Client-Server Architecture Client Server Sources Project run analysis Preprocess Local files copy / sync Server files 15 Tool Qualification Qualification Support Kit: Validation suite to demonstrate functional correctness of the tool in the operational context of the user. Report Package: Operational Requirements Report: lists all functional requirements Verification Test Plan: describes one or more test cases to check each functional requirement. Test Package: All test cases listed in the verification test plan report Scripts to execute all test cases including an evaluation of the results Qualification Support Life Cycle Data: Additional report describing the AbsInt development processes to demonstrate safety of tool development. Up to DO-178B/Level A; ISO-26262/TCL-4, … 16 Modeling the Environment Synchronous control systems are often modelled as a cyclic executive: int main() { /* system initialization */ while (1) { /* read input */ compute_output(); /* update environment */ } } 17 Modeling the Environment This can be directly handled by Astrée: Declaring the synchronous loop Enabling the clock domain __ASTREE_max_clock((#iterations)); int main() { /* system initialization */ while (1) { /* read input */ compute_output(); /* update environment */ __ASTREE_wait_for_clock(()); } } // Default: 3.600.000 Also repetitive task executions in a multi-tasking system can be analyzed this way. 18 Modeling the Environment Absolute memory addresses have to be 'declared' for Astrée. int main() { int HWconf1; /* … */ *(int*)0xFFFF0000 = HWconf1; } This will cause an alarm (invalid pointer), since validity of absolute memory address cannot be ensured. Thus insert into 'global directives': int Dummy_HWconfReg[1024]; __ASTREE_absolute_address((Dummy_HWconfReg, 0xFFFF0000)); Insertion of dummy variable only is necessary if there is no dedicated variable associated with the memory address in the input program. 19 Handling Input Often, input is handled as follows: Input variables can change at the beginning of the synchronous loop Input variables are assumed to be constant during execution of one iteration Often input variables are known to be in certain ranges (e.g. sensor values) while (1) { __ASTREE_modify((In1)); // reset all info about In1 __ASTREE_known_fact((lb1<=In1 && In1<=ub1])); // specify range /* … */ __ASTREE_modify((Ink)); // reset all info about Ink __ASTREE_known_fact((Ink, [lbk,ubk])); // specify range compute_output(); /* update environment */ __ASTREE_wait_for_clock(()); } 20 Handling Output Often, output values are assumed to be in certain ranges. Astrée can statically check validity of assumptions: while (1) { __ASTREE_modify((In1)); // reset all info about In1 __ASTREE_known_fact((In1, [lb1,ub1])); // specify range /* … */ __ASTREE_modify((Ink)); // reset all info about Ink __ASTREE_known_fact((Ink, [lbk,ubk])); // specify range compute_output(); __ASTREE_assert((lb1 <= Out1 && Out1 <= ub1)); /* … */ __ASTREE_assert((lbn <= Outn && Outn <= ubn)); /* update environment */ __ASTREE_wait_for_clock(()); } 21 Thank you! email: [email protected] http://www.absint.com
© Copyright 2025 Paperzz