good programs broken programs cs 251 fall 2019 cs 240
play

Good programs, broken programs? CS 251 Fall 2019 CS 240 Spring 2020 - PowerPoint PPT Presentation

Good programs, broken programs? CS 251 Fall 2019 CS 240 Spring 2020 Principles of Programming Languages Foundations of Computer Systems Ben Wood Ben Wood Goal: program works (does not fail) Need: definition of works/correct : a


  1. λ Good programs, broken programs? CS 251 Fall 2019 CS 240 Spring 2020 Principles of Programming Languages Foundations of Computer Systems Ben Wood Ben Wood Goal: program works (does not fail) Need: definition of works/correct : a specification Reasoning about Programs But programs fail all the time. Why? (and bugs) 1. Misuse of your code: caller did not meet assumptions 2. Errors in your code: mistake causes wrong computation A brief interlude on 3. Unpredictable external problems: specifications, assertions, and debugging Out of memory, missing file, network down, … Plan for these problems, fail gracefully. 4. Wrong or ambiguous specification, implemented correctly Largely based on material from University of Washington CSE 331 https://cs.wellesley.edu/~cs240/s20/ Reasoning about Programs 1 Reasoning about Programs 2 A Bug's Life, ca. 1947 A Bug's Life Defect : a mistake in the code Think 10 per 1000 lines of industry code. We're human. Error : incorrect computation -- Grace Hopper Because of defect, but not guaranteed to be visible Failure : observable error -- program violates its specification Crash, wrong output, unresponsive, corrupt data, etc. Time / code distance between stages varies: tiny (<second to minutes / one line of code) or enormous (years to decades to never / millons of lines of code) Reasoning about Programs 3 Reasoning about Programs 4

  2. "How to build correct code" Testing Can show that a program has an error. 1. Design and Verify Can show a point where an error causes a failure. Make correctness more likely or provable from the start. Cannot show the error that caused the failure. 2. Program Defensively Cannot show the defect that caused the error. Plan for defects and errors. make testing more likely to reveal errors as failures make debugging failures easier 3. Test and Validate Can improve confidence that the sorts of errors/failures Try to cause failures. targeted by the tests are less likely in programs similar to provide evidence of defects/errors the tests. or increase confidence of their absence 4. Debug Cannot show absence of defects/errors/failures. Determine the cause of a failure. Unless you can test all possible behaviors exhaustively. Usually (Hard! Slow! Avoid!) Solve inverse problem. intractable for interesting programs. Reasoning about Programs 6 Reasoning about Programs 8 (without running them) Reasoning about programs Why reason about programs statically? Reason about a single program execution. Concrete, dynamic : be the machine, run the program. “Today a usual technique is to make a program and then to Test or debug: important, but "too late." test it. While program testing can be a very effective way to Reason about all possible executions of a program. show the presence of bugs, it is hopelessly inadequate for Abstract, static : consider all possible paths at once. showing their absence. The only effective way to raise the Usually to prevent broken programs. confidence level of a program significantly is to give a Hard for whole programs, easier if program uses clean, convincing proof of its correctness. ” modular abstractions. -- Edsger Dijkstra Many compromises in between. Reasoning about Programs 9 Reasoning about Programs 10

  3. Forward Reasoning Forward: careful with assignment Suppose we initially know (or assume) w > 0 // we know: nothing w = x+y; // we know: w == x + y // w > 0 x = 4; x = 17; // we know: w == old x + y, x == 4 // w > 0, x == 17 // must update other facts too... y = 42; // w > 0, x == 17, y == 42 y = 3; z = w + x + y; // we know: w == old x + old y, // w > 0, x == 17, y == 42, z > 59 … // x == 4, y == 3 // we do NOT know: w == x + y == 7 Then we know various things after, e.g., z > 59 Reasoning about Programs 11 Reasoning about Programs 12 Backward Reasoning Reasoning Forward and Backward If we want z < 0 at the end Forward: Determine what assumptions imply. Ensure an invariant is maintained. Invariant = property that is always true // w + 17 + 42 < 0 x = 17; Backward: // w + x + 42 < 0 y = 42; Determine sufficient conditions. // w + x + y < 0 For a desired result: z = w + x + y; What assumptions are needed for correctness? // z < 0 For an undesired result: What assumptions will trigger an error/bug? Then we need to start with w < -59 Reasoning about Programs 13 Reasoning about Programs 14

  4. Reasoning Forward and Backward Precondition and Postcondition Forward: Simulate code on many inputs at once. Precondition: “assumption” before some code Learn many facts about code's behavior, some of which may be irrelevant. // pre: w < -59 Backward: x = 17; Show how each part of code affects the end result. // post: w + x < -42 More useful in many contexts (research, practice) Closely linked with debugging Postcondition: “what holds” after some code If you satisfy the precondition, then you are guaranteed the postcondition. Reasoning about Programs 15 Reasoning about Programs 17 Conditionals, forward. Conditionals, backward. // pre: initial assumptions // pre: (C, X) or (!C, Y) if(...) { if( C ) { // pre: && condition true // pre: X : weakest such that ... // post: X ... // post: Z } else { } else { // pre: && condition false // pre: Y : weakest such that ... // post: Y ... // post: Z } } // either branch could have executed // either branch could have executed // post: X || Y // post: need Z Weakest precondition: the minimal assumption under which the postcondition is guaranteed to be true. Reasoning about Programs 18 Reasoning about Programs 19

  5. Conditional, backward Is static reasoning enough? // 9. pre: x <= -3 or (3 <= x, x < 5) or 8 <= x Can learn things about the program we have. // 8. pre: (x <= -3, x < 5) or (3 <= x, x < 5) Basis for human proofs, limited automated reasoning. // or 8 <= x // 7. pre: (x < 5, (x <= -3 or 3 <= x)) Compilers check types, do correct optimizations. // or 8 <= x // 6. pre: (x < 5, 9 <= x*x) or 8 <= x Many static program analysis techniques // 5. pre: (x < 5, 9 <= x*x) or (5 <= x, 8 <= x) Proving entire program correct is HARD! if (x < 5) { // 4. pre: 9 <= x*x x = x*x; // 2. post: 9 <= x } else { Should also write down things we expect to be true // 3. pre: 8 <= x x = x+1; // 2. post: 9 <= x } // 1. post: 9 <= x -4 -3 -2 -1 0 1 2 3 4 5 6 7 8 9 Reasoning about Programs 20 Reasoning about Programs 21 "How to build correct code" What to do when things go wrong Early, informative failures 1. Design and Verify Make correctness more likely or provable from the start. Goal 1: Give information about the problem 2. Program Defensively To the programmer – descriptive error message Plan for defects and errors. To the client code: exception, return value, etc. make testing more likely to reveal errors as failures make debugging failures easier Goal 2: Prevent harm 3. Test and Validate Whatever you do, do it early: before small error causes big problems Try to cause failures. Abort: alert human, cleanup, log the error, etc. provide evidence of defects/errors Re-try if safe: problem might be transient or increase confidence of their absence Skip a subcomputation if safe: just keep going 4. Debug Fix the problem? Usually infeasible to repair automatically Determine the cause of a failure. (Hard! Slow! Avoid!) Solve inverse problem. Reasoning about Programs 22 Reasoning about Programs 23

  6. Defend your code There are two ways of constructing a software design: One way is to make it so simple that there are 1. Make errors impossible with type safety, memory safety (not C!). obviously no deficiencies, 2. Do not introduce defects, make reasoning easy with simple code. and the other way is to make it so complicated that KISS = Keep It Simple, Stupid there are no obvious deficiencies. 3. Make errors immediately visible with assertions. The first method is far more difficult. Reduce distance from error to failure -- Sir Anthony Hoare, Turing Award winner 4. Debug (last resort!): find defect starting from failure Easiest in modular programs with good specs, test suites, assertions Use scientific method to gain information. Debugging is twice as hard as writing the code in the first place. Therefore, if you write the code as cleverly as possible, Analogy to health/medicine: you are, by definition, not smart enough to debug it. wellness/prevention vs. diagnosis/treatment -- Brian Kernighan, author of The C Programming Language book, much more Reasoning about Programs 24 Reasoning about Programs 25 Defensive programming, testing Square root with assertion Check: Precondition and Postcondition // requires: x >= 0 Representation invariant // returns: approximation to square root of x double sqrt(double x) { Other properties that should be true assert(x >= 0.0); Check statically via reasoning and tools double result; Check dynamically via assertions ... compute square root ... assert(index >= 0); assert(absValue(result*result – x) < 0.0001); assert(array != null); return result; assert(size % 2 == 0); } Write assertions as you write code Write many tests and run them often Reasoning about Programs 26 Reasoning about Programs 28

Download Presentation
Download Policy: The content available on the website is offered to you 'AS IS' for your personal information and use only. It cannot be commercialized, licensed, or distributed on other websites without prior consent from the author. To download a presentation, simply click this link. If you encounter any difficulties during the download process, it's possible that the publisher has removed the file from their server.

Recommend


More recommend