David Evans http://www.cs.virginia.edu/~evans Lecture 5: Code Red, Ariane 5, and Gambling CS201j: Engineering Software University of Virginia Computer Science David Evans http://www.cs.virginia.edu/~evans
Menu No checking, run-time checking, static checking Implementing Data Abstractions Checking Invariants Rep Exposure PS2 Comments 12 September 2002 CS 201J Fall 2002
Handling Mistakes No checking Run-time checking Static checking Assume programmers know what they are doing Run-time checking Check for anomalous behavior during program execution Static checking Check at compile-time Know properties of all possible executions before executing code 12 September 2002 CS 201J Fall 2002
Example: Array Bounds What should happen when the program writes beyond the bounds of an array? int a[10]; a[10] = 17; 12 September 2002 CS 201J Fall 2002
C/C++ Answer Checking is just a waste of execution time, we should trust the programmer not to make mistakes. # include <iostream.h> int main (void) { int x = 9; char s[4]; cin >> s; cout << "s is: " << s << endl; cout << "x is: " << x << endl; } 12 September 2002 CS 201J Fall 2002
C/C++ Bounds NonChecking > g++ -o bounds bounds.cc > bounds cs s is: cs x is: 9 cs201 s is: cs201 x is: 49 cs201j s is: cs201j x is: 27185 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa s is: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x is: 1633771873 Segmentation fault (core dumped) # include <iostream.h> int main (void) { int x = 9; char s[4]; cin >> s; cout << "s is: " << s << endl; cout << "x is: " << x << endl; } (User input) 12 September 2002 CS 201J Fall 2002
What’s going on?!! s x ‘c’ ‘s’ ‘2’ ‘0’ ‘1’ = 49 9 # include <iostream.h> int main (void) { int x = 9; char s[4]; cin >> s; cout << "s is: " << s << endl; cout << "x is: " << x << endl; } ‘s’ ‘2’ ‘0’ x ‘1’ = 49 9 > bounds cs201 s is: cs201 x is: 49 12 September 2002 CS 201J Fall 2002
What’s going on?!! s x ‘c’ ‘s’ ‘2’ ‘0’ ‘1’ = 49 9 ‘j’ = 106 # include <iostream.h> int main (void) { int x = 9; char s[4]; cin >> s; cout << "s is: " << s << endl; cout << "x is: " << x << endl; } ‘s’ ‘2’ ‘0’ x ‘1’ = 49 9 ‘j’ = 106 > bounds cs201j s is: cs201j x is: 27185 In C/C++, space for int is enough to hold 4 chars. 12 September 2002 CS 201J Fall 2002
s x return address ‘a’ ‘a’ ‘a’ ‘a’ ‘a’ 9 ‘a’ ‘a’ 9 ‘a’ ‘a’ # include <iostream.h> int main (void) { int x = 9; char s[4]; cin >> s; cout << "s is: " << s << endl; cout << "x is: " << x << endl; } s ‘a’ ‘a’ ‘a’ ‘a’ x ‘a’ 9 > bounds aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa s is: aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa x is: 1633771873 Segmentation fault (core dumped) ‘a’ ‘a’ 9 ‘a’ When main returns, execution jumps to the return address stored on the stack. But, the input overwrote that return address! return address ‘a’ 12 September 2002 CS 201J Fall 2002
When things go really bad… If person entering input is clever, they can put what they want in the return address, and their own code after that to jump to! “Buffer Overflow Attack” “Stack Smashing” 12 September 2002 CS 201J Fall 2002
Code Red 12 September 2002 CS 201J Fall 2002
Buffer Overflows Code Red: exploited buffer overflow in Microsoft’s IIS (web server) Attacker sends excessively long request to web server, overflows buffer and puts virus code on stack About ½ of all security problems are due to buffer overflows! 12 September 2002 CS 201J Fall 2002
Array Bounds in Java public class AverageLength { public static void main (/*@non_null@*/ String args[]) { String filename = args[0]; … } > javac AverageLength.java > java AverageLength Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException at AverageLength.main(AverageLength.java:7) 12 September 2002 CS 201J Fall 2002
Array Bounds with ESC/Java public class AverageLength { public static void main (/*@non_null@*/ String args[]) { String filename = args[0]; … } > escjava AverageLength.java AverageLength.java:7: Warning: Array index possibly too large (IndexTooBig) String filename = args[0]; ^ 12 September 2002 CS 201J Fall 2002
Array Bounds Checking C/C++: No checking No execution cost Lower Development cost? (if you don’t care about robustness) Really, really bad things can happen (and do often for typical programs) 12 September 2002 CS 201J Fall 2002
Array Bounds Checking Java: Run-time checking Performance cost: virtual machine needs to check array indexes are in bounds Get a run-time error, instead of Code Red But, sometimes run-time errors can be really, really bad too! 12 September 2002 CS 201J Fall 2002
Run-Time Exceptions Before Run-Time Exception After Run-Time Exception Ariane V (European) rocket, $5B Rubble, $0B Rocket exploded because of Run-Time Exception (1996) (not array bounds, value out of range – one bad line of code) 12 September 2002 CS 201J Fall 2002
Array Bounds Checking ESC/Java: static checking Check at compile-time: know there will not be an array bounds error on any possible execution If you trust the compile time checking, can turn off run-time checking (no performance penalty) More apparent effort to develop code (but is there really?) 12 September 2002 CS 201J Fall 2002
Implementing Data Abstractions Undirected Graph: B D A E C 12 September 2002 CS 201J Fall 2002
Specifying Graph public class Graph { // OVERVIEW: // A Graph is a mutable type that // represents an undirected // graph. It consists of nodes that are // named by Strings, and edges that // connect a pair of nodes. Do all nodes have to be connected? Can there be more than one edge between the same two nodes? 12 September 2002 CS 201J Fall 2002
Abstract Notation // A typical Graph is: // < Nodes, Edges > // where // Nodes = { n1, n2, …, nm } // and // Edges = { {from_1, to_1}, // …, {from_n, to_n} } 12 September 2002 CS 201J Fall 2002
Operations Creator public Graph () // EFFECTS: Initializes this to a graph // with no nodes or edges: < {}, {} >. 12 September 2002 CS 201J Fall 2002
Mutators void addNode (String name) // REQUIRES: name is not the name of a node in this // MODIFIES: this // EFFECTS: adds a node named name to this: // this_post = < this_pre.nodes U { name }, this_pre.edges > void addEdge (String fnode, String tnode) // REQUIRES: fnode and tnode are names of nodes // in this. // MODIFIES: this // EFFECTS: Adds an edge from fnode to tnode to this: // this_post = < this_pre.nodes, // this_pre.edges U { {fnode, tnode} } > What if there is already an edge there? Can nodes have edges to themselves? 12 September 2002 CS 201J Fall 2002
Observers boolean hasNode (String node) // EFFECTS: Returns true iff node is // a node in this. 12 September 2002 CS 201J Fall 2002
Observers StringIterator nodes () // EFFECTS: Returns the StringIterator that // yields all nodes in this in arbitrary // order. 12 September 2002 CS 201J Fall 2002
Observers StringIterator neighbors (String node) // REQUIRES: node is a node in this // EFFECTS: Returns the StringIterator that // yields all nodes in this that are // directly connected to node: // \result = // { n | {node, n} is in this.edges } 12 September 2002 CS 201J Fall 2002
Implementing Graph Choose a rep Think about implementing addEdge, addNode and getNeighbors Next time: come to class Tuesday with at least one idea for a rep to implement Graph 12 September 2002 CS 201J Fall 2002
PS2 12 September 2002 CS 201J Fall 2002
Specifications Describe what it does that a caller can see, not how it does it. Specifications should never mention local variables: caller can’t see them Language like “calculates”, “reads”, “goes through”, etc. are a bad sign: these are not actions that are visible to the caller Use requires clause to eliminate inputs from consideration (that you don’t describe in your effects) 12 September 2002 CS 201J Fall 2002
Specifying AverageLength public class AverageLength { public static void main (String args[]) // REQUIRES: } After you fixed the code, do we need to require args has at least one element? No, we can specify in EFFECTS what happens when args has no elements. Only need to use REQUIRES to eliminate inputs where the behavior is not known. 12 September 2002 CS 201J Fall 2002
Specifying AverageLength public class AverageLength { public static void main (String args[]) // REQUIRES: } Anything needed in REQUIRES? String filename = args[0]; … FileInputStream infile = new FileInputStream (filename); StringTable names = new StringTable (infile); We need to satisfy the require clauses of all methods called in implementation! 12 September 2002 CS 201J Fall 2002
public class AverageLength { public StringTable (java.io.InputStream instream) // requires: The stream instream is a names file containing lines of the form // <name>: <rate> // where the name is a string of non-space characters and the rate is // a floating point number. // modifies: instream // effects: Initializes this as a names table using the data from instream. public class AverageLength { public static void main (/*@non_null@*/ String args[]) // REQUIRES: args is not null, and if args has at least one // element, and args[0] is the name of a readable file, the // file named by args[0] must contain lines of the form // <name>: <rate> // where the name is a string of non-space characters and // the rate is a floating point number. 12 September 2002 CS 201J Fall 2002
AverageLength Modifies Should we also take the modifies clause from StringTable (FileInputStream)? public StringTable (java.io.InputStream instream) // modifies: instream // effects: Initializes this as a names table using the data from instream. No: the stream passed to StringTable (FileInputStream) is a local variable. Although it is modified, this modification is not visible to the caller. How do we know the file associate with the stream is not modified? AverageLength does modify System.out by printing MODIFIES: System.out 12 September 2002 CS 201J Fall 2002
AverageLength Effects public class AverageLength { public static void main (/*@non_null@*/ String args[]) // REQUIRES: If args has at least one element, and args[0] // is the name of a readable file, the file named by args[0] // must contain lines of the form <name>: <rate> where // the name is a string of non-space characters and the rate // is a floating point number. // MODIFIES: System.out // EFFECTS: If args is an empty array, prints a warning and // exits. If args[0] is not the name of a readable file, // prints a warning and exits. If the file named by args[0] // is empty, prints a warning an exits. Otherwise, prints a // message that indicates the average length of the names in // the names file named by args[0]. 12 September 2002 CS 201J Fall 2002
Black Box/Glass Box Testing Black Box testing: consider specification only Paths through specification Glass Box testing: consider code Paths through the code 12 September 2002 CS 201J Fall 2002
Black Box Tests public class AverageLength { public static void main (/*@non_null@*/ String args[]) // REQUIRES: If args has at least one element, and args[0] // is the name of a readable file, the file named by args[0] // must contain lines of the form <name>: <rate> where // the name is a string of non-space characters and the rate // is a floating point number. // MODIFIES: System.out // EFFECTS: If args is an empty array, prints a warning and // exits. If args[0] is not the name of a readable file, // prints a warning and exits. If the file named by args[0] // is empty, prints a warning an exits. Otherwise, prints a // message that indicates the average length of the names in // the names file named by args[0]. Obvious paths: 1. args is an empty array (run java AverageLength) 2. args[0] is an empty file 3. otherwise (note: args[0] file must satisfy requires clause) Should try files with one entry and many entries 12 September 2002 CS 201J Fall 2002
Glass Box Tests Devise test cases that exercise interesting paths through code: Both branches of an if Zero, one, many iterations of a loop For straightforward implementations, often there are no new tests (beyond Black Box) For complex procedures (like most of your NameTrends), there may be many new tests 12 September 2002 CS 201J Fall 2002
Wagering Strategy How did you decide what to wager? How should you have decided what to wager? 12 September 2002 CS 201J Fall 2002
Commerce School Strategy If p is the probability your code is correct, Expected Return = wp – 2w (1-p) = 3wp - 2w If p < 2/3, maximize with w = 0. If p = 2/3, expected return is 0 regardless of wager. If p > 2/3, expected return increases with w, bet maximum. 12 September 2002 CS 201J Fall 2002
Psychological Strategies Expected return is a bad model, since the value is non-linear If my ps was worth 90 without wager, 1/3 change of getting a 50 is not worth 2/3 chance of getting 110. Dave is probably crazy for asking such a question, so I have no clue how this will be graded 12 September 2002 CS 201J Fall 2002
Why Confidence Matters? Incorrect code, no confidence Worthless, no one can use it (but if they do, they get what they deserve) Correct code, no confidence Worthless, no one can use it (but if they do, they get lucky) Incorrect code, high confidence Dangerous! Correct code, high confidence Valuable 12 September 2002 CS 201J Fall 2002
PS2 Wagering Hard to grade because of vague specs If I was super strict, everyone would have lost their wager. PS3: wagering question will be judged by testing your program against a (secret) test suite that I design 12 September 2002 CS 201J Fall 2002
Easy way to get 100 on PS 2: Get full credit for questions 1-4 Answer question 5 (specify name trends) badly (0): static public void main (String args[]) // REQUIRES: false // EFFECTS: Prints out a correct proof of // P = NP. 12 September 2002 CS 201J Fall 2002
Remaining Answers Implement program that satisfies spec: Testing Strategy No testing necessary, no way to satisfy requires Bet: 20 static public void main (String args[]) { // REQUIRES: false // EFFECTS: Prints out a correct proof of P = NP. System.err.println (“Ha ha ha!”) } Note: I didn’t actually want you to do this! 12 September 2002 CS 201J Fall 2002
Charge Next class: implementing Graph Choose a rep, abstraction function and rep invariant Implement the methods Before class: think about your rep PS3: due next Thursday 12 September 2002 CS 201J Fall 2002