-
Quest Complete: the Holy Grail of Gradual Security
Authors:
Tianyu Chen,
Jeremy G. Siek
Abstract:
Languages with gradual information-flow control combine static and dynamic techniques to prevent security leaks. Gradual languages should satisfy the gradual guarantee: programs that only differ in the precision of their type annotations should behave the same modulo cast errors. Unfortunately, Toro et al. [2018] identify a tension between the gradual guarantee and information security; they were…
▽ More
Languages with gradual information-flow control combine static and dynamic techniques to prevent security leaks. Gradual languages should satisfy the gradual guarantee: programs that only differ in the precision of their type annotations should behave the same modulo cast errors. Unfortunately, Toro et al. [2018] identify a tension between the gradual guarantee and information security; they were unable to satisfy both properties in the language $\mathrm{GSL}_\mathsf{Ref}$ and had to settle for only satisfying information-flow security. Azevedo de Amorim et al. [2020] show that by sacrificing type-guided classification, one obtains a language that satisfies both noninterference and the gradual guarantee. Bichhawat et al. [2021] show that both properties can be satisfied by sacrificing the no-sensitive-upgrade mechanism, replacing it with a static analysis.
In this paper we present a language design, $λ_{\mathtt{IFC}}^\star$, that satisfies both noninterference and the gradual guarantee without making any sacrifices. We keep the type-guided classification of $\mathrm{GSL}_\mathsf{Ref}$ and use the standard no-sensitive-upgrade mechanism to prevent implicit flows through mutable references. The key to the design of $λ_{\mathtt{IFC}}^\star$ is to walk back the decision in $\mathrm{GSL}_\mathsf{Ref}$ to include the unknown label $\star$ among the runtime security labels. We give a formal definition of $λ_{\mathtt{IFC}}^\star$, prove the gradual guarantee, and prove noninterference. Of technical note, the semantics of $λ_{\mathtt{IFC}}^\star$ is the first gradual information-flow control language to be specified using coercion calculi (a la Henglein), thereby expanding the coercion-based theory of gradual typing.
△ Less
Submitted 9 April, 2024; v1 submitted 4 December, 2023;
originally announced December 2023.
-
Mechanized Noninterference for Gradual Security
Authors:
Tianyu Chen,
Jeremy G. Siek
Abstract:
This paper presents the first machine-checked proof of noninterference for a language with gradual information-flow control, thereby establishing a rock solid foundation for secure programming languages that give programmers the choice between runtime versus compile-time enforcement. Along the way we uncovered a flaw in one of the noninterference proofs in the literature, and give a counterexample…
▽ More
This paper presents the first machine-checked proof of noninterference for a language with gradual information-flow control, thereby establishing a rock solid foundation for secure programming languages that give programmers the choice between runtime versus compile-time enforcement. Along the way we uncovered a flaw in one of the noninterference proofs in the literature, and give a counterexample for one of the main lemmas. The particular language studied in this paper, $λ_{\mathtt{SEC}}^\star$, is based on the GLIO language of Azevedo de Amorim et al. [2020]. To make the design more accessible to other researchers, this paper contributes the first traditional semantics for the language, that is, we define compilation from $λ_{\mathtt{SEC}}^\star$ to a cast calculus and design a reduction semantics for the latter that includes blame tracking. In addition to the proof of noninterference, we also mechanize proofs of type safety, determinism, and that compilation preserves types.
△ Less
Submitted 28 November, 2022;
originally announced November 2022.
-
Parameterized Cast Calculi and Reusable Meta-theory for Gradually Typed Lambda Calculi
Authors:
Jeremy G. Siek
Abstract:
The research on gradual typing has led to many variations on the Gradually Typed Lambda Calculus (GTLC) of Siek and Taha (2006) and its underlying cast calculus. For example, Wadler and Findler (2009) added blame tracking, Siek et al. (2009) investigated alternate cast evaluation strategies, and Herman et al. (2010) replaced casts with coercions for space-efficiency. The meta-theory for the GTLC h…
▽ More
The research on gradual typing has led to many variations on the Gradually Typed Lambda Calculus (GTLC) of Siek and Taha (2006) and its underlying cast calculus. For example, Wadler and Findler (2009) added blame tracking, Siek et al. (2009) investigated alternate cast evaluation strategies, and Herman et al. (2010) replaced casts with coercions for space-efficiency. The meta-theory for the GTLC has also expanded beyond type safety to include blame safety (Tobin-Hochstadt and Felleisen 2006), space consumption (Herman et al. 2010), and the gradual guarantees (Siek et al. 2015). These results have been proven for some variations of the GTLC but not others. Furthermore, researchers continue to develop variations on the GTLC but establishing all of the meta-theory for new variations is time consuming.
This article identifies abstractions that capture similarities between many cast calculi in the form of two parameterized cast calculi, one for the purposes of language specification and the other to guide space-efficient implementations. The article then develops reusable meta-theory for these two calculi, proving type safety, blame safety, the gradual guarantees, and space consumption. Finally, the article instantiates this meta-theory for eight cast calculi including five from the literature and three new calculi. All of these definitions and theorems, including the two parameterized calculi, the reusable meta-theory, and the eight instantiations, are mechanized in Agda making extensive use of module parameters and dependent records to define the abstractions.
△ Less
Submitted 15 May, 2021; v1 submitted 30 January, 2020;
originally announced January 2020.
-
Transitivity of Subtyping for Intersection Types
Authors:
Jeremy G. Siek
Abstract:
The subtyping rules for intersection types traditionally employ a transitivity rule (Barendregt et al. 1983), which means that subtyping does not satisfy the subformula property, making it more difficult to use in filter models for compiler verification. Laurent develops a sequent-style subtyping system, without transitivity, and proves transitivity via a sequence of six lemmas that culminate in c…
▽ More
The subtyping rules for intersection types traditionally employ a transitivity rule (Barendregt et al. 1983), which means that subtyping does not satisfy the subformula property, making it more difficult to use in filter models for compiler verification. Laurent develops a sequent-style subtyping system, without transitivity, and proves transitivity via a sequence of six lemmas that culminate in cut-elimination (2018). This article develops a subtyping system in regular style that omits transitivity and provides a direct proof of transitivity, significantly reducing the length of the proof, exchanging the six lemmas for just one. Inspired by Laurent's system, the rule for function types is essentially the $β$-soundness property. The new system satisfies the "subformula conjunction property": every type occurring in the derivation of $A <: B$ is a subformula of $A$ or $B$, or an intersection of such subformulas. The article proves that the new subtyping system is equivalent to that of Barendregt, Coppo, and Dezani-Ciancaglini.
△ Less
Submitted 15 May, 2020; v1 submitted 23 June, 2019;
originally announced June 2019.
-
Optimizing and Evaluating Transient Gradual Typing
Authors:
Michael M. Vitousek,
Jeremy G. Siek,
Avik Chaudhuri
Abstract:
Gradual typing enables programmers to combine static and dynamic typing in the same language. However, ensuring a sound interaction between the static and dynamic parts can incur significant runtime cost. In this paper, we perform a detailed performance analysis of the transient gradual typing approach implemented in Reticulated Python, a gradually typed variant of Python. The transient approach i…
▽ More
Gradual typing enables programmers to combine static and dynamic typing in the same language. However, ensuring a sound interaction between the static and dynamic parts can incur significant runtime cost. In this paper, we perform a detailed performance analysis of the transient gradual typing approach implemented in Reticulated Python, a gradually typed variant of Python. The transient approach inserts lightweight checks throughout a program rather than installing proxies on higher order values. We show that, when running Reticulated Python and the transient approach on CPython, performance decreases as programs evolve from dynamic to static types, up to a 6x slowdown compared to equivalent Python programs.
To reduce this overhead, we design a static analysis and optimization that removes redundant runtime checks. The optimization employs a static type inference algorithm that solves traditional subtyping constraints and also a new kind of check constraint. We evaluate the resulting performance and find that for many programs, the efficiency of partially typed programs is close to their untyped counterparts, removing most of the slowdown of transient checks. Finally, we measure the efficiency of Reticulated Python programs when running on PyPy, a tracing JIT. We find that combining PyPy with our type inference algorithm reduces the overall overhead to zero.
△ Less
Submitted 20 February, 2019;
originally announced February 2019.
-
Efficient Gradual Typing
Authors:
Andre Kuhlenschmidt,
Deyaaeldeen Almahallawi,
Jeremy G. Siek
Abstract:
Gradual typing combines static and dynamic typing in the same program. One would hope that the performance in a gradually typed language would range between that of a dynamically typed language and a statically typed language. Existing implementations of gradually typed languages have not achieved this goal due to overheads associated with runtime casts. Takikawa et al. (2016) report up to 100…
▽ More
Gradual typing combines static and dynamic typing in the same program. One would hope that the performance in a gradually typed language would range between that of a dynamically typed language and a statically typed language. Existing implementations of gradually typed languages have not achieved this goal due to overheads associated with runtime casts. Takikawa et al. (2016) report up to 100$\times$ slowdowns for partially typed programs. In this paper we present a compiler, named Grift, for evaluating implementation techniques for gradual typing. We take a straightforward but surprisingly unexplored implementation approach for gradual typing, that is, ahead-of-time compilation to native assembly code with carefully chosen runtime representations and space-efficient coercions.
Our experiments show that this approach achieves performance on par with OCaml on statically typed programs and performance between that of Gambit and Racket on untyped programs. On partially typed code, the geometric mean ranges from 0.42$\times$ to 2.36$\times$ that of (untyped) Racket across the benchmarks. We implement casts using the coercions of Siek, Thiemann, and Wadler (2015). This technique eliminates all catastrophic slowdowns without introducing significant overhead. Across the benchmarks, coercions range from 15% slower (fft) to almost 2$\times$ faster (matmult) than regular casts. We also implement the monotonic references of Siek et al. (2015). Monotonic references eliminate all overhead in statically typed code, and for partially typed code, they are faster than proxied references, sometimes up to 1.48$\times$.
△ Less
Submitted 18 February, 2018;
originally announced February 2018.
-
Revisiting Elementary Denotational Semantics
Authors:
Jeremy G. Siek
Abstract:
Operational semantics have been enormously successful, in large part due to its flexibility and simplicity, but they are not compositional. Denotational semantics, on the other hand, are compositional but the lattice-theoretic models are complex and difficult to scale to large languages. However, there are elementary models of the $λ$-calculus that are much less complex: by Coppo, Dezani-Ciancagli…
▽ More
Operational semantics have been enormously successful, in large part due to its flexibility and simplicity, but they are not compositional. Denotational semantics, on the other hand, are compositional but the lattice-theoretic models are complex and difficult to scale to large languages. However, there are elementary models of the $λ$-calculus that are much less complex: by Coppo, Dezani-Ciancaglini, and Salle (1979), Engeler (1981), and Plotkin (1993).
This paper takes first steps toward answering the question: can elementary models be good for the day-to-day work of language specification, mechanization, and compiler correctness? The elementary models in the literature are simple, but they are not as intuitive as they could be. To remedy this, we create a new model that represents functions literally as finite graphs. Regarding mechanization, we give the first machine-checked proof of soundness and completeness of an elementary model with respect to an operational semantics. Regarding compiler correctness, we define a polyvariant inliner for the call-by-value $λ$-calculus and prove that its output is contextually equivalent to its input. Toward scaling elementary models to larger languages, we formulate our semantics in a monadic style, give a semantics for System F with general recursion, and mechanize the proof of type soundness.
△ Less
Submitted 20 October, 2017; v1 submitted 12 July, 2017;
originally announced July 2017.
-
Well-Typed Languages are Sound
Authors:
Matteo Cimini,
Dale Miller,
Jeremy G. Siek
Abstract:
Type soundness is an important property of modern programming languages. In this paper we explore the idea that "well-typed languages are sound": the idea that the appropriate typing discipline over language specifications guarantees that the language is type sound. We instantiate this idea for a certain class of languages defined using small step operational semantics by ensuring the progress and…
▽ More
Type soundness is an important property of modern programming languages. In this paper we explore the idea that "well-typed languages are sound": the idea that the appropriate typing discipline over language specifications guarantees that the language is type sound. We instantiate this idea for a certain class of languages defined using small step operational semantics by ensuring the progress and preservation theorems. Our first contribution is a syntactic discipline for organizing and restricting language specifications so that they automatically satisfy the progress theorem. This discipline is not novel but makes explicit the way expert language designers have been organizing a certain class of languages for long time. We give a formal account of this discipline by representing language specifications as (higher-order) logic programs and by giving a meta type system over that collection of formulas. Our second contribution is a methodology and meta type system for guaranteeing that languages satisfy the preservation theorem. Ultimately, we proved that language specifications that conform to our meta type systems are guaranteed to be type sound. We have implemented these ideas in the TypeSoundnessCertifier, a tool that takes language specifications in the form of logic programs and type checks them according to our meta type systems. For those languages that pass our type checker, our tool automatically produces a proof of type soundness that can be machine-checked by the Abella proof assistant. For those languages that fail our type checker, the tool pinpoints the design mistakes that hinder type soundness. We have applied the TypeSoundnessCertifier to a large number of programming languages, including those with recursive types, polymorphism, letrec, exceptions, lists and other common types and operators.
△ Less
Submitted 15 November, 2016;
originally announced November 2016.
-
Gradual Typing in an Open World
Authors:
Michael M. Vitousek,
Jeremy G. Siek
Abstract:
Gradual typing combines static and dynamic typing in the same language, offering the benefits of both to programmers. Static typing provides error detection and strong guarantees while dynamic typing enables rapid prototyping and flexible programming idioms. For programmers to fully take advantage of a gradual type system, however, they must be able to trust their type annotations, and so runtime…
▽ More
Gradual typing combines static and dynamic typing in the same language, offering the benefits of both to programmers. Static typing provides error detection and strong guarantees while dynamic typing enables rapid prototyping and flexible programming idioms. For programmers to fully take advantage of a gradual type system, however, they must be able to trust their type annotations, and so runtime checks must be performed at the boundaries of static and dynamic code to ensure that static types are respected. Higher order and mutable values cannot be completely checked at these boundaries, and so additional checks must be performed at their use sites. Traditionally, this has been achieved by installing wrappers or proxies on such values that moderate the flow of data between static and dynamic, but these can cause problems if the language supports comparison of object identity or has a foreign function interface.
Reticulated Python is a gradually typed variant of Python implemented via a source-to-source translator for Python 3. It implements a proxy-free alternative design named transient casts. This paper presents a formal semantics for transient casts and shows that not only are they sound, but they work in an open-world setting in which the Reticulated translator has only been applied to some of the program; the rest is untranslated Python. We formalize this open world soundness property and use Coq to prove that it holds for Anthill Python, a calculus that models Reticulated Python.
△ Less
Submitted 26 October, 2016;
originally announced October 2016.
-
Monotonic References for Gradual Typing
Authors:
Jeremy G. Siek,
Michael M. Vitousek
Abstract:
We describe an alternative approach to handling mutable references (aka. pointers) within a gradually typed language that has different efficiency characteristics than the prior approach of Herman et al. [2010]. In particular, we reduce the costs of reading and writing through references in statically typed regions of code. We reduce the costs to be the same as they would in a statically typed lan…
▽ More
We describe an alternative approach to handling mutable references (aka. pointers) within a gradually typed language that has different efficiency characteristics than the prior approach of Herman et al. [2010]. In particular, we reduce the costs of reading and writing through references in statically typed regions of code. We reduce the costs to be the same as they would in a statically typed language, that is, simply the cost of a load or store instruction (for primitive data types). This reduction in cost is especially important for programmers who would like to use gradual typing to facilitate transitioning from a dynamically-typed prototype of an algorithm to a statically-typed, high-performance implementation. The programmers we have in mind are scientists and engineers who currently prototype in Matlab and then manually translate their algorithms into Fortran. We present the static and dynamic semantics for mutable references and a mechanized proof of type safety using the Isabelle proof assistant.
△ Less
Submitted 12 July, 2014; v1 submitted 2 December, 2013;
originally announced December 2013.
-
Modular Type-Safety Proofs using Dependant Types
Authors:
Christopher Schwaab,
Jeremy G. Siek
Abstract:
While methods of code abstraction and reuse are widespread and well researched, methods of proof abstraction and reuse are still emerging. We consider the use of dependent types for this purpose, introducing a completely mechanical approach to proof composition. We show that common techniques for abstracting algorithms over data structures naturally translate to abstractions over proofs. We first…
▽ More
While methods of code abstraction and reuse are widespread and well researched, methods of proof abstraction and reuse are still emerging. We consider the use of dependent types for this purpose, introducing a completely mechanical approach to proof composition. We show that common techniques for abstracting algorithms over data structures naturally translate to abstractions over proofs. We first introduce a language composed of a series of smaller language components tied together by standard techniques from Malcom (1990). We proceed by giving proofs of type preservation for each language component and show that the basic ideas used in composing the syntactic data structures can be applied to their semantics as well.
△ Less
Submitted 2 August, 2012;
originally announced August 2012.
-
Reliable Generation of High-Performance Matrix Algebra
Authors:
Geoffrey Belter,
Elizabeth Jessup,
Thomas Nelson,
Boyana Norris,
Jeremy G. Siek
Abstract:
Scientific programmers often turn to vendor-tuned Basic Linear Algebra Subprograms (BLAS) to obtain portable high performance. However, many numerical algorithms require several BLAS calls in sequence, and those successive calls result in suboptimal performance. The entire sequence needs to be optimized in concert. Instead of vendor-tuned BLAS, a programmer could start with source code in Fortran…
▽ More
Scientific programmers often turn to vendor-tuned Basic Linear Algebra Subprograms (BLAS) to obtain portable high performance. However, many numerical algorithms require several BLAS calls in sequence, and those successive calls result in suboptimal performance. The entire sequence needs to be optimized in concert. Instead of vendor-tuned BLAS, a programmer could start with source code in Fortran or C (e.g., based on the Netlib BLAS) and use a state-of-the-art optimizing compiler. However, our experiments show that optimizing compilers often attain only one-quarter the performance of hand-optimized code. In this paper we present a domain-specific compiler for matrix algebra, the Build to Order BLAS (BTO), that reliably achieves high performance using a scalable search algorithm for choosing the best combination of loop fusion, array contraction, and multithreading for data parallelism. The BTO compiler generates code that is between 16% slower and 39% faster than hand-optimized code.
△ Less
Submitted 5 May, 2012;
originally announced May 2012.
-
The C++0x "Concepts" Effort
Authors:
Jeremy G. Siek
Abstract:
C++0x is the working title for the revision of the ISO standard of the C++ programming language that was originally planned for release in 2009 but that was delayed to 2011. The largest language extension in C++0x was "concepts", that is, a collection of features for constraining template parameters. In September of 2008, the C++ standards committee voted the concepts extension into C++0x, but the…
▽ More
C++0x is the working title for the revision of the ISO standard of the C++ programming language that was originally planned for release in 2009 but that was delayed to 2011. The largest language extension in C++0x was "concepts", that is, a collection of features for constraining template parameters. In September of 2008, the C++ standards committee voted the concepts extension into C++0x, but then in July of 2009, the committee voted the concepts extension back out of C++0x.
This article is my account of the technical challenges and debates within the "concepts" effort in the years 2003 to 2009. To provide some background, the article also describes the design space for constrained parametric polymorphism, or what is colloquially know as constrained generics. While this article is meant to be generally accessible, the writing is aimed toward readers with background in functional programming and programming language theory. This article grew out of a lecture at the Spring School on Generic and Indexed Programming at the University of Oxford, March 2010.
△ Less
Submitted 29 December, 2011;
originally announced January 2012.
-
Well-typed Islands Parse Faster
Authors:
Erik Silkensen,
Jeremy G. Siek
Abstract:
This paper addresses the problem of specifying and parsing the syntax of domain-specific languages (DSLs) in a modular, user-friendly way. That is, we want to enable the design of composable DSLs that combine the natural syntax of external DSLs with the easy implementation of internal DSLs. The challenge in parsing composable DSLs is that the composition of several (individually unambiguous) langu…
▽ More
This paper addresses the problem of specifying and parsing the syntax of domain-specific languages (DSLs) in a modular, user-friendly way. That is, we want to enable the design of composable DSLs that combine the natural syntax of external DSLs with the easy implementation of internal DSLs. The challenge in parsing composable DSLs is that the composition of several (individually unambiguous) languages is likely to contain ambiguities. In this paper, we present the design of a system that uses a type-oriented variant of island parsing to efficiently parse the syntax of composable DSLs. In particular, we show how type-oriented island parsing is constant time with respect to the number of DSLs imported. We also show how to use our tool to implement DSLs on top of a host language such as Typed Racket.
△ Less
Submitted 29 December, 2011;
originally announced January 2012.
-
Effects for Funargs
Authors:
Jeremy G. Siek,
Michael M. Vitousek,
Jonathan D. Turner
Abstract:
Stack allocation and first-class functions don't naturally mix together. In this paper we show that a type and effect system can be the detergent that helps these features form a nice emulsion. Our interest in this problem comes from our work on the Chapel language, but this problem is also relevant to lambda expressions in C++ and blocks in Objective C. The difficulty in mixing first-class functi…
▽ More
Stack allocation and first-class functions don't naturally mix together. In this paper we show that a type and effect system can be the detergent that helps these features form a nice emulsion. Our interest in this problem comes from our work on the Chapel language, but this problem is also relevant to lambda expressions in C++ and blocks in Objective C. The difficulty in mixing first-class functions and stack allocation is a tension between safety, efficiency, and simplicity. To preserve safety, one must worry about functions outliving the variables they reference: the classic upward funarg problem. There are systems which regain safety but lose programmer-predictable efficiency, and ones that provide both safety and efficiency, but give up simplicity by exposing regions to the programmer. In this paper we present a simple design that combines a type and effect system, for safety, with function-local storage, for control over efficiency.
△ Less
Submitted 29 December, 2011;
originally announced January 2012.
-
A Language for Generic Programming in the Large
Authors:
Jeremy G. Siek,
Andrew Lumsdaine
Abstract:
Generic programming is an effective methodology for developing reusable software libraries. Many programming languages provide generics and have features for describing interfaces, but none completely support the idioms used in generic programming. To address this need we developed the language G. The central feature of G is the concept, a mechanism for organizing constraints on generics that is…
▽ More
Generic programming is an effective methodology for developing reusable software libraries. Many programming languages provide generics and have features for describing interfaces, but none completely support the idioms used in generic programming. To address this need we developed the language G. The central feature of G is the concept, a mechanism for organizing constraints on generics that is inspired by the needs of modern C++ libraries. G provides modular type checking and separate compilation (even of generics). These characteristics support modular software development, especially the smooth integration of independently developed components. In this article we present the rationale for the design of G and demonstrate the expressiveness of G with two case studies: porting the Standard Template Library and the Boost Graph Library from C++ to G. The design of G shares much in common with the concept extension proposed for the next C++ Standard (the authors participated in its design) but there are important differences described in this article.
△ Less
Submitted 16 August, 2007;
originally announced August 2007.