Title: Towards a Method of Programming with Assertions work by David S' Rosenblum
1Towards a Method of Programming with Assertions
work by David S. Rosenblum
- Cristian Garcia
- garciac_at_student.ethz.ch
- Software Engineering Seminar
- SS 2005
2Overview
- Assertions
- Introduction
- APP
- Classification of the assertions
- Discussion and Conclusions
3Assertions
- Are formal constraints
- Embedded assertions are powerful tools for
automatic runtime detection of software faults - Offer a practical alternative to mechanical proof
of correctness
4Assertions
- Specify system behaviour
- What rather than how
- Commonly written as annotations of a source text
- But they has seen little adoption in practice
5Introduction
- Since 1975 several authors demonstrated the
usefulness of the assertions - First appear in FORTRAN as annotations of source
text - Already in 1992 assertion features were available
in many high-level formal specification languages
and some newer programming languages
6Causes of little widespread use
- Tools fail to meet the need of the average
software developer - Programmers dont know what kind of assertions
are most effective at detecting faults
7APP
- Annotation PreProcessor for C programs developed
in UNIX - First prototype developed in 1989
- Is a replacement for standard preprocessor pass
of C compilers
8APP assertions
- Assertions appear as annotations /_at_ _at_/
- Constraint is specified using C language
expressions - Each APP assertion specifies a constraint to some
state of computation
9APP enhancement to C
- in evaluate a variable in the entry state
of the function - some
- all
10APP assertion constructs
- assume precondition
- promise postcondition
- return constraint on the return value
- assert constraint on an intermediate state
of a function body
11Example 1
- int square_root(int x)
- /_at_
- assume x gt 0 // precondition
- return y where y gt 0 // constraint on
- return y where yy lt x // return value
- x lt (y1)(y1)
- _at_/
-
- . . .
-
12Example 2
- void swap (int x, int y)
- /_at_
- assume x y x ! y // precondition
- promise x in y // postcondition
- promise y in x // postcondition
- _at_/
-
- x x y
- y x - y
- /_at_ assert y in x _at_/
- x x - y
-
13Violation actions and predefined macros
- APP converts an assertion to a runtime check
- Responses
- Default response
- promise invalid file swap.c, line 6,
- function swap
- Customized response
14Example customized response
- promise x in y
-
- printf(s invalid file s, ,
- _ _ANNONAME_ _, _ _FILE_ _)
- printf(line d, function s\n,
- _ _ANNOLINE_ _, _ _FUNCTION_ _)
- printf(out x d, out y d\n,
- x, y)
-
15Violation level
- It is possible to specify also the severity level
for each assertion - Example
- 1 assume x gt 0
- 1 is the default level and highest severity
- 0 disables all checking runtime
16Generating and running self-checked programs
- APP invoked through cc
- Greatly simplify the generation of
- self-checking programs
- No changes to UNIX and C
- Once compiled the program can be executed as usual
17A classification of assertions
- Are divided in two groups
- Specification of function interface
- Specification of function bodies
18Specification of function interface
19Consistency between arguments
- Often arguments are interdependent
- Sometime dependencies cannot be specified
directly in the programming language
20Consistency between arguments (example)
- enum Token_Kind identifier, number, string
- void store_token (Token_Kind kind, char token)
- /_at_
- assume (kind identifier token 0 gt a
- token 0 lt z)
- (kind number token 0 gt 0
- token 0 lt 9)
- (kind string token 0 )
- _at_/
-
21Dependencies of return value on arguments
- State the relationship between return value of a
function and the functions arguments upon entry
22Dependencies of return value on arguments
(example)
- int square_root(int x)
- /_at_
- assume x gt 0 // precondition
- return y where y gt 0 // constraint on
- return y where yy lt x // return value
- x lt (y1)(y1)
- _at_/
-
- . . .
-
23Dependencies of return value on arguments
(example)
- void swap (int x, int y)
- /_at_
- assume x y x ! y // precondition
- promise x in y // postcondition
- promise y in x // postcondition
- _at_/
-
- x x y
- y x - y
- /_at_ assert y in x _at_/
- x x - y
-
24Effect on global state
- Function often have side effects
- Use assertion to specify how a function changes
the global program state
25Effect on global state (example)
- // variable symbols is a symbol table
- void delete_name (char name)
- /_at_
- assume hashget (symbols, name)
- promise !hashget ( symbols, name)
- _at_/
- . . .
26The context in which a function is called
- Sometimes a function can be called only within
certain processing contexts - For example assertions can be used to check that
the function is called only when the appropriate
command-line option has been specified
27The context in which a function is called
(Example)
- void print_warning(int code, int line,
- char file)
- /_at_
- assume warnings_on
- _at_/
-
28Frame specification
- Functions are often required to leave certain
data unchanged - Assertions can be used to express such
requirements, which are called frame
specifications - Example
- promise
- strcmp(name, in strdup(name)) 0
29Subrange membership of data
- C does not allow the specification of subrange
constraints on numeric types - Assertions used to specify constraints that guard
against the mishandling of arrays - void fill_and_truncate ( )
- /_at_
- promise some (int i0 i lt BUFFSIZE ii1)
- buffer i \0
- _at_/
- . . .
30Other Specifications of function interface
- Non-null pointer
- assume x y x ! y
- Enumeration membership of data
- assume (kind identifier token 0 gt a
- token 0 lt z)
31Specification of function bodies
32Condition of the else part of complex if
statement
- Condition of the default branch of an if
statement is often intended to be stronger than
the simple negation of the disjunction of the
explicit, non-default conditions - Can be used also for the switch statement
33Condition of the else part of complex if
statement (example)
-
- if (token 0 gt a token 0 lt z)
- . . . / Handle identifier /
- else if (token 0 gt 0 token 0 lt 9)
- . . . / Handle number /
- else
- / Handle string /
- /_at_ assert token0 _at_/
- . . .
-
34Consistency between related data
- It is often necessary to process related data in
different ways and ensure that the data remain
consistent after processing - /_at_
- assert new_entry-gtnext ! 0
- queue-gttail new_entry
- _at_/
35Intermediate Summary of processing
- Assertions can be used for periodically summarize
the effect of a complex function at intermediate
points in its body
36Intermediate Summary of processing (example)
- void swap (int x, int y)
- /_at_
- assume x y x ! y // precondition
- promise x in y // postcondition
- promise y in x // postcondition
- _at_/
-
- x x y
- y x - y
- /_at_ assert y in x _at_/
- x x - y
37Discussion and conclusion
- Perry and Evangelist study 50 of the faults
were faults of inadequate error processing,
construction or inadequate functionality - Assertions can avoid most of this faults
- Incomplete specifications that capture the
essence of the intended behaviour are enough for
reliably detecting software faults at runtime
38Discussion and conclusion
- Performance APP can process approximately 20000
lines of C code per CPU-minute on a Sun-4
workstation - Statistic on a C program of 12000 lines, the
self-checking version is 12 larger than the
normal version and it runs with no discernible
difference in speed
39Questions?