Download presentation
Presentation is loading. Please wait.
Published byErnest McDonald Modified over 6 years ago
1
Grigore Rosu University of Illinois at Urbana-Champaign, USA
From Rewriting Logic, to Programming Language Semantics, to Program Verification Grigore Rosu University of Illinois at Urbana-Champaign, USA
2
How it all started 1996: Started PhD with Joseph Goguen
Discovered Maude as “fast OBJ”, then rewriting logic 2000: Started at NASA Ames Started meeting with Jose regularly at SRI 2001: Jose moved to UIUC Invited me to visit, then encouraged me to apply 2002: Started at UIUC 2003: Jose (and Gul Agha) asked me to teach PL 2005: Rewriting Logic Semantics Project Countless hours of discussions; how far can it go?
3
Rewriting Logic Semantics Vision
Deductive program verifier Parser Interpreter Formal Language Definition (Syntax and Semantics) Model checker Symbolic execution (semantic) Debugger K is a language design framework and suite of tools. Its vision is to allow and encourage the language designers to formally define their languages once and for all, using an intuitive and attractive notation, and then obtain essentially for free implementations as well as analysis tools for the defined languages. This is a long-standing dream of the programming language community. Our objective in the K project is to develop the foundations, techniques, and tools to make this dream a reality. Compiler
4
The Adventure Began I was sold, this was too beautiful to pass
Question was: does it really work? We tried various semantic styles Small-step and big-step SOS Reduction semantics with evaluation contexts Chemical abstract machine Continuation-based style, denotational But each of the above had limitations Especially related to modularity and verification K framework was engineered to avoid limitations Initially implemented by translation to Maude
5
K Team http://kframework.org UIUC, USA Romania Former members
Grigore Rosu (started K in 2003) Brandon Moore Daejun Park Lucas Pena Cosmin Radoi Yuwen Shijiao Andrei Stefanescu Former members Kyle Blocher, Thomas Bogue, Peter Dinges, Chucky Ellison, Cansu Erdogan, Dwight Guth, Mike Ilseman, David Lazar, Patrick Meredith, Erick Mikida, Traian Serbanuta Runtime Verification, Inc., USA Dwight Guth Manasvi Saxena Romania Dorel Lucanu Traian Florin Serbanuta Andrei Arusoae Stefan Ciobaca Radu Mereuta Former Members Irina Asavoae, Mihai Asavoae, Denis Bogdanas, Gheorghe Grigoras, Emilian Necula, Raluca Necula Traian Serbanuta is currently the K tool development lead.
6
K Approach Deductive program verifier Test-case generation Parser
Interpreter Formal Language Definition (Syntax and Semantics) Model checker Symbolic execution (semantic) Debugger Recall our overall approach: one formal definition of the language given once and for all, and then the various tools derived from the formal definition. Compiler
7
Complete K Definition of KernelC
Here is a complete definition of a fragment of C, called KernelC, as generated by the K tool. The left column defines its formal syntax and the other two its formal semantics. I will next zoom through this definition and highlight some of the K tool’s features.
8
Complete K Definition of KernelC
Syntax declared using annotated BNF … Syntax is declared using the conventional BNF notation, annotated with K attributes (in blue). For example, assignment is an expression construct taking two expression arguments (the left one can be a variable x, a pointer *x, etc.; we only discuss the former case here). The “strict(2)” annotation states that assignment is strict in the second argument, that is, that argument needs to be evaluated first. The semantic rule of assignment, which we discuss shortly, then can assume that the second argument is already a value.
9
Complete K Definition of KernelC
Configuration given as a nested cell structure. Leaves can be sets, multisets, lists, maps, or syntax K makes heavy use of configurations, which in the tool can be defined and initialized in a user friendly and colorful way. A configuration can be regarded as a snapshot of the program execution: it includes the remaining program, together with all the necessary semantic information to execute it. K configurations are organized as nested cell structures, whose leaves hold basic data organized in lists, maps, sets, etc. Cells can be referred to by their name; their order is irrelevant. In KernelC, the k cell holds the remaining code, funs the set of functions, env the current environment, mem the current heap, fstack the current function stack, in and out the current input/output buffers, ptr the current malloc/free pointer map, and so on.
10
Complete K Definition of KernelC
Semantic rules given contextually rule <k> X = V => V …</k> <env>… X |-> (_ => V) …</env> Once the syntax and configuration are defined, we can start adding semantic rules. K rules are contextual: they mention a configuration context in which they apply, together with local changes they make to that context. To enhance the modularity of your language definition, you typically aim at only mentioning the absolutely necessary context in your rules; the remaining details are filled in automatically by the tool. For example, here is the K rule for assignment, both in graphical and in ASCII formats; we only discuss the graphical notation here. Recall that assignment was strict(2), so we can assume that its second argument is a value, say V. The context of this rule involves two cells, the k cell which holds the current code and the env cell which holds the current environment. Moreover, from each cell, we only need certain pieces of information: from the k cell we only need the first task, which is the assignment X=V, and from the env cell we only need the binding X |-> _. The underscore stands for an anonymous variable, the intuition here being that that value is discarded anyway, so there is no need to bother naming it. The unnecessary parts of the cells, which we call frames, are metaphorically “torn away” and ignored, as suggested by the tears. Then, once the local context is established, we identify the parts of the context which need to change, underlying them, and then provide the changes under the lines. In our case, we rewrite both the assignment expression and the value of X in the environment to the assigned value V. Everything else stays unchanged. The concurrent semantics of K regards each rule as a transaction: all changes in a rule happen concurrently; moreover, rules themselves apply concurrently, provided their changes do not overlap.
11
K Scales Several large languages were recently defined in K:
Java 1.4: by Bogdanas etal [POPL’15] 800+ program test suite that covers the semantics JavaScript ES5: by Park etal [PLDI’15] Passes existing conformance test suite (2872 pgms) Found (confirmed) bugs in Chrome, IE, Firefox, Safari C11: Ellison etal [POPL’12, PLDI’15] All 77 different types of undefined behavior Commercialized by startup (Runtime Verification, Inc.) … K scales! Besides a series of smaller and paradigmatic languages that are used for teaching purposes, there are several large and real languages that have been given semantics in K, such as: Java has been defined by Bogdanas; Javascript by Park and Stefanescu; C by Ellison etal; just to mention a few. Many other large K semantics are under development.
12
K Configuration and Definition of C
Heap To give an idea what it takes to define a large language, here is, for example, the configuration of C. It has more than 70 cells! The heap, which is the subject of so many debates in program verification, is just one of them. 120 Cells! … plus ~2000 rules …
13
K Semantics are testable!
Parser Interpreter Formal Language Definition (Syntax and Semantics) (semantic) Debugger
14
Testing the K definition of C
Tested on thousands of C programs (several benchmarks, including the gcc torture test, code from the obfuscated C competition, etc.) Passed 99.2% so far! GCC passes 99%, ICC 99.4%, Clang 98.3% (no opt.) The most complete formal C semantics The C definition has about 1200 rules. Since a definition is correct by definition, it is important to gain as much confidence in it as possible. Our approach in K is to extensively test our definitions by executing them. In the case of C, the semantics has been tested against several thousands programs in a regression test suite, including gcc’s torture test suite, code from the obfuscated C competitions, as well as many other programs found on the internet which were devised to explore the dark corners of the C language. As of now (Septemeber 2012), the K semantics of C passes 99.2% of the programs in our large test suite. Note that gcc only passes 99%, ICC 99.4%, and Clang 98.3%, all these without optimizations enabled (optimizations reduce these numbers by a few percentages). The reason for which these compilers and even our semantics do not pass all programs, is partly because the semantics of C is not well explained in the manual and allows room for interpretation and confusion. These tools simply do not agree on what a correct C program is. Funny, isn’t it? Particularly when you want to actually verify C programs … At our knowledge, the K semantics of C is the most complete C semantic to date. [POPL’12, PLDI’15]
15
How slow is it? K Framework supports attaching backends
Initial translation to Maude became a backend Java (symbolic) and OCAML (concrete) backends C loop calculating … + 5,000,000 Compiled with gcc: 18 ms Fastest hand-written Interpreter: 2 sec (111 x C) K[OCAML]: 14 sec (777 x C, 7 x I) K[Java]: 20 min (66000 x C, 86 x O, 600 x I) K[Maude]: 10 x slower than K[Java] Further improvements coming soon (improving the semantics of C, LLVM backend, compilation) Semantics-based language design feasible !
16
Deductive program verifier
Formal Language Definition (Syntax and Semantics) Symbolic execution
17
State-of-the-Art Many different program logics for “state” properties: FOL, HOL, Separation logic… Redefine the language using a different semantic approach (Hoare/separation/dynamic logic) Language specific, non-executable, error-prone
18
State-of-the-Art Thus, these semantics need to be proved sound (and relatively complete) wrt trusted, operational semantics (reference model) Huge effort, few dare to do it; so typically not done But verification tools are developed using them So we have an inherent gap between trusted, operational semantics, and the semantics currently used for program verification
19
Our Approach Use directly the trusted operational semantics!
Formal Language Definition (Syntax and Semantics) Deductive program verifier Symbolic execution Use directly the trusted operational semantics! Language-independent proof system Takes operational semantics as axioms Derives reachability properties Sound and relatively complete for all languages!
20
Need a means to specify static and dynamic program properties
Deductive program verifier Formal Language Definition (Syntax and Semantics) Symbolic execution
21
Matching Logic for Static Properties
Specify properties over program configurations and reason about them using matching logic Ultimate “program logic” for the language in question, specifically crafted for it We only discuss first-order variant here Can be obtained from FOL by collapsing its operation and predicate symbols Collapsing its terms and predicates, into patterns Interpreting symbols in powerset domains
22
Matching Logic vs. FOL Simpler (no need to distinguish operations from predicates) Same expressiveness, but patterns more succinct than FOL formulae When fixing model(s), quite a convenient notation (captures separation logic)
23
Separation logic = Matching logic [Map]
Consider map model, with some useful axioms Then we can define map patterns “a la SL”
24
MatchC Example http://matching-logic.org
25
Sound and complete proof system
[RTA’15] Sample derivation: Local reasoning globalized (“structural framing” for free!) Above derivation can be lifted to whole configuration
26
Need a means to specify static and dynamic program properties
Deductive program verifier Formal Language Definition (Syntax and Semantics) Symbolic execution
27
Reachability Logic for Dynamic Properties [LICS’13], [RTA’14]
“Rewrite” rules over matching logic patterns: (generalize to conditional rules) Since patterns generalize terms, matching logic reachability rules capture term rewriting rules Moreover, deals naturally with side conditions: turn into
28
Expressiveness of Reachability Rules
Capture operational semantics rules: Capture Hoare Triples:
29
Reachability Logic Language-independent proof system for deriving sequents of the form where A (axioms) and C (circularities) are sets of reachability rules Intuitively: symbolic execution with operational semantics + reasoning with cyclic behaviors
30
Proof System for Reachability
Proves any reachability property of any lang., including anything that Hoare logic can (proofs of comparable size) [FM’12] Sound (partially correct) and relatively complete [ICALP’12], [OOPSLA’12], [LICS’13], [RTA’14]
31
Traditional Verification vs. Our Approach
Traditional proof systems: language-specific Our proof system: language-independent
32
Does It Really Work? Reachability logic implemented in K, generically
Evaluated it with the existing semantics of C, Java, and JavaScript, and several tricky programs Q1: Can we specify the desired properties? Q2: Is performance OK?
33
Time (seconds) spent on applying semantic steps (symbolic execution)
Evaluation Results Time (seconds) spent on applying semantic steps (symbolic execution) Time (seconds) spent on domain reasoning (matching logic + querying Z3) Properties very challenging to verify automatically. We only found one such prover for C, based on a separation logic extension of VCC Which takes 260 sec to verify AVL insert (ours takes 210 sec; see above)
34
Conclusion: It can be done
Conclusion: It can be done. Thank you, Jose, for firmly believing it from day 1! Test-case generation Deductive program verifier Parser Interpreter Formal Language Definition (Syntax and Semantics) Model checker Symbolic execution (semantic) Debugger Compiler
35
Extra Slides
36
Motivation Goal: verify programs using directly the trusted executable semantics of the language Avoid defining Hoare logic or axiomatic semantics Many existing executable semantics frameworks PLT-REDEX (Findler etal) , MSOS tool (Mosses etal) , OTT (Sewell etal) , Spoofax (Visser etal) , K (Rosu etal) Semantics = rewrite rules over configuration patterns Need: specify properties/patterns/structure of interest over program configurations
37
Matching Logic - Overview
Logic for reasoning about structure Structure defined as algebraic data-types Formulae specify desired structure templates or patterns Formula satisfaction is pattern matching Historical remarks First variant proposed in 2010 (Rosu, Ellison, Schulte) Continuously improved, implemented and applied since then, as part of larger projects on program reasoning Latest and most comprehensive reference: RTA’15 Most general variant; soundness and completeness
38
Talk Overview Context: Executable language semantics Matching logic
The K framework Matching logic Application: Program specification and verification using matching logic
39
Vision and Objective Deductive program verifier Test-case generation
Parser Interpreter Formal Language Definition (Syntax and Semantics) Model checker Symbolic execution (semantic) Debugger K is a language design framework and suite of tools. Its vision is to allow and encourage the language designers to formally define their languages once and for all, using an intuitive and attractive notation, and then obtain essentially for free implementations as well as analysis tools for the defined languages. This is a long-standing dream of the programming language community. Our objective in the K project is to develop the foundations, techniques, and tools to make this dream a reality. Compiler
40
Current State-of-the-Art in PL Design, Implementation and Analysis
Consider some programming language, L Formal semantics of L? Typically skipped: considered expensive and useless Implementations for L Based on some adhoc understanding of what L is Model checkers for L Based on some adhoc encodings/models of L Program verifiers for L Based on some other adhoc encodings/models of L … Before we introduce our approach, let me first explain what the problem is. Consider some real programming language, say L. Do we have any formal semantics for L? Most likely not. This step is typically skipped, being considered by many, unfortunately even programming language experts, too expensive to be worth the effort. In fact, a human readable language semantics can be an excellent means to understand and even learn the language! One problem is, however, that existing semantic approaches are too heavy, non-modular, and hard to digest by humans. Then consider the various implementations and analysis tools for L, even the formal analysis tools. With a lack of semantics, these are based on some adhoc understanding of their developers of what the language L is; more specifically, they build upon adhoc language models, which are hardwired in the tools or systems, but without any guarantee that these models are the right ones, or even sound projections of the actual language semantics.
41
Example of C Program What should the following program evaluate to?
According to the C “standard”, it is undefined GCC4, MSVC: it returns 4 GCC3, ICC, Clang: it returns 3 State-of-the-art formal program verifiers "prove" that this program returns 4 int main(void) { int x = 0; return (x = 1) + (x = 2); } The lack of a formal semantics in implementations and analysis tools does not come without consequences. Consider this two-line C function. Recall that, in C, assignment is an expression construct which evaluates to the assigned expression and, as a side effect, also writes the variable. What does main() return? According to the C “standard”, a rather informal and confusing 700-page document, this program is undefined (because it manifests two unsequenced writes to the same location). However, different C compilers, even different versions of the same compiler, return different results: some 3, others 4. While surprising, this is somewhat acceptable, since compilers are free to optimize assuming that it is programmers’ responsibility that their programs are defined. What is surprising, even unacceptable, is that formal program verifiers actually “prove” that it returns 4! I personally have a hard time understanding how it is even possible to return 4. Anyway, the rhetoric question here is: how can we trust any program verification claims, if advanced formal analysis tools can prove correct obviously wrong two-line programs?
42
A Formal Semantics Manifesto
Languages must have formal semantics! And analysis/verification tools should build on them Otherwise they are adhoc and likely wrong Informal manuals are not sufficient Manuals typically have a formal syntax of the language (in an appendix) Why not a formal semantics appendix as well? Our firm position is that programming languages must have formal semantics. Period! Moreover, analysis or verification tools should build upon formal semantics. Otherwise, they are adhoc and likely wrong. Informal language manuals, or “standards” are simply insufficient. Interestingly, these manuals tend to include a formal syntax of the language, typically in an appendix. Why not a formal semantics appendix as well? In our experience, most programmers are simply scared of semantics, and for good reasons: it takes a lot to digest semantic formalisms, then it is quite boring and tedious to give a semantics to a complete language due to the lack of modularity of most semantic frameworks, and in the end there is not much you can get from or do with a semantics. We are here because we believe that this can be changed.
43
Recall - First Order Logic
44
From FOL to Matching Logic
45
From FOL to Matching Logic
Collapse symbols
46
From FOL to Matching Logic
Collapse symbols
47
From FOL to Matching Logic
Collapse terms and predicates
48
From FOL to Matching Logic
Collapse terms and predicates
49
From FOL to Matching Logic
Interpret symbols into powerdomains
50
From FOL to Matching Logic
Interpret symbols into powerdomains
51
Matching Logic vs. FOL Simpler (no need to distinguish operations from predicates) Same expressiveness, but patterns more succinct than FOL formulae When fixing model(s), quite a convenient notation (captures separation logic)
52
Bottom Line No distinction between function and predicate symbols; they build patterns In models, patterns evaluate to sets of elements, namely those that match them Examples , written , matched by singletons of sort s matched by successor of x elements are either zero or successors matched by all linked lists in the heap starting with pointer x and holding mathematical sequence S
53
Useful Sugar Derived constructs Definedness, equality, membership
Either the empty set (when empty) or otherwise the total set (when non-empty) Sort subscripts and superscripts can be inferred from the context, so we do not write them
54
We write it using the functional notation:
More Sugar Functions (recovering “operation” symbols) Similarly we can define partial functions, total relations, etc. Algebraic specification and FOL subsumed notationally. For example: We write it using the functional notation:
55
Matching Logic vs. Separation Logic
Matching logic achieves separation through matching at the structural (term) level, not through special logical connectives (*). Separation logic = Matching logic [heap] OOPSLA’12, RTA’15 Matching logic realizes separation at all levels of the configuration, not only in the heap the heap was only 1 out of the 120 cells in C’s def.
56
Examples of Patterns |A| >1
x points to sequence A with |A|>1, and the reversed sequence rev(A) has been output untrusted()can only be called from trusted() |A| >1
57
Reduction to Predicate Logic=
(see paper) Like FOL, ML can be reduced to predicate logic Explosion in size, new quantifiers; impractical
Similar presentations
© 2025 SlidePlayer.com. Inc.
All rights reserved.