Extended Interface Grammars for Automated Stub Generation Graham Hughes Tevfik Bultan Department of Computer Science University of California, Santa Barbara.

Slides:



Advertisements
Similar presentations
Chapter 22 Implementing lists: linked implementations.
Advertisements

Automated Theorem Proving Lecture 1. Program verification is undecidable! Given program P and specification S, does P satisfy S?
Lectures on File Management
Semantics Static semantics Dynamic semantics attribute grammars
Intermediate Code Generation
Introducing Formal Methods, Module 1, Version 1.1, Oct., Formal Specification and Analytical Verification L 5.
Abstraction and Modular Reasoning for the Verification of Software Corina Pasareanu NASA Ames Research Center.
1 Mooly Sagiv and Greta Yorsh School of Computer Science Tel-Aviv University Modern Compiler Design.
1 Symbolic Execution for Model Checking and Testing Corina Păsăreanu (Kestrel) Joint work with Sarfraz Khurshid (MIT) and Willem Visser (RIACS)
CS 267: Automated Verification Lecture 10: Nested Depth First Search, Counter- Example Generation Revisited, Bit-State Hashing, On-The-Fly Model Checking.
9/27/2006Prof. Hilfinger, Lecture 141 Syntax-Directed Translation Lecture 14 (adapted from slides by R. Bodik)
272: Software Engineering Fall 2008 Instructor: Tevfik Bultan Lectures 13: Modularity, Interfaces and Verification.
1 Chapter 4 Language Fundamentals. 2 Identifiers Program parts such as packages, classes, and class members have names, which are formally known as identifiers.
Developing Verifiable Concurrent Software Tevfik Bultan Department of Computer Science University of California, Santa Barbara
© 2006 Pearson Addison-Wesley. All rights reserved4-1 Chapter 4 Data Abstraction: The Walls.
Modularity, Interfaces, and Verification Tevfik Bultan Department of Computer Science University of California, Santa Barbara.
CS 106 Introduction to Computer Science I 03 / 21 / 2008 Instructor: Michael Eckmann.
Software Reliability Methods Sorin Lerner. Software reliability methods: issues What are the issues?
Client and Server Verification for Web Services Using Interface Grammars Graham Huges, Tevfik Bultan, Muath Alkhalaf Department of Computer Science University.
Interface Grammars for Modular Software Verification Tevfik Bultan Department of Computer Science University of California, Santa Barbara.
© 2006 Pearson Addison-Wesley. All rights reserved4-1 Chapter 4 Data Abstraction: The Walls.
1 Run time vs. Compile time The compiler must generate code to handle issues that arise at run time Representation of various data types Procedure linkage.
Efficient Modular Glass Box Software Model Checking Michael Roberson Chandrasekhar Boyapati The University of Michigan.
272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 4: SMT-based Bounded Model Checking of Concurrent Software.
CSC 8310 Programming Languages Meeting 2 September 2/3, 2014.
272: Software Engineering Fall 2012 Instructor: Tevfik Bultan Lecture 2: Software Verification with JPF, ALV and Design for Verification.
Unit Testing & Defensive Programming. F-22 Raptor Fighter.
System/Software Testing
2.2 A Simple Syntax-Directed Translator Syntax-Directed Translation 2.4 Parsing 2.5 A Translator for Simple Expressions 2.6 Lexical Analysis.
1 CISC181 Introduction to Computer Science Dr. McCoy Lecture 19 Clicker Questions November 3, 2009.
A Review of Recursion Dr. Jicheng Fu Department of Computer Science University of Central Oklahoma.
Chapter 1 Introduction Dr. Frank Lee. 1.1 Why Study Compiler? To write more efficient code in a high-level language To provide solid foundation in parsing.
1 Chapter 5 LL (1) Grammars and Parsers. 2 Naming of parsing techniques The way to parse token sequence L: Leftmost R: Righmost Top-down  LL Bottom-up.
C++ for Engineers and Scientists Second Edition Chapter 6 Modularity Using Functions.
Testing Grammars For Top Down Parsers By Asma M Paracha, Frantisek F. Franek Dept. of Computing & Software McMaster University Hamilton, Ont.
1 Top Down Parsing. CS 412/413 Spring 2008Introduction to Compilers2 Outline Top-down parsing SLL(1) grammars Transforming a grammar into SLL(1) form.
EECE 310: Software Engineering Iteration Abstraction.
1 Introduction Modules  Most computer programs solve much larger problem than the examples in last sessions.  The problem is more manageable and easy.
Profs. Necula CS 164 Lecture Top-Down Parsing ICOM 4036 Lecture 5.
Lesson 3 CDT301 – Compiler Theory, Spring 2011 Teacher: Linus Källberg.
Low-Level Detailed Design SAD (Soft Arch Design) Mid-level Detailed Design Low-Level Detailed Design Design Finalization Design Document.
Testing. 2 Overview Testing and debugging are important activities in software development. Techniques and tools are introduced. Material borrowed here.
CS412/413 Introduction to Compilers and Translators Spring ’99 Lecture 8: Semantic Analysis and Symbol Tables.
1 Compiler Construction (CS-636) Muhammad Bilal Bashir UIIT, Rawalpindi.
Interpretation Environments and Evaluation. CS 354 Spring Translation Stages Lexical analysis (scanning) Parsing –Recognizing –Building parse tree.
Semantic Analysis. Find 6 problems with this code. These issues go beyond syntax.
CS 153: Concepts of Compiler Design October 5 Class Meeting Department of Computer Science San Jose State University Fall 2015 Instructor: Ron Mak
Property of Jack Wilson, Cerritos College1 CIS Computer Programming Logic Programming Concepts Overview prepared by Jack Wilson Cerritos College.
CS Data Structures I Chapter 2 Principles of Programming & Software Engineering.
1. 2 Preface In the time since the 1986 edition of this book, the world of compiler design has changed significantly 3.
Symbolic Execution with Abstract Subsumption Checking Saswat Anand College of Computing, Georgia Institute of Technology Corina Păsăreanu QSS, NASA Ames.
CS536 Semantic Analysis Introduction with Emphasis on Name Analysis 1.
CS 153: Concepts of Compiler Design October 7 Class Meeting Department of Computer Science San Jose State University Fall 2015 Instructor: Ron Mak
1 CSCD 326 Data Structures I Software Design. 2 The Software Life Cycle 1. Specification 2. Design 3. Risk Analysis 4. Verification 5. Coding 6. Testing.
The Interpreter Pattern (Behavioral) ©SoftMoore ConsultingSlide 1.
Recursion A recursive definition is one which uses the word or concept being defined in the definition itself Example: “A computer is a machine.
PROGRAMMING PRE- AND POSTCONDITIONS, INVARIANTS AND METHOD CONTRACTS B MODULE 2: SOFTWARE SYSTEMS 13 NOVEMBER 2013.
Chap. 7, Syntax-Directed Compilation J. H. Wang Nov. 24, 2015.
COMP 3438 – Part II-Lecture 5 Syntax Analysis II Dr. Zili Shao Department of Computing The Hong Kong Polytechnic Univ.
LECTURE 3 Compiler Phases. COMPILER PHASES Compilation of a program proceeds through a fixed series of phases.  Each phase uses an (intermediate) form.
Concurrency (Threads) Threads allow you to do tasks in parallel. In an unthreaded program, you code is executed procedurally from start to finish. In a.
© 2011 Pearson Education, publishing as Addison-Wesley Chapter 1: Computer Systems Presentation slides for Java Software Solutions for AP* Computer Science.
LECTURE 10 Semantic Analysis. REVIEW So far, we’ve covered the following: Compilation methods: compilation vs. interpretation. The overall compilation.
Chapter 8: Recursion Data Structures in Java: From Abstract Data Types to the Java Collections Framework by Simon Gray.
EECE 310: Software Engineering
A Simple Syntax-Directed Translator
Ch. 4 – Semantic Analysis Errors can arise in syntax, static semantics, dynamic semantics Some PL features are impossible or infeasible to specify in grammar.
Syntax-Directed Translation
Aspect Validation: Connecting Aspects and Formal Methods
Compilers Principles, Techniques, & Tools Taught by Jing Zhang
Presentation transcript:

Extended Interface Grammars for Automated Stub Generation Graham Hughes Tevfik Bultan Department of Computer Science University of California, Santa Barbara

Outline Motivation Interface Grammars Shape Types Interface Grammars + Shape Types Experiments Conclusions

Motivation Cool Verification Technique A Software System

Motivating Examples Cool verification technique: Action Language Verifier –An infinite state model checker for specifications with unbounded integers, boolean and enumerated variables Application: Check synchronization in Java programs Does not really work –ALV cannot handle Java semantics (objects, recursion etc.) –ALV would not scale to the state space of a typical Java program

Read-Write Lock in Action Language module main() integer nr; boolean busy; restrict: nr>=0; initial: nr=0 and !busy; module ReaderWriter() enumerated state {idle, reading, writing}; initial: state=idle; r_enter: state=idle and !busy and nr’=nr+1 and state’=reading; r_exit: state=reading and nr’=nr-1 and state’=idle; w_enter: state=idle and !busy and nr=0 busy’ and state’=writing; w_exit: state=writing and !busy’ and state’=idle; ReaderWriter: r_enter | r_exit | w_enter | w_exit; endmodule main: ReaderWriter() | ReaderWriter() | ReaderWriter(); spec: invariant(busy => nr=0) spec: invariant(busy => eventually(!busy)) endmodule

Read-Write Lock in Java class ReadWriteLock { private Object lockObj; private int totalReadLocksGiven; private boolean writeLockIssued; private int threadsWaitingForWriteLock; public ReadWriteLock() { lockObj = new Object(); writeLockIssued = false; } public void getReadLock() { synchronized (lockObj) { while ((writeLockIssued) || (threadsWaitingForWriteLock != 0)) { try { lockObj.wait(); } catch (InterruptedException e) { } } totalReadLocksGiven++; } } public void getWriteLock() { synchronized (lockObj) { threadsWaitingForWriteLock++; while ((totalReadLocksGiven != 0) || (writeLockIssued)) { try { lockObj.wait(); } catch (InterruptedException e) { // } } threadsWaitingForWriteLock--; writeLockIssued = true; } } public void done() { synchronized (lockObj) { //check for errors if ((totalReadLocksGiven == 0) && (!writeLockIssued)) { System.out.println(" Error: Invalid call to release the lock"); return; } if (writeLockIssued) writeLockIssued = false; else totalReadLocksGiven--; lockObj.notifyAll(); } } }

Motivating Examples Cool Verification Technique: Java Path Finder –An explicit state model checker (like Spin) for Java programs Application: Check assertions in Java programs Does not really work –JPF cannot handle native code –JPF does not scale to large Java programs

Verifiability Via Modularity Modularity is key to scalability of any verification or testing technique –Moreover, it can help isolating the behavior you wish to focus on, removing the parts that are beyond the scope of your verification technique Modularity is also a key concept for successful software design –The question is finding effective ways of exploiting the modularity in software during verification

Interfaces for Modularity How do we do modular verification? –Divide the software to a set of modules –Check each module in isolation How do we isolate a module during verification/testing? –Provide stubs representing other modules How do we get the stubs representing other modules? –Write interfaces Interfaces specify the behavior of a module from the viewpoint of other modules Generate stubs from the interfaces

Interface Grammars Program Component Interface Grammar Interface Compiler Component Stub Program Model Checker Interface Grammar

Start → Base Base →begin Tail Base |ε |ε Tail →commit |rollback |rollback An Example An interface grammar for transactions –Specifies the appropriate ordering for method calls to a transaction manager –Method calls are the terminal symbols of the interface grammar

Consider the call sequence begin rollback begin commit Here is a derivation: Start  Base  begin Tail Base  begin rollback Base  begin rollback begin Tail Base  begin rollback begin commit Base  begin rollback begin commit S tart → Base Base →begin Tail Base |ε |ε Tail →commit |rollback |rollback An Example

Another Example The earlier example we gave can also be specified as a FSM However, the following grammar which specifies nested transactions cannot be specified as a FSM Start → Base Base →begin Base Tail Base |ε |ε Tail →commit |rollback |rollback

Yet Another Example setrollbackonly which forces all the pending transactions to finish with rollback instead of commitLet’s add another method called setrollbackonly which forces all the pending transactions to finish with rollback instead of commit We achieve this by extending the interface grammars with semantic predicates and semantic actionsWe achieve this by extending the interface grammars with semantic predicates and semantic actions Start →«r:=false; l:=0» Base Base →begin «l:=l+1» Base Tail «l:=l-1; if l=0 then r:=false» Base «l:=l-1; if l=0 then r:=false» Base |setrollbackonly «r:=true» Base |setrollbackonly «r:=true» Base |ε |ε Tail →«r=false» commit |rollback |rollback

Our Interface Grammar Language rule base { choose { case ?begin: { «l++;» return begin; apply base; apply tail; «l--; if (l==0) r=false;» apply base; case ?setRollbackOnly: case ?setRollbackOnly:«r=true;» return setRollbackOnly; apply base;...}}...

Verification with Interface Grammars Interface Grammar Interface Compiler Program Model Checker Top-down parser parse table semantic predicates and semantic actions parser stack Component Stub method invocation (lookahead)

Checking Arguments A crucial part of the interface specification is specifying the allowable values for the method arguments and generating allowable return values In what I discussed so far all these are done in the semantic actions and semantic predicates The question is can we specify the constraints about the arguments and return values using the grammar rules –Recursive data structures are especially good candidates for this!

Shape Types Shape types [Fradet, Metayer, POPL 97] provide a formalism for specifying recursive data structures It is a specification formalism based on graph grammars Shape types can be used to specify the connections among the heap allocated objects Objects become the parameters of the nonterminals and the constraints on the connections among the objects are specified on the right-hand-sides of the grammar rules (similar to semantic predicates)

Shape Type for Doubly Linked List 12 next prev p 3 next prev 4 next prev next prev Doubly →p x, prev x null, L x L x →next x y, prev y x, L y L x →next x null p 1, prev 1 null, L 1 Doubly  p 1, prev 1 null, L 1  next 1 2, prev 2 1, L 2  next 2 3, prev 3 2, L 3  next 3 4, prev 4 3, L 4  next 4 null

Shape Type for Binary Tree 1 right left p right left right left 4 right left Bintree →p x, B x B x →left x y, right x z, B y, B z B x →left x null, right x null

Extension to Interface Grammars In order to support shape types we extend the interface grammars as follows: –We allow nonterminals with parameters This extension is sufficient since the constraints about the connections among the objects can be stated using semantics predicates and semantic actions

Interface Grammars + Shape Types Doubly →p x, prev x null, L x L x →next x y, prev y x, L y L x →next x null rule genDoubly(Node x) { «x = new Node(); x.setPrev(null);» apply genL(x); } rule genL(Node x) { choose { case: Node y = «new Node();» «x.setNext(y); y.setPrev(x);» apply genL(y); case: case:«x.setNext(null);»}

Objection Generation vs. Validation The use of shape types in interface grammars has two purposes –For the objects that are passed as method arguments we need to check that their shape is allowed by the shape type We call this object validation –For the objects that are returned by the component we need to generate an object that is allowed by the shape type We call this object generation

Object Generation vs. Validation Object generation and validation tasks are broadly symmetric –The set of nonterminals and productions used for object generation and validation are the same and are dictated by the shape type specification –In object generation semantic actions are used to set the fields of objects to appropriate values dictated by the shape type specification –In object validation these are constraints are checked using semantic predicates specified as guards

Object Generation vs. Validation There is a minor problem with object validation In shape type specifications, the assumption is that there is no aliasing among the objects unless it is explicitly specified This assumption is easy to enforce during object generation since every new statement creates a new object that has nothing else pointing to it In order to enforce the same constraint during object validation we need to make sure that there is no unspecified aliasing –This can be enforced by using a hash-set for storing and propagating all the observed objects

Experiments We wrote an interface grammar for the EJB 3.0 Persistence API – This is an API specification for mapping Java object graphs to a relational database – Hibernate is an implementation of this API Used several Hibernate test cases to evaluate performance and correctness Several test cases are designed to fail, and test exceptional behavior by violating the specification Accordingly we can verify the fidelity of our stub as well as verify the test cases themselves

Test caseInterface verificationClient verificationErr? bidir2 s15 MB2 s16 MBno mergeAndBidir2 s15 MB2 s16 MBno callbacks2 s15 MB2 s15 MBno exception2 s15 MB2 s15 MByes clear2 s15 MB2 s15 MBno contains3 s26 MB2 s15 MByes isOpen2 s15 MB2 s15 MBno persistNone2 s15 MB2 s15 MBno entityNotFound2 s15 MB2 s15 MByes alwaysTransactional2 s15 MB2 s15 MByes wrongId2 s15 MB2 s15 MByes find2 s15 MB2 s15 MBno Verification Results

Discussion No test can run under JPF without an environment Verification is quite efficient – This is because the test clients are pretty small – The important thing is that we are able to reduce the state space by replacing the EJB code with our stub Relative to a hand written environment we do not seem to pay a speed or memory penalty Time taken to develop the interface was dominated by the need to understand EJB Persistence first; about a couple of hours

Account Entry amount Transaction  (entry.amount) = 0 1 * 2.. * * sub-account More Experiments We extended the interface specification to represent a recursive data structure for accounts and transactions Accounts can have sub-accunts and, hence, are organized in a tree structure We specified this tree structure in an interface grammar based on shape types and conducted experiments for verification of client code

Four Clients We wrote 4 clients: –Client 1: Correct client, does not create any new data –Client 2: Correct client, creates new data –Client 3: Sometimes incorrect client –Client 4: Always incorrect client We increased the state space by increasing the number of accounts and entries and checked the verification performance

Experiments secMBsecMBsecMBsecMBAcc.Ent. 0:11260:17270:10270: :14260:23370:16360: :21340:38390:20360: :49362:55410:17360: :383615:37500:18360: Client 1Client 2 Client 3Client 4

Experiments secMBsecMBsecMBsecMBMB Acc.Ent. 0:14260:23370:16360: :09352:35410:56380: :093734:184314:03390: Client 1 Client 2 Client 3 Client 4

Conclusions Modular verificaiton is a necessity Interfaces are crucial for modular verification Interface grammars provide a new specification mechanism for interfaces We showed that interface grammars can be used for automated stub generation leading to modular verification

Related Work: Interfaces L. de Alfaro and T. A. Henzinger. Interface automata. O. Tkachuk, M. B. Dwyer, and C. Pasareanu. Automated environment generation for software model checking. A. Betin-Can and T. Bultan. Verifiable concurrent programming using concurrency controllers. T. Ball and S. K. Rajamani. SLAM interface specification language. G. T. Leavens et al.: JML

Related: Grammar-based Testing A. G. Duncan, J. S. Hurchinson: Using attributed grammars to test designs and implementations P. M. Maurer: Generating test data with enhanced context free grammars P. M. Maurer: The design and implementation of a grammar-based data generator E. G. Sirer and B. N. Bershad: Using production grammars in software testing

THE END