Advanced programming tools

Document Sample
Advanced programming tools Powered By Docstoc
					Advanced programming tools at
   K. Rustan M. Leino
   Microsoft Research, Redmond, WA, USA

16 May 2005
Distinguished lecture, York University
Toronto, ON, Canada
Software engineering problem

 Building and maintaining large systems
 that are correct

• Specifications record design decisions
  – bridge intent and code
• Tools amplify human effort
  – manage details
  – find inconsistencies
  – ensure quality
Design decisions
– examples and trends

      procedural abstraction
      int x;
      assert(x < a.Length);
        finite-state protocols
           pre- and postconditions, and
           object invariants
More powerful techniques
—a selection

  0.   PREfix
  1.   SLAM
  2.   SpecStrings
  3.   Spec#
0. PREfix                            [Bush, Pincus, Sielaff, et

• Detects common errors in C/C++
  – incorrect usage of null pointers, memory
    allocation, uninitialized variables, library
    idioms, ...
• Performs symbolic execution
  – detailed C semantics
  – paths simulated in detail, not all paths
  – interprocedural, procedures summarized by
    small subset of their paths
PREfix example

 int abs(int x) {
     int y;
     if (0 <= x) {
            y = x;
     return y;
                       possible use of
                     uninitialized variable
PREfix virtues

• Expensive to run
  – whole-program analysis
• Reduces effects of spurious warnings
  – filters and prioritizes output, uses heuristics
• Effective at finding errors
  – 1/8 of bugs fixed in Windows Server 2003
    found by PREfix (and PREfast)
• Widely deployed
The PREfast revolution             [Weise, et al.]

• PREfast – framework for authoring
  analyses (walks AST)
• PREfix runs centrally after check-ins,
  PREfast can run on developer desktops
  before check-ins
• Name recognition, plug-ins
On the road to embracing static analysis:
PREfix milestone
  PREfix and PREfast have opened
  eyes of developers and management
  to power of compile-time checking
1. Niche: device drivers

• bugs can have severe effects
• relatively small code base (usually ≤ 50
• crash-freedom specified by finite-state API

  protocols                               Release()


• correctness mostly

  depends on flow of
  control, not data
SLAM                              [Ball, Rajamani, et al.]

• Software model checking
  – predicate abstraction
  – model checking (state exploration)
  – counterexample-driven predicate refinement
Predicate abstraction and refinement

       boolean             model               abstract
       program            checker               trace


C program    predicate                         feasible?
                 s                        no           yes
                             refinement                        message
SLAM example

do {
   KeAcquireSpinLock();                          Release()

  nPacketsOld = nPackets;

   if (request) {
         request = request->Next;
} while (nPackets != nPacketsOld);

SLAM example                             Predicates:
                                         • P: spin lock held
do {
   assert ¬P; P := true;     // KeAcquireSpinLock();

   if ( * ) {

           assert P; P := false;   // KeReleaseSpinLock();

} while ( * );

assert P; P := false;    // KeReleaseSpinLock();
SLAM example                          Predicates:
                                      • P: spin lock held
do {
   assert ¬P; P := true;

   if ( * ) {

           assert P; P := false;

} while ( * );

assert P; P := false;

     error path in abstract program
SLAM example                         Predicates:
                                     • P: spin lock held
do {

  nPacketsOld = nPackets;

   if (request) {
         request = request->Next;
} while (nPackets != nPacketsOld);
                                      infeasible path in concrete program

    error path in abstract program
SLAM example                         Predicates:
                                     • P: spin lock held
do {                                 • Q: nPackets == nPacketsOld

  nPacketsOld = nPackets;

   if (request) {
         request = request->Next;
} while (nPackets != nPacketsOld);
                                      infeasible path in concrete program

    error path in abstract program
SLAM example                                 Predicates:
                                             • P: spin lock held
do {                                         • Q: nPackets == nPacketsOld
    assert ¬P; P := true;

   Q := true;    // nPacketsOld = nPackets;

   if ( * ) {

          assert P; P := false;
          Q := if Q then false else * end;     // nPackets++;
} while (¬ Q);   // nPackets != nPacketsOld

assert P; P := false;
                            no error path in abstract program;
                           hence, concrete program is correct
SLAM at Microsoft
• finite-state API protocols specified by
• applied to 100s of Windows drivers,
  for 10s of rules, found 60+ errors
• Static Driver Verifier
  – transferred to Windows
    Driver Quality group
  – to be released in DDK
On the road to embracing static analysis:
SLAM milestone
  SLAM showcases specifications and
  powerful checking
2. SpecStrings                    [Das, Fähndrich, et al.]

• company-wide effort to annotate C/C++
• standard annotation language (SAL) for
  describing assumptions about parameters
• limited checking by PREfast plug-in
  – can catch some null problems and buffer
SpecString example
   void * memcpy(
     pre notnull
     pre writableTo(pre byteCount(num))
     post readableTo(pre byteCount(num))
     void * dest,
     pre notnull
     pre readableTo(pre byteCount(num))
     void * src,
     size_t num);
SpecStrings at Microsoft

• emphasizes importance of interfaces
• better documentation
• improves checking
  – fewer spurious warnings
  – can detect errors from violations of stated
On the road to embracing static analysis:
SpecStrings milestone
  With SpecStrings, developers become
  used to source-code annotations that
  go beyond what compiler requires
3. Into the future

• managed code (C#, …)
• involve developers more intimately
  – capture design decisions earlier
  – let developers take control of their code
• reach beyond checking limits of current
• Experimental mix of contracts and tool support
• Aimed at experienced developers who know the
  high cost of testing and maintenance
• Superset of C#                            contracts
   – non-null types                                 everywhere

   – pre- and postconditions                     into the future

   – object invariants
• Tool support                   type     run-time      static
   – more type checking          checking checks verification

   – compiler-emitted run-time checks       degree of checking,
   – static program verification
      Specifications today
StringBuilder.Append Method (Char[ ], Int32, Int32)
Appends the string representation of a specified subarray of Unicode characters to the end of this
  public StringBuilder Append(char[] value, int startIndex, int charCount);
     A character array.
     The starting position in value.
     The number of characters append.
Return Value
  A reference to this instance after the append operation has occurred.
   Exception Type                      Condition
   ArgumentNullException               value is a null reference, and startIndex and charCount are not zero.
   ArgumentOutOfRangeException         charCount is less than zero.
                                       startIndex is less than zero.
                                       startIndex + charCount is less than the length of value.
Spec# specifications
                                • Callers are expected to establish
public StringBuilder Append(      precondition before invoking method
  char[ ] value,                • Implementations can assume
  int startIndex,                 precondition holds on entry

  int charCount);
   requires value != null || (startIndex == 0 && charCount ==
   requires 0 <= startIndex && 0 <= charCount;
   requires startIndex + charCount <= value.Length;
  ensures result == this;       Postcondition
                                • Implementations are expected to
                                  establish postcondition on exit
                                • Callers can assume postcondition
                                  upon return from method invocation
Object invariants
 readonly int rows;
 readonly int columns;
 readonly double[,] m;
 readonly int numInitialVars;
 readonly int numSlackVars;
 readonly int rhsColumn;
 readonly ArrayList<object> dims;
 readonly int[] basisColumns;
 readonly int[] inBasis;
 bool constructionDone = false;
 invariant   rows == m.GetLength(0);
 invariant   1 <= columns && columns == m.GetLength(1);
 invariant   0 <= numInitialVars;
 invariant   0 <= numSlackVars && numSlackVars <= rows;
 invariant   numInitialVars + numSlackVars + 1 == columns;
 invariant   rhsColumn == columns - 1;
 invariant   dims.Count == numInitialVars;
 invariant   basisColumns.Length == rows;
 invariant   inBasis.Length == numInitialVars + numSlackVars;
Spec# demo
Spec# verifier architecture
  Spec# compiler
    MSIL (“bytecode”)         Spec# static program verifier, akaBoogie

                               inference engine
           Boogie PL

               V.C. generator
                   verification condition
                        theorem prover
                             “correct” or list of errors
Analyzing verification conditions

• Automatic theorem prover
  – can be hidden from programmer
  – generates counterexamples
• Interactive theorem prover
  – requires gurus
  – not limited by built-in decision procedures
Generating verification conditions
                            Weakest preconditions
  int AbsX(Robot c)
                          c ≠ null 
    requires c ≠ null;      c ≠ null 
    ensures 0 ≤ result;     (0 ≤ sel(c,x)  c ≠ null  0 ≤ sel(c,x)) 
  {                         (¬(0 ≤ sel(c,x))  c ≠ null  0 ≤ −sel(c,x
    if (0 ≤ c.x) {        c ≠ null 
       a := c.x;          (0 ≤ sel(c,x)  c ≠ null  0 ≤ sel(c,x)) 
    } else {              (¬(0 ≤ sel(c,x))  c ≠ null  0 ≤ −sel(c,x))
       a := −c.x;         c ≠ null  0 ≤ sel(c,x)
    }                     c ≠ null  0 ≤ −sel(c,x)
    return a;
                          0 ≤ result
What’s in a language

      the programming language
      is the software engineer's
      primary thinking and working tool
Designing more rigor into the language

• Type system                         non-null types

  – impose coarse-grained restrictions
  – easy to understand and use
  – sound efficient checking    requires Pre;
• General specifications            modifies Frame;
                                    ensures Post;
  – enforce by mix of dynamic and static checking
  – don’t worry about completeness or
    decidability             requires this.inv = Valid;
• Develop good defaults          modifies this.*;
                                 ensures true;
Enforcing specifications

• Run-time checking
  – may leave out expensive checks, if not
    required for soundness
     • example: modifies clauses
                                   type     run-time      static
• Static verification              checking checks verification
                                              degree of checking,
  – requires more effort from the user                      effort
     • example: modifies clauses
  – modular checking a necessity
Migration problems

• To the new language
  – how does the language compare to existing
    ones?                                 contracts
                                         into the future
• From (!) the new language
  – development organizations may have process
         • Trend toward more rigorous languages and checking
         • Desire to contribute customized specifications
         • Tool support is crucial
         • Despite significant advances in the use of static analyses, we
           need more experience before we’d expect users to take on
           more detailed verification tasks
         • Some areas where more research will help
             –   language design
             –   program semantics
             –   specification techniques
             –   inference algorithms
             –   decision procedures
             –   methodology

Shared By: