Presentation is loading. Please wait.

Presentation is loading. Please wait.

Fixing Software Before It Breaks SIGAda 2001 S. Tucker Taft CTO AverCom Corp., a Titan Company October 3, 2001 Bloomington, MN.

Similar presentations


Presentation on theme: "Fixing Software Before It Breaks SIGAda 2001 S. Tucker Taft CTO AverCom Corp., a Titan Company October 3, 2001 Bloomington, MN."— Presentation transcript:

1 Fixing Software Before It Breaks SIGAda 2001 S. Tucker Taft CTO AverCom Corp., a Titan Company October 3, 2001 Bloomington, MN

2 Outline  Why Static Analysis?  Comparison of Static Error Detection in Current Ada versus C-based Languages  How Far Can Static Analysis Go?  Possible New (Annotation) Language Features to Enhance Static Error Detection  Conclusion  Acknowledgements: These ideas have been freely stolen from SPARK, Eiffel, Cyclone, Hermes/NIL,... and further developed in conjunction with Bob Duff

3 Why Static Analysis?  Full Run-Time Coverage Testing is Very Expensive  If Run-Time Exceptions are Possible, Coverage Testing Becomes That Much Harder  Tasking Creates A Potentially Intractable Number of Distinct Cases to Test  Generics Can Only Be Tested At Run-Time for Specific Instantiations -- Testing in General At Run-Time Is Not Defined.

4 Comparing Current Ada with C-Based Languages  Array Checking  Ada: Must be correct index type  C/C++/Java: Any integer type may index any array; Java checks out-of-range at run-time  Enumeration Types  Ada: No implicit conversion to/from an enumeration type  C: Freely interconvertible with any integer type  C++: Freely convertible to integer, but not back  Java: No enumeration types, must use ints with named constants

5 Comparing Current Ada with C-Based Languages (cont’d)  Generic Templates  Ada: Compile-time checks that generic body uses parameters appropriately  C++: No checking of generic template until instantiated  Synchronized/Protected Operations  Ada: All operations with access to protected data components lock during call  Java: May always add operation that doesn’t lock, either in same class or a subclass

6 Comparing Current Ada with C-Based Languages (cont’d)  Reading Uninitialized Variables  Ada: Bounded error to reference  Java: Disallowed at Compile-Time  Exceptions Handled  Ada: Unhandled exceptions propagated  Java: Unhandled exceptions disallowed at compile-time unless in “throws” clause (or “unchecked” exception)

7 How Far Can Static Analysis Go?  My Claim:  All situations that might result in failures of language-defined checks, or in bounded error or erroneous execution, can be eliminated at compile-time  My Concern:  How conservative, burdensome, or restrictive would the compile-time checks become?  SPARK-Ada95 is example of fairly restrictive subset, though it has grown into a highly usable system.

8 How Far Can Static Analysis Go? (cont’d)  My Belief:  Careful (annotation) language design can produce a highly flexible and usable language which nevertheless has no language-defined run-time failure conditions.  Many Higher-level or Application-specific failure conditions or inconsistencies can also be eliminated at compile-time using a “programmable” annotation language  Physical Units Checking is an example  Need to Study:  What are Typical Sources of (Human) Error

9 Typical Mistakes  Sin of Omission  Uninitialized Variables  Missing case in switch/case statement  Missing token/character (e.g. “break;”, “=“, “&”)  Missing return statement  Missing “increment” step in loop  Sin of Confusion  Swapping the parameters to “strcpy”  Confusing 1 = success vs. 0 = success  Forgetting about implicit effects or precedence

10 Typical Mistakes (cont’d)  Sin of Short-Sightedness (aka Laziness)  Fixed size buffer (the famous “gets” hole in “sendmail”)  Fixed size table (annoying “too many revisions” in RCS)  Well (Human) Engineered Language can:  Minimize Occurrence of These, or...  Catch These Mistakes at Compile-Time Well Human Engineered

11 Blaming the Worker for C’s Poor Human Engineering  A Software Fault Prevention Approach in Coding and Root Cause Analysis  Weider D. Yu, Bell Labs Technical Journal, April-June 1998  The top three root causes of the faults were:  execution/oversight (38%),  Inadequate attention to details (75%) and inadequate considerations to all relevant issues (11%);  resource/planning (19%),  Not enough engineer time (76%) and not enough internal support (4%);  education and training (15%).  Area of technical responsibility (68%) and programming language usage (15%).

12 Lucent 5ESS Software Fault Root Cause Analysis No Mention of Defective Material (i.e. the C Language) -- Only Defective Workmanship!

13 Lucent 5ESS C Programmer Advisories  Initialize all variables before use  Control flow of break and continue statements  Check C operator associativity and precedence for correct usage  Ensure loop boundaries are correct  Do not over-index arrays  Ensure value of variables is not truncated  Reference pointer variables correctly  Check pointer increments/decrements  Ensure logical OR and AND tests are correct

14 Lucent 5ESS C Programmer Advisories (cont’d)  Use all assignment and equal operators as intended  Ensure bit field data types are either unsigned or enum  Use logical AND and mask operators as intended  Check preprocessor conditionals  Check comment delimiters  Test unsigned variables for == 0 or != 0 only  Use cast cautiously Such Advisories are a sure sign of Poor Human Engineering and/or Defective Materials

15 The Big Trick to Catching Errors Early  Redundancy  Force the programmer to follow the writing- teacher’s rule:  Tell you what they are going to say  Tell you  Tell you what they said  Kinds of Redundancy:  Type Declarations  Subrange Declarations  var vs. const, in vs. out specification  Assertions, Pre/Post Conditions  Separation of Interface and Implementation  Tools should check for consistency

16 The Second Big Trick  Compartmentalization  Create many different specialized types  Any one type may only be used in appropriate places  Examples of Compartmentalization:  Use Uniquely shaped plugs and sockets  Define Appropriate Enumeration Types  Disallow Implicit Numeric Conversions, Allow usage- specific numeric types (“age”, “length”)  Specify Minimal Subrange for each variable  Require Boolean inside a conditional test  Avoid “if (func_name) { …”  Create a “gauntlet” for the program to pass  Lot’s of little, picky, tests on every line (like a slalom)

17 The Third Big Trick  Require Completeness  Don’t Fill in the blanks without explicit direction (e.g. explicit and local specification of default)  Examples of Completeness Requirements:  Case statement must cover all possible values of expression  Initializer must provide value for all components  Implementation Module must provide code for every (non-abstract) function appearing in Interface Module; every abstract function must be overridden  All Local Variables must be Explicitly Initialized on all paths prior to use  Every path out of function requires a “return” or “raise”

18 The Last Big Trick  Require Explicitness  aka: “Say it at least once!”  Favor the reader over the writer  Minimize implicit/side effects  Keep semantics obvious  Disallow possibly ambiguous cases  E.g., don’t create elaborate preference rules or implicit conversion rules  Make sure any defaults are safe and benign  Make sure the simple thing to do is the safest and easiest to maintain  Make sure unsafe programming constructs are highly visible, and require extra and explicit work at each use X

19 Examples of Areas for Enhanced Static Analysis for Ada  Uninitialized Variables  Null Checks  Erroneous Concurrent Access  Access-Before Elaboration  Physical Units Checking  Programmable Static Analysis

20 Basic Principles  All Run-Time Checks become Compile-Time Checks based on possibility of failure using “basic” flow analysis  Should support “simple” conditional/variant code  E.g.: if cond then X := 3; end if; …. If cond then Y := X; end if;  Explicit Checks coded by programmer will be recognized  E.g.: if X /= null then...  Annotations added to Spec to “Pass” PreConditions/PostConditions to Caller  This process can be automated

21 Uninitialized Variables  Add in/out/in-out/uninit annotation for global variables to spec  Add init/uninit annotations for exception propagation (if exceptions allowed)  Add default init/uninit annotations for access/comp/priv types (normal default is init)  Require initialization for:  Elementary value usage  RHS of composite assignment  “in”, “in out” params/globals at call (including ops)  Expr or “out” param/global at return

22 Null Checks  Very similar to Uninitialized variables  Add “not-null” annotation (or subtype constraint) for params, globals, func-result  Add “not-null” annotation for components  Require not null value upon:  Dereference (implicit or explicit)  Pass/Assign to not-null param/object  Return with not-null result, “out” param/global

23 Erroneous Concurrent Access  Add “task_safe” annotation for subprograms, packages, tasks  Task_safe subprograms may only refer to globals that are atomic or protected.  Task_safe tasks/subps may only have nested task_safe tasks, and call non-local subprograms only if they are task_safe.  “Task_safe” on a package implies all nested tasks, and all visible task types and subps are task_safe, and has task_safe elaboration

24 Access Before Elaboration  Add pragma which requires static elaboration checks  Complain at link-time if statically-safe elaboration order not determinable  Analysis shows this imposes very few restrictions on “real” programs

25 Physical Units Checking  Add pragma/attribute/annotation of units for scalar subtypes  Add subp annotations that require unit relationships, or compute units of result/out params based on units of other params  Compute and check unit relationships at compile-time or instantiation time.

26 Programmable Static Analysis  Allow declaration of “compile-time” attributes for instances of types, instances of generic, etc.  Allow annotations / preconditions / postconditions to use compile-time attributes.  Propagate annotations along with other information through flow analysis

27 Conclusion  Proving correctness is extremely hard  Proving “reasonableness,” consistency, etc. is feasible at compile-time  Pushing all of Ada’s current exception, bounded-error, and erroneous conditions to compile-time checks is possible, without creating excessive constraints  Adding programmable static analysis can allow compile-time checking to check application-specific “reasonableness.”


Download ppt "Fixing Software Before It Breaks SIGAda 2001 S. Tucker Taft CTO AverCom Corp., a Titan Company October 3, 2001 Bloomington, MN."

Similar presentations


Ads by Google