Monadic Refinement Types for Verifying JavaScript Programs
Researchers have developed several special-purpose type systems and program logics to analyze JavaScript and other dynamically typed programming languages. Still, no prior system can precisely reason about both higher-order programs and mutable state; each system comes with its own delicate soundness proof (when such proofs are provided at all); and tools based on these theories (when they exist) are a significant implementation burden.
This paper shows that JavaScript programs can be verified using a general-purpose verification tool—in our case, F*, a dependently typed dialect of ML. Our methodology consists of a few steps. First, we extend prior work on LambdaJS (Guha et al.) by translating JavaScript programs to F*. Within F*, we type pure JavaScript terms using a refinement of the type dyn, an algebraic datatype for dynamically typed values, where the refinement recovers more precise type information. Stateful expressions are typed using the Hoare state monad. Relying on a general-purpose weakest pre-condition calculus for this monad, we obtain higher-order verification conditions for JavaScript programs that can be discharged (via a novel encoding) by an off-the-shelf automated theorem prover. Our approach enjoys a fully mechanized proof of soundness, by virtue of the soundness of F*.
We report on experiments that apply our tool chain to verify a collection of web browser extensions for the absence of JavaScript runtime errors. We conclude that, despite commonly held misgivings about JavaScript, automated verification for a sizable subset of the language is feasible. Our work opens the door to applying a wealth of research in automated program verification techniques to JavaScript programs.