skip to main content

Modular specification and verification of closures in Rust

Published:15 October 2021Publication History
Skip Abstract Section

Abstract

Closures are a language feature supported by many mainstream languages, combining the ability to package up references to code blocks with the possibility of capturing state from the environment of the closure's declaration. Closures are powerful, but complicate understanding and formal reasoning, especially when closure invocations may mutate objects reachable from the captured state or from closure arguments.

This paper presents a novel technique for the modular specification and verification of closure-manipulating code in Rust. Our technique combines Rust's type system guarantees and novel specification features to enable formal verification of rich functional properties. It encodes higher-order concerns into a first-order logic, which enables automation via SMT solvers. Our technique is implemented as an extension of the deductive verifier Prusti, with which we have successfully verified many common idioms of closure usage.

Skip Supplemental Material Section

Supplemental Material

Auxiliary Presentation Video

This is the OOPSLA 2021 presentation video for our paper, "Modular Specification and Verification of Closures in Rust". This video: - contains a short introduction of closures and why they are difficult in a verification context; - highlights some cases where Rust's ownership type system makes the problem more manageable; - describes 3 of the issues we address with our paper and the solutions we apply: history invariants, specification entailments, and call descriptions; and - briefly describes our implementation and its evaluation.

References

  1. Vytautas Astrauskas, Christoph Matheja, Federico Poli, Peter Müller, and Alexander J. Summers. 2020. How do programmers use unsafe Rust? Proc. ACM Program. Lang., 4, OOPSLA (2020), Article 136, 11, 27 pages. https://doi.org/10.1145/3428204 Google ScholarGoogle ScholarDigital LibraryDigital Library
  2. Vytautas Astrauskas, Peter Müller, Federico Poli, and Alexander J. Summers. 2019. Leveraging Rust types for modular specification and verification. Proc. ACM Program. Lang., 3, OOPSLA (2019), Article 147, Oct., 30 pages. https://doi.org/10.1145/3360573 Google ScholarGoogle ScholarDigital LibraryDigital Library
  3. Mike Barnett, Bor-Yuh Evan Chang, Robert DeLine, Bart Jacobs, and K. Rustan M. Leino. 2006. Boogie: A Modular Reusable Verifier for Object-Oriented Programs. In Formal Methods for Components and Objects, Frank S. de Boer, Marcello M. Bonsangue, Susanne Graf, and Willem-Paul de Roever (Eds.) (LNCS, Vol. 4111). Springer, Berlin, Heidelberg. 364–387. https://doi.org/10.1007/11804192_17 Google ScholarGoogle ScholarDigital LibraryDigital Library
  4. Arthur Charguéraud and François Pottier. 2008. Functional translation of a calculus of capabilities. In ICFP. Association for Computing Machinery, New York, NY, USA. 213–224. https://doi.org/10.1145/1411204.1411235 Google ScholarGoogle ScholarDigital LibraryDigital Library
  5. Ernie Cohen, Mark A. Hillebrand, Stephan Tobies, Michał Moskal, and Wolfram Schulte. 2015. Verifying C Programs: A VCC Tutorial. https://bit.ly/32BkCWN Working draft, version 0.2.Google ScholarGoogle Scholar
  6. Ádám Darvas and K. Rustan M. Leino. 2007. Practical Reasoning About Invocations and Implementations of Pure Methods. In Fundamental Approaches to Software Engineering, Matthew B. Dwyer and Antónia Lopes (Eds.) (LNCS, Vol. 4422). Springer, Berlin, Heidelberg. 336–351. https://doi.org/10.1007/978-3-540-71289-3_26 Google ScholarGoogle ScholarCross RefCross Ref
  7. Leonardo Mendonça de Moura and Nikolaj Bjørner. 2007. Efficient E-Matching for SMT Solvers. In Automated Deduction – CADE-21, Frank Pfenning (Ed.). 4603, Springer, 183–198. https://doi.org/10.1007/978-3-540-73595-3_13 Google ScholarGoogle ScholarDigital LibraryDigital Library
  8. Krishna K. Dhara and Gary T. Leavens. 1996. Forcing behavioral subtyping through specification inheritance. In Proceedings of IEEE 18th International Conference on Software Engineering. IEEE Computer Society Press, Los Alamitos, CA, USA. 258–267. https://doi.org/10.1109/ICSE.1996.493421 Google ScholarGoogle ScholarCross RefCross Ref
  9. Ana Nora Evans, Bradford Campbell, and Mary Lou Soffa. 2020. Is Rust Used Safely by Software Developers? In Proceedings of the ACM/IEEE 42nd International Conference on Software Engineering (ICSE ’20). Association for Computing Machinery, New York, NY, USA. 246–257. https://doi.org/10.1145/3377811.3380413 Google ScholarGoogle ScholarDigital LibraryDigital Library
  10. Robert Bruce Findler and Matthias Felleisen. 2002. Contracts for higher-order functions. In ICFP. ACM, New York, NY, USA. 48–59. https://doi.org/10.1145/581478.581484 Google ScholarGoogle ScholarDigital LibraryDigital Library
  11. David Harel, Dexter Kozen, and Jerzy Tiuryn. 2002. Dynamic Logic. In Handbook of Philosophical Logic, Dov M. Gabbay and Franz Guenthner (Eds.) (Handbook of Philosophical Logic, Vol. 4). Springer Netherlands, Dordrecht. 99–217. https://doi.org/10.1007/978-94-017-0456-4_2 Google ScholarGoogle ScholarCross RefCross Ref
  12. Kohei Honda, Nobuko Yoshida, and Martin Berger. 2005. An Observationally Complete Program Logic for Imperative Higher-Order Frame Rules. In 20th Annual IEEE Symposium on Logic in Computer Science (LICS ’05). IEEE Computer Society, Los Alamitos, CA, USA. 270–279. https://doi.org/10.1109/LICS.2005.5 Google ScholarGoogle ScholarDigital LibraryDigital Library
  13. Bart Jacobs, Jan Smans, Pieter Philippaerts, Frédéric Vogels, Willem Penninckx, and Frank Piessens. 2011. VeriFast: A Powerful, Sound, Predictable, Fast Verifier for C and Java. In NFM 2011, Mihaela Gheorghiu Bobaru, Klaus Havelund, Gerard J. Holzmann, and Rajeev Joshi (Eds.) (LNCS, Vol. 6617). Springer, 41–55. https://doi.org/10.1007/978-3-642-20398-5_4 Google ScholarGoogle ScholarCross RefCross Ref
  14. Johannes Kanig and Jean-Christophe Filliâtre. 2009. Who: a verifier for effectful higher-order programs. In Proceedings of the 2009 ACM SIGPLAN workshop on ML (ML ’09). Association for Computing Machinery, New York, NY, USA. 39–48. https://doi.org/10.1145/1596627.1596634 Google ScholarGoogle ScholarDigital LibraryDigital Library
  15. Ioannis T. Kassios. 2006. Dynamic Frames: Support for Framing, Dependencies and Sharing Without Restrictions. In FM 2006: Formal Methods, Jayadev Misra, Tobias Nipkow, and Emil Sekerinski (Eds.). Springer, Berlin, Heidelberg. 268–283. https://doi.org/10.1007/11813040_19 Google ScholarGoogle ScholarDigital LibraryDigital Library
  16. Ioannis T. Kassios and Peter Müller. 2010. Specification and verification of closures. ETH Zürich. https://doi.org/10.3929/ETHZ-A-006843251 Google ScholarGoogle ScholarCross RefCross Ref
  17. Steve Klabnik and Carol Nichols. 2021. The Rust Programming Language. https://doc.rust-lang.org/book/Google ScholarGoogle Scholar
  18. Neelakantan R. Krishnaswami. 2012. Verifying Higher-Order Imperative Programs with Higher-Order Separation Logic. Ph.D. Dissertation. Carnegie Mellon University. https://doi.org/10.1184/R1/6724235.v1 Google ScholarGoogle ScholarCross RefCross Ref
  19. Peter J. Landin. 1964. The Mechanical Evaluation of Expressions. Comput. J., 6, 4 (1964), 1 Jan., 308–320. https://doi.org/10.1093/comjnl/6.4.308 Google ScholarGoogle ScholarCross RefCross Ref
  20. Gary T. Leavens and David A. Naumann. 2015. Behavioral Subtyping, Specification Inheritance, and Modular Reasoning. ACM Trans. Program. Lang. Syst., 37, 4 (2015), Article 13, Aug., 88 pages. https://doi.org/10.1145/2766446 Google ScholarGoogle ScholarDigital LibraryDigital Library
  21. Gary T Leavens, Erik Poll, Curtis Clifton, Yoonsik Cheon, Clyde Ruby, David Cok, Peter Müller, Joseph Kiniry, Patrice Chalin, and Daniel M Zimmerman. 2008. JML reference manual.Google ScholarGoogle Scholar
  22. K. Rustan M. Leino. 2010. Dafny: An Automatic Program Verifier for Functional Correctness. In Logic for Programming, Artificial Intelligence, and Reasoning, Edmund M. Clarke and Andrei Voronkov (Eds.) (LNCS, Vol. 6355). Springer, Berlin, Heidelberg. 348–370. https://doi.org/10.1007/978-3-642-17511-4_20 Google ScholarGoogle ScholarCross RefCross Ref
  23. Barbara H. Liskov and Jeannette M. Wing. 1994. A behavioral notion of subtyping. ACM Trans. Program. Lang. Syst., 16, 6 (1994), Nov., 1811–1841. https://doi.org/10.1145/197320.197383 Google ScholarGoogle ScholarDigital LibraryDigital Library
  24. Nicholas D. Matsakis. 2013. The Case of the Recurring Closure. http://smallcultfollowing.com/babysteps/blog/2013/04/30/the-case-of-the-recurring-closureGoogle ScholarGoogle Scholar
  25. Nicholas D. Matsakis and Felix S. Klock. 2014. The Rust language. Ada Lett., 34, 3 (2014), Oct., 103–104. https://doi.org/10.1145/2692956.2663188 Google ScholarGoogle ScholarDigital LibraryDigital Library
  26. Davood Mazinanian, Ameya Ketkar, Nikolaos Tsantalis, and Danny Dig. 2017. Understanding the use of lambda expressions in Java. Proc. ACM Program. Lang., 1, OOPSLA (2017), Article 85, Oct., 31 pages. https://doi.org/10.1145/3133909 Google ScholarGoogle ScholarDigital LibraryDigital Library
  27. Peter Müller, Malte Schwerhoff, and Alexander J. Summers. 2016. Viper: A Verification Infrastructure for Permission-Based Reasoning. In Verification, Model Checking, and Abstract Interpretation, Barbara Jobstmann and K. Rustan M. Leino (Eds.) (LNCS, Vol. 9583). Springer, Berlin, Heidelberg. 41–62. https://doi.org/10.1007/978-3-662-49122-5_2 Google ScholarGoogle ScholarDigital LibraryDigital Library
  28. Aleksandar Nanevski, Greg Morrisett, and Lars Birkedal. 2008. Hoare type theory, polymorphism and separation. J. Funct. Prog., 18, 5–6 (2008), Sept., 865–911. https://doi.org/10.1017/S0956796808006953 Google ScholarGoogle ScholarDigital LibraryDigital Library
  29. Aleksandar Nanevski, Greg Morrisett, Avraham Shinnar, Paul Govereau, and Lars Birkedal. 2008. Ynot: dependent types for imperative programs. In ICFP. Association for Computing Machinery, New York, NY, USA. 229–240. https://doi.org/10.1145/1411204.1411237 Google ScholarGoogle ScholarDigital LibraryDigital Library
  30. Martin Nordio, Cristiano Calcagno, Bertrand Meyer, Peter Müller, and Julian Tschannen. 2010. Reasoning about Function Objects. In Objects, Models, Components, Patterns, Jan Vitek (Ed.) (LNCS, Vol. 6141). Springer, Berlin, Heidelberg. 79–96. https://doi.org/10.1007/978-3-642-13953-6_5 Google ScholarGoogle ScholarCross RefCross Ref
  31. Peter O’Hearn, John Reynolds, and Hongseok Yang. 2001. Local Reasoning about Programs that Alter Data Structures. In Computer Science Logic, Laurent Fribourg (Ed.) (LNCS, Vol. 2142). Springer, Berlin, Heidelberg. 1–19. https://doi.org/10.1007/3-540-44802-0_1 Google ScholarGoogle ScholarCross RefCross Ref
  32. Peter W. O’Hearn and John C. Reynolds. 2000. From Algol to polymorphic linear lambda-calculus. J. ACM, 47, 1 (2000), Jan., 167–223. https://doi.org/10.1145/331605.331611 Google ScholarGoogle ScholarDigital LibraryDigital Library
  33. Mário José Parreira Pereira. 2018. Tools and Techniques for the Verification of Modular Stateful Code. Ph.D. Dissertation. Université Paris Saclay. https://tel.archives-ouvertes.fr/tel-01980343/documentGoogle ScholarGoogle Scholar
  34. Yann Régis-Gianas and François Pottier. 2008. A Hoare Logic for Call-by-Value Functional Programs. In Mathematics of Program Construction, Philippe Audebaud and Christine Paulin-Mohring (Eds.) (LNCS, Vol. 5133). Springer, Berlin, Heidelberg. 305–335. https://doi.org/10.1007/978-3-540-70594-9_17 Google ScholarGoogle ScholarDigital LibraryDigital Library
  35. Steve M. Shaner, Gary T. Leavens, and David A. Naumann. 2007. Modular verification of higher-order methods with mandatory calls specified by model programs. In OOPSLA. Association for Computing Machinery, New York, NY, USA. 351–368. https://doi.org/10.1145/1297027.1297053 Google ScholarGoogle ScholarDigital LibraryDigital Library
  36. Jan Smans, Bart Jacobs, and Frank Piessens. 2010. Heap-Dependent Expressions in Separation Logic. In Formal Techniques for Distributed Systems, John Hatcliff and Elena Zucca (Eds.) (LNCS, Vol. 6117). Springer, Berlin, Heidelberg. 170–185. https://doi.org/10.1007/978-3-642-13464-7_14 Google ScholarGoogle ScholarDigital LibraryDigital Library
  37. Jan Smans, Bart Jacobs, and Frank Piessens. 2012. Implicit Dynamic Frames. ACM Trans. Program. Lang. Syst., 34, 1 (2012), Article 2, May, 58 pages. https://doi.org/10.1145/2160910.2160911 Google ScholarGoogle ScholarDigital LibraryDigital Library
  38. Neelam Soundarajan and Stephen Fridella. 2004. Incremental Reasoning for Object Oriented Systems. In From Object-Orientation to Formal Methods, Olaf Owe, Stein Krogdahl, and Tom Lyche (Eds.) (LNCS, Vol. 2635). Springer, Berlin, Heidelberg. 302–333. https://doi.org/10.1007/978-3-540-39993-3_15 Google ScholarGoogle ScholarCross RefCross Ref
  39. Kasper Svendsen, Lars Birkedal, and Matthew Parkinson. 2010. Verifying Generics and Delegates. In ECOOP 2010 – Object-Oriented Programming, Theo D’Hondt (Ed.) (LNCS, Vol. 6183). Springer, Berlin, Heidelberg. 175–199. https://doi.org/10.1007/978-3-642-14107-2_9 Google ScholarGoogle ScholarCross RefCross Ref
  40. Nikhil Swamy, Joel Weinberger, Cole Schlesinger, Juan Chen, and Benjamin Livshits. 2013. Verifying higher-order programs with the Dijkstra monad. SIGPLAN Not., 48, 6 (2013), June, 387–398. https://doi.org/10.1145/2499370.2491978 Google ScholarGoogle ScholarDigital LibraryDigital Library
  41. Fabian Wolff. 2020. Verification of Closures in Rust Programs. Master’s thesis. ETH Zürich. https://doi.org/10.3929/ethz-b-000444764 Google ScholarGoogle ScholarCross RefCross Ref
  42. Fabian Wolff, Aurel Bílý, Christoph Matheja, Peter Müller, and Alexander J. Summers. 2021. Modular Specification and Verification of Closures in Rust (artefact). https://doi.org/10.5281/zenodo.5482557 Google ScholarGoogle ScholarDigital LibraryDigital Library
  43. Fabian Wolff, Aurel Bílý, Christoph Matheja, Peter Müller, and Alexander J. Summers. 2021. Prusti extension for closure verification. https://github.com/Aurel300/prusti-dev/tree/closure-oopsla-submission-2Google ScholarGoogle Scholar
  44. Nobuko Yoshida, Kohei Honda, and Martin Berger. 2007. Logical Reasoning for Higher-Order Functions with Local State. In Foundations of Software Science and Computational Structures, Helmut Seidl (Ed.) (LNCS, Vol. 4423). Springer, Berlin, Heidelberg. 361–377. https://doi.org/10.1007/978-3-540-71389-0_26 Google ScholarGoogle ScholarCross RefCross Ref

Index Terms

  1. Modular specification and verification of closures in Rust

                  Recommendations

                  Comments

                  Login options

                  Check if you have access through your login credentials or your institution to get full access on this article.

                  Sign in

                  Full Access

                  PDF Format

                  View or Download as a PDF file.

                  PDF

                  eReader

                  View online with eReader.

                  eReader
                  About Cookies On This Site

                  We use cookies to ensure that we give you the best experience on our website.

                  Learn more

                  Got it!