+ All Categories
Home > Documents > Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might...

Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might...

Date post: 18-Aug-2020
Category:
Upload: others
View: 0 times
Download: 0 times
Share this document with a friend
82
David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software
Transcript
Page 1: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

David Van HornMatthew Might

Scalable Abstractionsfor Trustworthy Software

Page 2: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Demonstrate our approach can be efficient

Demonstrate our approach can be modular

Sketch how we can verify rich properties

Purpose

Page 3: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Semantics

Analysis

Page 4: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Analysis

SemanticsManifest.xml

Manifest.xml

Page 5: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Analysis

SemanticsManifest.xml

Manifest.xml

Compile-time manifest checking

Page 6: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Analysis

SemanticsSpecification

Compile-time specification

checking

Specification

Page 7: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Analysis

Semantics

Has to be:- precise- fast- scalable to rich specifications

Compile-time specification

checking

Specification

Specification

Page 8: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Efficiency

Page 9: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Analysis

Semantics

Page 10: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Analysis

Semantics

But is it fast?

Page 11: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Good news: it’s blazingly fast...

Page 12: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Good news: it’s blazingly fast... ...to implement.

Page 13: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Good news: it’s blazingly fast... ...to implement.

Good news (for people who love bad news):it’s dog slow to run.

Page 14: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Good news: it’s blazingly fast... ...to implement.

Good news (for people who love bad news):it’s dog slow to run.

Good news (for people who love good news):we can make it faster, systematically.

Page 15: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

2

= YDU (x)| OLW (l)| ODP (x, e)| DSS (e, e)| LI (e, e, e)

x = [ | \ | . . .l = z | b | oz = � | � | !� | . . .b = WW | IIo = ]HUR? | DGG� | VXE� | . . .

!

(l,!,") = a,! ! [a "# {"}] a /$ !

(!, x, v) = #[x "# a],! ! [a "# {v}]

Page 16: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

2

= YDU (x)| OLW (l)| ODP (x, e)| DSS (e, e)| LI (e, e, e)

x = [ | \ | . . .l = z | b | oz = � | � | !� | . . .b = WW | IIo = ]HUR? | DGG� | VXE� | . . .

!

(l,!,") = a,! ! [a "# {"}] a /$ !

(!, x, v) = #[x "# a],! ! [a "# {v}]

It’s just Core Java

Page 17: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(e) = {! | HY (e,!,!, PW) !"## !}

HY (YDU (x), ",#,$) !"# FR ($, v,#) v $ #("(x))

HY (OLW (l), ",#,$) !"# FR ($, l,#)

HY (ODP (x, e), ",#,$) !"# FR ($, FORV (x, e, "),#)

HY (DSS (e0, e1), ",#,$) !"# HY (e0, ",#!, DU (e1, ", a)) a,#! = (#,$)

HY (LI (e0, e1, e2), ",#,$) !"# HY (e0, ",#!, IL (e1, e2, ", a)) a,#! = (#,$)

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (e, ", a), v,#) !"# HY (e, ",#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,$,#) $ $ #(a)

FR (IL (e0, e1, ", a), WW,#) !"# HY (e0, ",#,$) $ $ #(a)

FR (IL (e0, e1, ", a), II,#) !"# HY (e1, ",#,$) $ $ #(a)

DS (FORV (x, e, "), v,#,$) !"# HY!(e, "!,#!,$) "!,#!, ! = (#, x, v)

DS (o, v,#,$) !"# FR ($, v!,#) $ $ #(a) v! $ !(o, v)

2

a !" !

k

k

= . . .

= . . .

Page 18: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(e) = {! | HY (e,!,!, PW) !"## !}

HY (YDU (x), ",#,$) !"# FR ($, v,#) v $ #("(x))

HY (OLW (l), ",#,$) !"# FR ($, l,#)

HY (ODP (x, e), ",#,$) !"# FR ($, FORV (x, e, "),#)

HY (DSS (e0, e1), ",#,$) !"# HY (e0, ",#!, DU (e1, ", a)) a,#! = (#,$)

HY (LI (e0, e1, e2), ",#,$) !"# HY (e0, ",#!, IL (e1, e2, ", a)) a,#! = (#,$)

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (e, ", a), v,#) !"# HY (e, ",#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,$,#) $ $ #(a)

FR (IL (e0, e1, ", a), WW,#) !"# HY (e0, ",#,$) $ $ #(a)

FR (IL (e0, e1, ", a), II,#) !"# HY (e1, ",#,$) $ $ #(a)

DS (FORV (x, e, "), v,#,$) !"# HY!(e, "!,#!,$) "!,#!, ! = (#, x, v)

DS (o, v,#,$) !"# FR ($, v!,#) $ $ #(a) v! $ !(o, v)

2

a !" !

k

k

= . . .

= . . .

Arbiter of context sensitivity

Arbiter of polyvariance

Page 19: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

�� DSSO � � �;� ��; �! �6HWRI ;�� �! ��6HWRI ;� �! �6HWRI ;�����GHILQH ��DSSO I� V�

�IRU�IROG �>L �VHW�@��>[ �LQ�VHW V�@��VHW�XQLRQ L �I [����

�� &DOFXODWH IL[SRLQW RI �DSSO I���� IL[ � � �;� ��; �! �6HWRI ;�� �6HWRI ;� �! �6HWRI ;����GHILQH �IL[ I V�

�OHW ORRS ��DFFXP �VHW�� �IURQW V��

2

= YDU (x)| OLW (l)| ODP (x, e)| DSS (e, e)| LI (e, e, e)

x = [ | \ | . . .l = z | b | oz = � | � | !� | . . .b = WW | IIo = ]HUR? | DGG� | VXE� | . . .

!

(!,",#) = a," ! [a "# {#}] a /$ "

(", x, v) = $[x "# a]," ! [a "# {v}] a /$ "

Interpreter:

Abstract interpreter (0CFA):

Page 20: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(e) = {! | HY (e,!,!, PW) !"## !}

HY (YDU (x), ",#,$) !"# FR ($, v,#) v $ #("(x))

HY (OLW (l), ",#,$) !"# FR ($, l,#)

HY (ODP (x, e), ",#,$) !"# FR ($, FORV (x, e, "),#)

HY (DSS (e0, e1), ",#,$) !"# HY (e0, ",#!, DU (e1, ", a)) a,#! = (#,$)

HY (LI (e0, e1, e2), ",#,$) !"# HY (e0, ",#!, IL (e1, e2, ", a)) a,#! = (#,$)

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (e, ", a), v,#) !"# HY (e, ",#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,$,#) $ $ #(a)

FR (IL (e0, e1, ", a), WW,#) !"# HY (e0, ",#,$) $ $ #(a)

FR (IL (e0, e1, ", a), II,#) !"# HY (e1, ",#,$) $ $ #(a)

DS (FORV (x, e, "), v,#,$) !"# HY!(e, "!,#!,$) "!,#!, ! = (#, x, v)

DS (o, v,#,$) !"# FR ($, v!,#) $ $ #(a) v! $ !(o, v)

2

a !" !

k

k

= . . .

= . . .

Page 21: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

�� 6WDWH ! 6HWRI 6WDWH�GHILQH �VWHS VWDWH��PDWFK VWDWH>�HY H N��PDWFK H>�YDU! [� �IRU�VHW ��Y �ORRNXS [��� �FR N Y��@>�OLW! O� �VHW �FR N Q��@>�ODP! [ H� �VHW �FR N �FORV [ H ���@>�DSS! I H��GHILQH�YDOXHV � D� �SXVK VWDWH���VHW �HY I �DU H D���@>�LIH! H� H� H���GHILQH�YDOXHV � D� �SXVK VWDWH���VHW �HY H� �LIN H� H� D���@�@

>�FR N Y��PDWFK N>PW �VHW �DQV Y��@>�DU! H � �VHW �HY H �IQ Y O���@>�IQ! I� �IRU�VHW ��N �JHW�FRQW O��� �DS I Y N��@>�IL! F D ��IRU�VHW ��N �JHW�FRQW O����HY �LI Y F D� N��@�@

>�DS IXQ D N��PDWFK IXQ>�FORV O [ H ��GHILQH�YDOXHV � � �ELQG VWDWH���VHW �HY H N��@>�" RS" R��IRU �VHW ��N �JHW�FRQW O��

�Y �! R �OLVW Y�����FR N Y��

>B �VHW�@��@��

Page 22: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

�� DSSO � � �;� ��; �! �6HWRI ;�� �! ��6HWRI ;� �! �6HWRI ;�����GHILQH ��DSSO I� V�

�IRU�IROG �>L �VHW�@��>[ �LQ�VHW V�@��VHW�XQLRQ L �I [����

�� &DOFXODWH IL[SRLQW RI �DSSO I���� IL[ � � �;� ��; �! �6HWRI ;�� �6HWRI ;� �! �6HWRI ;����GHILQH �IL[ I V�

�OHW ORRS ��DFFXP �VHW�� �IURQW V���LI �VHW�HPSW\" IURQW�

DFFXP�OHW ��QHZ�IURQW ��DSSO I� IURQW����ORRS �VHW�XQLRQ DFFXP IURQW�

�VHW�VXEWUDFW QHZ�IURQW DFFXP������

�� 6WDWHA �FRQV �6HW &RQI� 6WRUH�

�� �6WDWH �! 6HWRI 6WDWH� �! 6WDWHA �! ^ 6WDWHA `�GHILQH ��ZLGH�VWHS VWHS� VWDWH�

�PDWFK VWDWH>�FRQV FV ��GHILQH VV ��DSSO VWHS�

�IRU�VHW �>F FV@� �F�!V F �����VHW �FRQV �IRU�VHW �>V VV@� �V�!F V��

�MRLQ�VWRUHV VV���@��

Generic fixpoint calculator

Page 23: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

�� ([SU ! 6HWRI 6WDWH�GHILQH �HYDO H�

�IL[ VWHS �VHW �LQM H����

�� DSSO � � �;� ��; �! �6HWRI ;�� �! ��6HWRI ;� �! �6HWRI ;�����GHILQH ��DSSO I� V�

�IRU�IROG �>L �VHW�@��>[ �LQ�VHW V�@��VHW�XQLRQ L �I [����

�� &DOFXODWH IL[SRLQW RI �DSSO I���� IL[ � � �;� ��; �! �6HWRI ;�� �6HWRI ;� �! �6HWRI ;����GHILQH �IL[ I V�

�OHW ORRS ��DFFXP �VHW�� �IURQW V���LI �VHW�HPSW\" IURQW�

DFFXP�OHW ��QHZ�IURQW ��DSSO I� IURQW����ORRS �VHW�XQLRQ DFFXP IURQW�

�VHW�VXEWUDFW QHZ�IURQW DFFXP������

�� 6WDWHA �FRQV �6HW &RQI� 6WRUH�

�� �6WDWH �! 6HWRI 6WDWH� �! 6WDWHA �! ^ 6WDWHA `�GHILQH ��ZLGH�VWHS VWHS� VWDWH�

�PDWFK VWDWH>�FRQV FV ��GHILQH VV ��DSSO VWHS�

�IRU�VHW �>F FV@� �F�!V F �����VHW �FRQV �IRU�VHW �>V VV@� �V�!F V��

�MRLQ�VWRUHV VV���@��

Page 24: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Page 25: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�GHILQH !�" �& �I� �& �[� �I �I [�����

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Page 26: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

interface Function<X,Y> { Y apply(X x); }

class Two<X,X> implements Function<Function<X,X>,Function<X,X>> {

apply(final Function<X,Y> f) = { return new Function<X,X>() { X apply(X x) { return f.apply(f.apply(x)); }; } }}

// (λ (f) (λ (x) (f (f x))))

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�GHILQH !�" �& �I� �& �[� �I �I [�����

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Page 27: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�GHILQH !�" �& �I� �& �[� �I �I [�����

�GHILQH SUHG�& �Q�

�& �UI��& �U[�

���Q �& �J� �& �K� �K �J UI������& �L� U[���& �LG� LG������

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Page 28: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Page 29: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Time: ∞

Page 30: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

<E₀,R₀,[0↦{8}],K₀>

<E₁,R₁,[1↦{6}],K₁>

<E₂,R₂,[1↦{3}],K₂>

Page 31: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

{<E₁,R₁,K₁> <E₁,R₁,K₁>

<E₂,R₂,K₂>},[0↦{8},1↦{3,6}]

Page 32: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

�� ([SU ! 6HWRI 6WDWH�GHILQH �HYDO H�

�IL[ VWHS �VHW �LQM H����

�� DSSO � � �;� ��; �! �6HWRI ;�� �! ��6HWRI ;� �! �6HWRI ;�����GHILQH ��DSSO I� V�

�IRU�IROG �>L �VHW�@��>[ �LQ�VHW V�@��VHW�XQLRQ L �I [����

�� &DOFXODWH IL[SRLQW RI �DSSO I���� IL[ � � �;� ��; �! �6HWRI ;�� �6HWRI ;� �! �6HWRI ;����GHILQH �IL[ I V�

�OHW ORRS ��DFFXP �VHW�� �IURQW V���LI �VHW�HPSW\" IURQW�

DFFXP�OHW ��QHZ�IURQW ��DSSO I� IURQW����ORRS �VHW�XQLRQ DFFXP IURQW�

�VHW�VXEWUDFW QHZ�IURQW DFFXP������

�� 6WDWHA �FRQV �6HW &RQI� 6WRUH�

�� �6WDWH �! 6HWRI 6WDWH� �! 6WDWHA �! ^ 6WDWHA `�GHILQH ��ZLGH�VWHS VWHS� VWDWH�

�PDWFK VWDWH>�FRQV FV ��GHILQH VV ��DSSO VWHS�

�IRU�VHW �>F FV@� �F�!V F �����VHW �FRQV �IRU�VHW �>V VV@� �V�!F V��

�MRLQ�VWRUHV VV���@��

Generic store widening

Page 33: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

�� ([SU ! 6HWRI 6WDWH�GHILQH �HYDO H�

�IL[ VWHS �VHW �LQM H����

�� DSSO � � �;� ��; �! �6HWRI ;�� �! ��6HWRI ;� �! �6HWRI ;�����GHILQH ��DSSO I� V�

�IRU�IROG �>L �VHW�@��>[ �LQ�VHW V�@��VHW�XQLRQ L �I [����

�� &DOFXODWH IL[SRLQW RI �DSSO I���� IL[ � � �;� ��; �! �6HWRI ;�� �6HWRI ;� �! �6HWRI ;����GHILQH �IL[ I V�

�OHW ORRS ��DFFXP �VHW�� �IURQW V���LI �VHW�HPSW\" IURQW�

DFFXP�OHW ��QHZ�IURQW ��DSSO I� IURQW����ORRS �VHW�XQLRQ DFFXP IURQW�

�VHW�VXEWUDFW QHZ�IURQW DFFXP������

�� 6WDWHA �FRQV �6HW &RQI� 6WRUH�

�� �6WDWH �! 6HWRI 6WDWH� �! 6WDWHA �! ^ 6WDWHA `�GHILQH ��ZLGH�VWHS VWHS� VWDWH�

�PDWFK VWDWH>�FRQV FV ��GHILQH VV ��DSSO VWHS�

�IRU�VHW �>F FV@� �F�!V F �����VHW �FRQV �IRU�VHW �>V VV@� �V�!F V��

�MRLQ�VWRUHV VV���@��

Time: 551571ms (≈9.2m)

Generic store widening

Page 34: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Precision PreservingRecipe

Page 35: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(e) = {! | HY (e,!,!, PW) !"## !}

HY (YDU (x), ",#,$) !"# FR ($, v,#) v $ #("(x))

HY (OLW (l), ",#,$) !"# FR ($, l,#)

HY (ODP (x, e), ",#,$) !"# FR ($, FORV (x, e, "),#)

HY (DSS (e0, e1), ",#,$) !"# HY (e0, ",#!, DU (e1, ", a)) a,#! = (#,$)

HY (LI (e0, e1, e2), ",#,$) !"# HY (e0, ",#!, IL (e1, e2, ", a)) a,#! = (#,$)

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (e, ", a), v,#) !"# HY (e, ",#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,$,#) $ $ #(a)

FR (IL (e0, e1, ", a), WW,#) !"# HY (e0, ",#,$) $ $ #(a)

FR (IL (e0, e1, ", a), II,#) !"# HY (e1, ",#,$) $ $ #(a)

DS (FORV (x, e, "), v,#,$) !"# HY!(e, "!,#!,$) "!,#!, ! = (#, x, v)

DS (o, v,#,$) !"# FR ($, v!,#) $ $ #(a) v! $ !(o, v)

2

a !" !

k

k

= . . .

= . . .

Lazy non-determinism

Page 36: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(e) = {! | HY (e,!,!, PW) !"## !}

HY (YDU (x), ",#,$) !"# FR ($, v,#) v $ #("(x))

HY (OLW (l), ",#,$) !"# FR ($, l,#)

HY (ODP (x, e), ",#,$) !"# FR ($, FORV (x, e, "),#)

HY (DSS (e0, e1), ",#,$) !"# HY (e0, ",#!, DU (e1, ", a)) a,#! = (#,$)

HY (LI (e0, e1, e2), ",#,$) !"# HY (e0, ",#!, IL (e1, e2, ", a)) a,#! = (#,$)

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (e, ", a), v,#) !"# HY (e, ",#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,$,#) $ $ #(a)

FR (IL (e0, e1, ", a), WW,#) !"# HY (e0, ",#,$) $ $ #(a)

FR (IL (e0, e1, ", a), II,#) !"# HY (e1, ",#,$) $ $ #(a)

DS (FORV (x, e, "), v,#,$) !"# HY!(e, "!,#!,$) "!,#!, ! = (#, x, v)

DS (o, v,#,$) !"# FR ($, v!,#) $ $ #(a) v! $ !(o, v)

2

a !" !

k

k

= . . .

= . . .

Lazy non-determinism

Page 37: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(e) = {! | HY (e,!,!, PW) !"## !}

HY (YDU (x), ",#,$) !"# FR ($, v,#) v $ #("(x))

HY (OLW (l), ",#,$) !"# FR ($, l,#)

HY (ODP (x, e), ",#,$) !"# FR ($, FORV (x, e, "),#)

HY (DSS (e0, e1), ",#,$) !"# HY (e0, ",#!, DU (e1, ", a)) a,#! = (#,$)

HY (LI (e0, e1, e2), ",#,$) !"# HY (e0, ",#!, IL (e1, e2, ", a)) a,#! = (#,$)

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (e, ", a), v,#) !"# HY (e, ",#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,$,#) $ $ #(a)

FR (IL (e0, e1, ", a), WW,#) !"# HY (e0, ",#,$) $ $ #(a)

FR (IL (e0, e1, ", a), II,#) !"# HY (e1, ",#,$) $ $ #(a)

DS (FORV (x, e, "), v,#,$) !"# HY!(e, "!,#!,$) "!,#!, ! = (#, x, v)

DS (o, v,#,$) !"# FR ($, v!,#) $ $ #(a) v! $ !(o, v)

2

a !" !

k

k

= . . .

= . . .

Lazy non-determinism

Page 38: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Time: 551571ms (≈9.2m)

Page 39: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Time: 551571ms (≈9.2m)Time: 255397ms (≈4.3m)

Page 40: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

HY

DSS (DSS (DSS (x, e1), e2), e3)

HY (DSS (DSS (DSS (x, e1), e2), e3), !,",#0)

!"# HY (DSS (DSS (x, e1), e2), !, DU (e3, !, a1),#1)

!"# HY (DSS (x, e1), !, DU (e2, !, a2),#2)

!"# HY (x, !, DU (e1, !, a3),#3)

!"# FR (DU (e1, !), v,#4) v $ #(!(a))

#4 = #0 % {[a1 !# {"}], [a2 !# DU (e3, !, a1)][a3 !# DU (e2, !, a2)]

!YDU (x)" = !(",#,$).FR ($, v,#) v ! #("(x))

!OLW (l)" = !(",#,$).FR ($, l,#)

!ODP (x, e)" = !(",#,$).FR ($, FORV (x, !e", "),#)!DSS (e0, e1)" = ! (",#,$).!e0" (",#!, DU (!e1", ", a)) a,#! = (#,$)

!LI (e0, e1, e2)" = ! (",#,$).!e0"!(",#!, IL (!e1", !e2", ", a)) a,#! = (#,$)

Page 41: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

HY

DSS (DSS (DSS (x, e1), e2), e3)

HY (DSS (DSS (DSS (x, e1), e2), e3), !,",#0)

!"# HY (DSS (DSS (x, e1), e2), !, DU (e3, !, a1),#1)

!"# HY (DSS (x, e1), !, DU (e2, !, a2),#2)

!"# HY (x, !, DU (e1, !, a3),#3)

!"# FR (DU (e1, !), v,#4) v $ #(!(a))

#4 = #0 % {[a1 !# {"}], [a2 !# DU (e3, !, a1)][a3 !# DU (e2, !, a2)]

!YDU (x)" = !(",#,$).FR ($, v,#) v ! #("(x))

!OLW (l)" = !(",#,$).FR ($, l,#)

!ODP (x, e)" = !(",#,$).FR ($, FORV (x, !e", "),#)!DSS (e0, e1)" = ! (",#,$).!e0" (",#!, DU (!e1", ", a)) a,#! = (#,$)

!LI (e0, e1, e2)" = ! (",#,$).!e0"!(",#!, IL (!e1", !e2", ", a)) a,#! = (#,$)

HY

DSS (DSS (DSS (x, e1), e2), e3)

HY (DSS (DSS (DSS (x, e1), e2), e3), !,",#0)

!"# HY (DSS (DSS (x, e1), e2), !, DU (e3, !, a1),#1)

!"# HY (DSS (x, e1), !, DU (e2, !, a2),#2)

!"# HY (x, !, DU (e1, !, a3),#3)

!"# FR (DU (e1, !), v,#4) v $ #(!(a))

#4 = #0 % {[a1 !# {"}], [a2 !# DU (e3, !, a1)][a3 !# DU (e2, !, a2)]

!YDU (x)" = !(",#,$).FR ($, v,#) v ! #("(x))

!OLW (l)" = !(",#,$).FR ($, l,#)

!ODP (x, e)" = !(",#,$).FR ($, FORV (x, !e", "),#)!DSS (e0, e1)" = ! (",#,$).!e0" (",#!, DU (!e1", ", a)) a,#! = (#,$)

!LI (e0, e1, e2)" = ! (",#,$).!e0"!(",#!, IL (!e1", !e2", ", a)) a,#! = (#,$)

Page 42: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Time: 551571ms (≈9.2m)Time: 255397ms (≈4.3m)

Page 43: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(!,",#) = !," ! [! "# {#}](", x, v) = $[x "# x]," ! [x "# {v}]

z + 1 $ %(DGG�, z) z % 1 $ %(VXE�, z)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

= $ %(DGG�, z) = $ %(VXE�, z)

WW $ %(]HUR?, =) II $ %(]HUR?, =)

WW $ %(]HUR?, �) II $ %(]HUR?, z) z &= �

�� PXOWLSOLFDWLRQ GLVWULEXWHV RYHU DGGLWLRQ��FKXUFK " ��PXOW !�"� ��SOXV !�"� !�"�����SOXV ��PXOW !�"� !�"�� ��PXOW !�"� !�"�����

FKXUFK "SUHG SOXV PXOW

N

Time: 551571ms (≈9.2m)Time: 255397ms (≈4.3m)Time: 31173ms (≈.5m)

Page 44: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(e) = {! | !e"(",!,!, PW) !"## !}

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (k, $, a), v,#) !"# k ($,#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,%,#) % $ #(a)

FR (IL (k0, k1, $, a), WW,#) !"# k0($,#,%) % $ #(a)

FR (IL (k0, k1, $, a), II,#) !"# k1($,#,%) % $ #(a)

DS (FORV (x, k, $), v,#,%) !"# k!($!,#!,%) $!,#!, ! = (#, x, v)

DS (o, v,#,%) !"# FR (%, v!,#) % $ #(a) v! $ !(o, v)

2

�� 6WDWHA �! 6WDWHA�� 6SHFLDOL]HG IURP ZLGH�VWHS � 6WDWHA �! 6WDWHA ߠ 6WDWHA �! 6WDWHA�GHILQH �ZLGH�VWHS�VSHFLDOL]HG VWDWH�

�PDWFK VWDWH>�FRQV FV��GHILQH�YDOXHV �FV ��IRU�IROG �>FV �VHW�@ > @�

�>F FV@��PDWFK �VWHS�FRPSLOHGA �FRQV F��

>�FRQV FV ��YDOXHV �VHW�XQLRQ FV FV � �MRLQ�VWRUH ��@���

�FRQV �VHW�XQLRQ FV FV ��@��

Specialized fixpoint computation

Time: 551571ms (≈9.2m)Time: 255397ms (≈4.3m)Time: 31173ms (≈.5m)

Page 45: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(e) = {! | !e"(",!,!, PW) !"## !}

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (k, $, a), v,#) !"# k ($,#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,%,#) % $ #(a)

FR (IL (k0, k1, $, a), WW,#) !"# k0($,#,%) % $ #(a)

FR (IL (k0, k1, $, a), II,#) !"# k1($,#,%) % $ #(a)

DS (FORV (x, k, $), v,#,%) !"# k!($!,#!,%) $!,#!, ! = (#, x, v)

DS (o, v,#,%) !"# FR (%, v!,#) % $ #(a) v! $ !(o, v)

2

�� 6WDWHA �! 6WDWHA�� 6SHFLDOL]HG IURP ZLGH�VWHS � 6WDWHA �! 6WDWHA ߠ 6WDWHA �! 6WDWHA�GHILQH �ZLGH�VWHS�VSHFLDOL]HG VWDWH�

�PDWFK VWDWH>�FRQV FV��GHILQH�YDOXHV �FV ��IRU�IROG �>FV �VHW�@ > @�

�>F FV@��PDWFK �VWHS�FRPSLOHGA �FRQV F��

>�FRQV FV ��YDOXHV �VHW�XQLRQ FV FV � �MRLQ�VWRUH ��@���

�FRQV �VHW�XQLRQ FV FV ��@��

Specialized fixpoint computation

Time: 551571ms (≈9.2m)Time: 255397ms (≈4.3m)Time: 31173ms (≈.5m)Time: 14212ms

Page 46: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

(e) = {! | !e"(",!,!, PW) !"## !}

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (k, $, a), v,#) !"# k ($,#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,%,#) % $ #(a)

FR (IL (k0, k1, $, a), WW,#) !"# k0($,#,%) % $ #(a)

FR (IL (k0, k1, $, a), II,#) !"# k1($,#,%) % $ #(a)

DS (FORV (x, k, $), v,#,%) !"# k!($!,#!,%) $!,#!, ! = (#, x, v)

DS (o, v,#,%) !"# FR (%, v!,#) % $ #(a) v! $ !(o, v)

2

�� 6WDWHA �! 6WDWHA�� 6SHFLDOL]HG IURP ZLGH�VWHS � 6WDWHA �! 6WDWHA ߠ 6WDWHA �! 6WDWHA�GHILQH �ZLGH�VWHS�VSHFLDOL]HG VWDWH�

�PDWFK VWDWH>�FRQV FV��GHILQH�YDOXHV �FV ��IRU�IROG �>FV �VHW�@ > @�

�>F FV@��PDWFK �VWHS�FRPSLOHGA �FRQV F��

>�FRQV FV ��YDOXHV �VHW�XQLRQ FV FV � �MRLQ�VWRUH ��@���

�FRQV �VHW�XQLRQ FV FV ��@��

Specialized fixpoint computation

Time: 551571ms (≈9.2m)Time: 255397ms (≈4.3m)Time: 31173ms (≈.5m)Time: 14212ms

Page 47: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Time: 14212ms

Computing with store diffs

(e) = {! | !e"(",!,!, PW) !"## !}

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (k, $, a), v,#) !"# k ($,#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,%,#) % $ #(a)

FR (IL (k0, k1, $, a), WW,#) !"# k0($,#,%) % $ #(a)

FR (IL (k0, k1, $, a), II,#) !"# k1($,#,%) % $ #(a)

DS (FORV (x, k, $), v,#,%) !"# k!($!,#!,%) $!,#!, ! = (#, x, v)

DS (o, v,#,%) !"# FR (%, v!,#) % $ #(a) v! $ !(o, v)

2

�� 6WDWHA �! 6WDWHA�� 6SHFLDOL]HG IURP ZLGH�VWHS � 6WDWHA �! 6WDWHA ߠ 6WDWHA �! 6WDWHA�GHILQH �ZLGH�VWHS�VSHFLDOL]HG VWDWH�

�PDWFK VWDWH>�FRQV FV��GHILQH�YDOXHV �FV ��IRU�IROG �>FV �VHW�@ > @�

�>F FV@��PDWFK �VWHS�FRPSLOHGA �FRQV F��

>�FRQV FV ��YDOXHV �VHW�XQLRQ FV FV � �MRLQ�VWRUH ��@���

�FRQV �VHW�XQLRQ FV FV ��@��

�� 6WDWHA �! 6WDWHA�� 6SHFLDOL]HG IURP ZLGH�VWHS � 6WDWHA �! 6WDWHA ߠ 6WDWHA �! 6WDWHA�GHILQH �ZLGH�VWHS�VSHFLDOL]HG VWDWH�

�PDWFK VWDWH>�FRQV FV��GHILQH�YDOXHV �FV �ޱ�IRU�IROG �>FV �VHW�@ ޱ< ��@�

�>F FV@��PDWFK �VWHS�FRPSLOHGA �FRQV F��

>�FRQV ޱ FV ��YDOXHV �VHW�XQLRQ FV FV � �DSSHQG ޱ ޱ��@���

�FRQV �XSGDWH ޱ � �VHW�XQLRQ FV FV ��@��

Page 48: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Time: 14212ms

Computing with store diffs

(e) = {! | !e"(",!,!, PW) !"## !}

FR (PW, Y,#) !"# DQV (#, v)

FR (DU (k, $, a), v,#) !"# k ($,#, IQ (v, a))

FR (IQ (u, a), v,#) !"# DS (v, u,%,#) % $ #(a)

FR (IL (k0, k1, $, a), WW,#) !"# k0($,#,%) % $ #(a)

FR (IL (k0, k1, $, a), II,#) !"# k1($,#,%) % $ #(a)

DS (FORV (x, k, $), v,#,%) !"# k!($!,#!,%) $!,#!, ! = (#, x, v)

DS (o, v,#,%) !"# FR (%, v!,#) % $ #(a) v! $ !(o, v)

2

�� 6WDWHA �! 6WDWHA�� 6SHFLDOL]HG IURP ZLGH�VWHS � 6WDWHA �! 6WDWHA ߠ 6WDWHA �! 6WDWHA�GHILQH �ZLGH�VWHS�VSHFLDOL]HG VWDWH�

�PDWFK VWDWH>�FRQV FV��GHILQH�YDOXHV �FV ��IRU�IROG �>FV �VHW�@ > @�

�>F FV@��PDWFK �VWHS�FRPSLOHGA �FRQV F��

>�FRQV FV ��YDOXHV �VHW�XQLRQ FV FV � �MRLQ�VWRUH ��@���

�FRQV �VHW�XQLRQ FV FV ��@��

�� 6WDWHA �! 6WDWHA�� 6SHFLDOL]HG IURP ZLGH�VWHS � 6WDWHA �! 6WDWHA ߠ 6WDWHA �! 6WDWHA�GHILQH �ZLGH�VWHS�VSHFLDOL]HG VWDWH�

�PDWFK VWDWH>�FRQV FV��GHILQH�YDOXHV �FV �ޱ�IRU�IROG �>FV �VHW�@ ޱ< ��@�

�>F FV@��PDWFK �VWHS�FRPSLOHGA �FRQV F��

>�FRQV ޱ FV ��YDOXHV �VHW�XQLRQ FV FV � �DSSHQG ޱ ޱ��@���

�FRQV �XSGDWH ޱ � �VHW�XQLRQ FV FV ��@��

Time: 668ms

Page 49: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

{ !v3, !v5, !v6} = 0001011

Time: 668ms

Page 50: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

{ !v3, !v5, !v6} = 0001011

Time: 668msTime: 342ms

Page 51: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

{ !v3, !v5, !v6} = 0001011

Time: 668msTime: 342ms

{ !v3, !v5, !v6} = 0001011

! = P|��ێ��0�� |�

Page 52: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

{ !v3, !v5, !v6} = 0001011

Time: 668msTime: 342ms

{ !v3, !v5, !v6} = 0001011

! = P|��ێ��0�� |�

Time: 112ms

Page 53: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

★ Lazy non-determinism★ Abstract compilation★ Specialized fixpoint★ Store diffs★ Finite sets as bit vectors★ Pre-allocation

Precision PreservingRecipe

Page 54: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

★ Lazy non-determinism★ Abstract compilation★ Specialized fixpoint★ Store diffs★ Finite sets as bit vectors★ Pre-allocation

Precision PreservingRecipe≈ 5000x improvement

Page 55: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Modularity★ Some programs are open★ Good components in bad languages★ Programs are big; analysis is hard★ Libraries matter

Page 56: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Analysis

Page 57: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Analysis

Think hard about modularity

Page 58: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Semantics

Analysis

Think hard about modularity

Page 59: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Semantics

Analysis

Think hard about modularity

Page 60: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

PCF

Page 61: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

2. Contracts and Contract PCFThe basic building block of our specification system isbehavioral software contracts. Originally introduced byMeyer [31], contracts are executable specifications that sit atthe boundary between software components. In a first-ordersetting, properly assessing which component violated a con-tract at run-time is straightforward. Matters are complicatedwhen higher-order values such as functions or objects are in-cluded in the language. Findler and Felleisen [17] introducedthe notion of blame and established a semantic frameworkfor properly assessing blame at run-time in a higher-orderlanguage, providing the theoretical basis for contract sys-tems such as Racket’s.

(module double(provide [dbl ((even? -> even?)

-> (even? -> even?))])(define dbl (! (f) (! (x) (f (f x))))))

> (dbl (! (x) 7))

top-level broke the contract on dbl;expected <even?>, given: 7

To illustrate, consider the program above, which consistsof a module and top-level expression. Module double pro-vides a dbl function that implements twice-iterated applica-tion, operating on functions on even numbers. The top-levelexpression makes use of the dbl function, but incorrectly—dbl is applied to a function that produces 7.

Contract checking and blame assignment in a higher-order program is complicated by the fact that it is not de-cidable in general whether the argument of dbl is a functionfrom and to even numbers. Thus, higher-order contracts arepushed down into delayed lower-order checks, but care mustbe taken to get blame right. In our example, the top-levelis blamed, and rightly so, even though even? witnesses theviolation when f is applied to x while executing dbl.

2.1 Contract PCFDimoulas et al. [12, 13] introduce Contract PCF as a corecalculus for the investigation of contracts, which we take asthe starting point for our model. CPCF extends PCF [33]with contracts for base values and first-class functions. Weprovide a brief recap of the syntax and semantics of CPCF.

Contracts for flat values, flat(E), employ predicates thatmay use the full expressive power of CPCF. Function con-tracts, C1 !" C2, consist of a pre-condition contract C1 forthe argument to the function and a post-condition contractC2 for the function’s result. Dependent function contracts,C1 !"!X.C2, bind X to the argument of the function in thepost-condition contract C2, and thus express a dependencybetween a function’s input and result. In the remainder of thepaper, we treat the non-dependent function contract C1 !"C2

as shorthand for C1 !"!X.C2 where X is fresh.

PCF with Contracts

Types T ::= B | T " T | con(T )Base types B ::= N | BTerms E ::= A | X | E E | µX :T .E | if E E E

| O1(E) | O2(E,E) | monf,ff (C,E)

Operations O1 ::= zero? | false? | . . .O2 ::= + | # | $ | % | . . .

Contracts C ::= flat(E) | C !"C | C !"!X :T.C

Answers A ::= V | E [blameff ]

Values V ::= !X :T.E | 0 | 1 | # 1 | . . . | tt | !Evaluation E ::= [ ] | E E | V E | O2(E , E) | O2(V, E)contexts | O1(E) | if E E E | monf,gh (C, E)

Semantics for PCF with Contracts E !#" E!

if tt E1 E2 !#" E1

if ! E1 E2 !#" E2

(!X :T.E) V !#" [V/X]E

µX :T .E !#" [µX :T .E/X]E

O(!V ) !#" A if "(O, !V ) = A

monf,gh (C1 !"!X :T.C2, V ) !#"!X :T.monf,gh (C2, (V mong,fh (C1, X)))

monf,gh (flat(E), V ) !#" if (E V ) V blamefh

A contract C is attached to an expression with the monitorconstruct monf,gh (C,E), which carries three labels: f , g, andh, denoting the names of components which may be blamedfor contract failure. (An implementation would synthesizethese names from the source code.) The monitor checksany interaction between the expression and its context is inaccordance with the contract.

Component labels play an important role in case a con-tract failure is detected during contract checking. In such acase, blame is assigned with the blamefg construct, whichstates that the component named f broke its contract with g.

CPCF is equipped with a standard type system for PCFplus the addition of a contract type con(T ), which denotesthe set of contracts for values of type T [12, 13]. The typesystem is straightforward, so for the sake of space, we deferthe details to an appendix (§A.1).

The semantics of CPCF are given as a call-by-value re-duction relation on programs. One-step reduction E !#" E!

is defined above, contextually closed over evaluation con-texts E ; its reflexive transitive closure is written E !#"" E!.

The first five cases of the reduction relation are stan-dard for PCF. The remaining two cases implement con-tract checking for function contracts and flat contracts, re-spectively. The monitor of a function contract on a func-tion reduces to a function that monitors its input with re-versed blame labels and monitors its output with the origi-

Page 62: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Symbolic PCF

Page 63: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

nal blame labels.1 The monitor of a flat contract reduces toan if-expression which tests whether the predicate holds. Ifit does, the value is returned. Otherwise, a contract error issignaled with appropriate blame.

3. Symbolic PCF with ContractsWe now present an extension to Contract PCF and its seman-tics that enriches the language with symbolic values, drawnfrom the language of contracts. The key idea of SCPCF isto take the values of CPCF as “pre”-values U and add a no-tion of an unknown values (of type T ), written “•T ”. Purelyunknown values have arbitrary behavior, but we refine un-knowns by attaching a set of contracts that specify an agree-ment between the program and the missing component. Suchrefinements can guide an operational characterization of aprogram. Pre-values are refined by a set of contracts to forma value, U/C, where C ranges over sets of contracts.

The high-level goal of the following semantics is to en-able the running of programs with unknown components.The main requirement is that the results of running suchcomputations should soundly and precisely approximate theresult of running that same program after replacing an un-known with any allowable value. More precisely, if a pro-gram involving some value V produces an answer A, thenabstracting away that value to an unknown should producean approximation of A:

if E [V ] !"## A and $ V : T , then E [•T ] !"## A!,

where A! “approximates” A.

Notation: Abstract (or synonymously: symbolic) values !Vrange over values of the form •T /C. Whenever the refine-ment of a value is irrelevant, we omit the C set. We writeV · C for U/C % {C} where V = U/C.

The semantics given below replace that of section 2,equipping the operational semantics with an interpretationof symbolic values. (The semantics of contract checking isdeferred for the moment.)

To do so requires two changes:

1. the ! relation must be extended to interpret operationswhen applied to symbolic values, and

2. the one-step reduction relation must be extended to thecases of (1) branching on a (potentially) symbolic value,and (2) applying a symbolic function.

3.1 Operations on symbolic valuesTypically, the interpretation of operations is defined by afunction ! that maps an operation and argument values to

1 For simplicity, we present the so-called lax dependent contract rule; ourimplementation uses indy [13], obtained by replacing the contractum with:

!X :T.monf,gh ([monf,hh (C1, X)/X]C2, V mong,fh (C1, X)).

Symbolic PCF with Contracts

Prevalues U ::= •T | !X :T.E | 0 | 1 | " 1 | . . . | tt | !Values V ::= U/{C, . . . }

Semantics for Symbolic PCF with Contracts E !"# E!

if V E1 E2 !"# E1 if !(false?, V ) & !

if V E1 E2 !"# E2 if !(false?, V ) & tt

(!X :T.E) V !"# [V/X]E

µX :T .E !"# [µX :T .E/X]E

O("V ) !"# A if !(O, "V ) & A

(•T"T !/C) V !"# •T !

/{[V/X]C2 | C1 !#!X :T.C2 ' C}(•T"T !

/C) V !"# havocT V

an answer, e.g. !(add1, 0) = 1. The result of applying aprimitive may either be a value in case the operation isdefined on its given arguments, or blame in case it is not.

The extension of ! to interpret symbolic values is largelystraightforward. It starts by generalizing ! from a functionfrom an operation and values to an answer, to a relationbetween operations, values, and answers (or equivalently, toa function from an operation and values to sets of answers).This enables multiple results when a symbolic value does notconvey enough information to uniquely determine a singleresult. For example, !(zero?, 0) = {tt}, but !(zero?, •N) ={tt,!}. From here, all that remains is adding appropriateclauses to the definition of ! for handling symbolic values.As an example, the definition includes:

!(+, V1, V2) & •N, if V1 or V2 = •N/C.

The remaining cases are similarly straightforward.The revised reduction relation reduces an operation, non-

deterministically, to any answer in the ! relation.

3.2 Branching on symbolic valuesThe shift from the semantics of section 2 to section 3 also in-volves what appears to be a cosmetic change in the reductionof conditionals, e.g., from

if tt E1 E2 !"# E1

toif V E1 E2 !"# E1 if !(false?, V ) & !.

In the absence of symbolic values, the two relations areequivalent, but once symbolic values are introduced, thelatter handles branching on potentially symbolic values bydeferring to ! to determine if V is possibly true. Conse-quently branching on •B results in both E1 and E2 since!(false?, •B) = {tt,!}. Without this slight refactoring forconditionals, additional cases for the reduction relation arerequired, and these cases would largely mimic the existing

Page 64: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

nal blame labels.1 The monitor of a flat contract reduces toan if-expression which tests whether the predicate holds. Ifit does, the value is returned. Otherwise, a contract error issignaled with appropriate blame.

3. Symbolic PCF with ContractsWe now present an extension to Contract PCF and its seman-tics that enriches the language with symbolic values, drawnfrom the language of contracts. The key idea of SCPCF isto take the values of CPCF as “pre”-values U and add a no-tion of an unknown values (of type T ), written “•T ”. Purelyunknown values have arbitrary behavior, but we refine un-knowns by attaching a set of contracts that specify an agree-ment between the program and the missing component. Suchrefinements can guide an operational characterization of aprogram. Pre-values are refined by a set of contracts to forma value, U/C, where C ranges over sets of contracts.

The high-level goal of the following semantics is to en-able the running of programs with unknown components.The main requirement is that the results of running suchcomputations should soundly and precisely approximate theresult of running that same program after replacing an un-known with any allowable value. More precisely, if a pro-gram involving some value V produces an answer A, thenabstracting away that value to an unknown should producean approximation of A:

if E [V ] !"## A and $ V : T , then E [•T ] !"## A!,

where A! “approximates” A.

Notation: Abstract (or synonymously: symbolic) values !Vrange over values of the form •T /C. Whenever the refine-ment of a value is irrelevant, we omit the C set. We writeV · C for U/C % {C} where V = U/C.

The semantics given below replace that of section 2,equipping the operational semantics with an interpretationof symbolic values. (The semantics of contract checking isdeferred for the moment.)

To do so requires two changes:

1. the ! relation must be extended to interpret operationswhen applied to symbolic values, and

2. the one-step reduction relation must be extended to thecases of (1) branching on a (potentially) symbolic value,and (2) applying a symbolic function.

3.1 Operations on symbolic valuesTypically, the interpretation of operations is defined by afunction ! that maps an operation and argument values to

1 For simplicity, we present the so-called lax dependent contract rule; ourimplementation uses indy [13], obtained by replacing the contractum with:

!X :T.monf,gh ([monf,hh (C1, X)/X]C2, V mong,fh (C1, X)).

Symbolic PCF with Contracts

Prevalues U ::= •T | !X :T.E | 0 | 1 | " 1 | . . . | tt | !Values V ::= U/{C, . . . }

Semantics for Symbolic PCF with Contracts E !"# E!

if V E1 E2 !"# E1 if !(false?, V ) & !

if V E1 E2 !"# E2 if !(false?, V ) & tt

(!X :T.E) V !"# [V/X]E

µX :T .E !"# [µX :T .E/X]E

O("V ) !"# A if !(O, "V ) & A

(•T"T !/C) V !"# •T !

/{[V/X]C2 | C1 !#!X :T.C2 ' C}(•T"T !

/C) V !"# havocT V

if •T E1 E2 !"# E1

if •T E1 E2 !"# E2

(•T"T !) V !"# •T !

(•T"T !) V !"# havocT V

an answer, e.g. !(add1, 0) = 1. The result of applying aprimitive may either be a value in case the operation isdefined on its given arguments, or blame in case it is not.

The extension of ! to interpret symbolic values is largelystraightforward. It starts by generalizing ! from a functionfrom an operation and values to an answer, to a relationbetween operations, values, and answers (or equivalently, toa function from an operation and values to sets of answers).This enables multiple results when a symbolic value does notconvey enough information to uniquely determine a singleresult. For example, !(zero?, 0) = {tt}, but !(zero?, •N) ={tt,!}. From here, all that remains is adding appropriateclauses to the definition of ! for handling symbolic values.As an example, the definition includes:

!(+, V1, V2) & •N, if V1 or V2 = •N/C.

The remaining cases are similarly straightforward.The revised reduction relation reduces an operation, non-

deterministically, to any answer in the ! relation.

3.2 Branching on symbolic valuesThe shift from the semantics of section 2 to section 3 also in-volves what appears to be a cosmetic change in the reductionof conditionals, e.g., from

if tt E1 E2 !"# E1

toif V E1 E2 !"# E1 if !(false?, V ) & !.

In the absence of symbolic values, the two relations areequivalent, but once symbolic values are introduced, thelatter handles branching on potentially symbolic values by

nal blame labels.1 The monitor of a flat contract reduces toan if-expression which tests whether the predicate holds. Ifit does, the value is returned. Otherwise, a contract error issignaled with appropriate blame.

3. Symbolic PCF with ContractsWe now present an extension to Contract PCF and its seman-tics that enriches the language with symbolic values, drawnfrom the language of contracts. The key idea of SCPCF isto take the values of CPCF as “pre”-values U and add a no-tion of an unknown values (of type T ), written “•T ”. Purelyunknown values have arbitrary behavior, but we refine un-knowns by attaching a set of contracts that specify an agree-ment between the program and the missing component. Suchrefinements can guide an operational characterization of aprogram. Pre-values are refined by a set of contracts to forma value, U/C, where C ranges over sets of contracts.

The high-level goal of the following semantics is to en-able the running of programs with unknown components.The main requirement is that the results of running suchcomputations should soundly and precisely approximate theresult of running that same program after replacing an un-known with any allowable value. More precisely, if a pro-gram involving some value V produces an answer A, thenabstracting away that value to an unknown should producean approximation of A:

if E [V ] !"## A and $ V : T , then E [•T ] !"## A!,

where A! “approximates” A.

Notation: Abstract (or synonymously: symbolic) values !Vrange over values of the form •T /C. Whenever the refine-ment of a value is irrelevant, we omit the C set. We writeV · C for U/C % {C} where V = U/C.

The semantics given below replace that of section 2,equipping the operational semantics with an interpretationof symbolic values. (The semantics of contract checking isdeferred for the moment.)

To do so requires two changes:

1. the ! relation must be extended to interpret operationswhen applied to symbolic values, and

2. the one-step reduction relation must be extended to thecases of (1) branching on a (potentially) symbolic value,and (2) applying a symbolic function.

3.1 Operations on symbolic valuesTypically, the interpretation of operations is defined by afunction ! that maps an operation and argument values to

1 For simplicity, we present the so-called lax dependent contract rule; ourimplementation uses indy [13], obtained by replacing the contractum with:

!X :T.monf,gh ([monf,hh (C1, X)/X]C2, V mong,fh (C1, X)).

Symbolic PCF with Contracts

Prevalues U ::= •T | !X :T.E | 0 | 1 | " 1 | . . . | tt | !Values V ::= U/{C, . . . }

Semantics for Symbolic PCF with Contracts E !"# E!

if V E1 E2 !"# E1 if !(false?, V ) & !

if V E1 E2 !"# E2 if !(false?, V ) & tt

(!X :T.E) V !"# [V/X]E

µX :T .E !"# [µX :T .E/X]E

O("V ) !"# A if !(O, "V ) & A

(•T"T !/C) V !"# •T !

/{[V/X]C2 | C1 !#!X :T.C2 ' C}(•T"T !

/C) V !"# havocT V

an answer, e.g. !(add1, 0) = 1. The result of applying aprimitive may either be a value in case the operation isdefined on its given arguments, or blame in case it is not.

The extension of ! to interpret symbolic values is largelystraightforward. It starts by generalizing ! from a functionfrom an operation and values to an answer, to a relationbetween operations, values, and answers (or equivalently, toa function from an operation and values to sets of answers).This enables multiple results when a symbolic value does notconvey enough information to uniquely determine a singleresult. For example, !(zero?, 0) = {tt}, but !(zero?, •N) ={tt,!}. From here, all that remains is adding appropriateclauses to the definition of ! for handling symbolic values.As an example, the definition includes:

!(+, V1, V2) & •N, if V1 or V2 = •N/C.

The remaining cases are similarly straightforward.The revised reduction relation reduces an operation, non-

deterministically, to any answer in the ! relation.

3.2 Branching on symbolic valuesThe shift from the semantics of section 2 to section 3 also in-volves what appears to be a cosmetic change in the reductionof conditionals, e.g., from

if tt E1 E2 !"# E1

toif V E1 E2 !"# E1 if !(false?, V ) & !.

In the absence of symbolic values, the two relations areequivalent, but once symbolic values are introduced, thelatter handles branching on potentially symbolic values bydeferring to ! to determine if V is possibly true. Conse-quently branching on •B results in both E1 and E2 since!(false?, •B) = {tt,!}. Without this slight refactoring forconditionals, additional cases for the reduction relation arerequired, and these cases would largely mimic the existing

Page 65: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

nal blame labels.1 The monitor of a flat contract reduces toan if-expression which tests whether the predicate holds. Ifit does, the value is returned. Otherwise, a contract error issignaled with appropriate blame.

3. Symbolic PCF with ContractsWe now present an extension to Contract PCF and its seman-tics that enriches the language with symbolic values, drawnfrom the language of contracts. The key idea of SCPCF isto take the values of CPCF as “pre”-values U and add a no-tion of an unknown values (of type T ), written “•T ”. Purelyunknown values have arbitrary behavior, but we refine un-knowns by attaching a set of contracts that specify an agree-ment between the program and the missing component. Suchrefinements can guide an operational characterization of aprogram. Pre-values are refined by a set of contracts to forma value, U/C, where C ranges over sets of contracts.

The high-level goal of the following semantics is to en-able the running of programs with unknown components.The main requirement is that the results of running suchcomputations should soundly and precisely approximate theresult of running that same program after replacing an un-known with any allowable value. More precisely, if a pro-gram involving some value V produces an answer A, thenabstracting away that value to an unknown should producean approximation of A:

if E [V ] !"## A and $ V : T , then E [•T ] !"## A!,

where A! “approximates” A.

Notation: Abstract (or synonymously: symbolic) values !Vrange over values of the form •T /C. Whenever the refine-ment of a value is irrelevant, we omit the C set. We writeV · C for U/C % {C} where V = U/C.

The semantics given below replace that of section 2,equipping the operational semantics with an interpretationof symbolic values. (The semantics of contract checking isdeferred for the moment.)

To do so requires two changes:

1. the ! relation must be extended to interpret operationswhen applied to symbolic values, and

2. the one-step reduction relation must be extended to thecases of (1) branching on a (potentially) symbolic value,and (2) applying a symbolic function.

3.1 Operations on symbolic valuesTypically, the interpretation of operations is defined by afunction ! that maps an operation and argument values to

1 For simplicity, we present the so-called lax dependent contract rule; ourimplementation uses indy [13], obtained by replacing the contractum with:

!X :T.monf,gh ([monf,hh (C1, X)/X]C2, V mong,fh (C1, X)).

Symbolic PCF with Contracts

Prevalues U ::= •T | !X :T.E | 0 | 1 | " 1 | . . . | tt | !Values V ::= U/{C, . . . }

Semantics for Symbolic PCF with Contracts E !"# E!

if V E1 E2 !"# E1 if !(false?, V ) & !

if V E1 E2 !"# E2 if !(false?, V ) & tt

(!X :T.E) V !"# [V/X]E

µX :T .E !"# [µX :T .E/X]E

O("V ) !"# A if !(O, "V ) & A

(•T"T !/C) V !"# •T !

/{[V/X]C2 | C1 !#!X :T.C2 ' C}(•T"T !

/C) V !"# havocT V

if •T E1 E2 !"# E1

if •T E1 E2 !"# E2

(•T"T !) V !"# •T !

(•T"T !) V !"# havocT V

an answer, e.g. !(add1, 0) = 1. The result of applying aprimitive may either be a value in case the operation isdefined on its given arguments, or blame in case it is not.

The extension of ! to interpret symbolic values is largelystraightforward. It starts by generalizing ! from a functionfrom an operation and values to an answer, to a relationbetween operations, values, and answers (or equivalently, toa function from an operation and values to sets of answers).This enables multiple results when a symbolic value does notconvey enough information to uniquely determine a singleresult. For example, !(zero?, 0) = {tt}, but !(zero?, •N) ={tt,!}. From here, all that remains is adding appropriateclauses to the definition of ! for handling symbolic values.As an example, the definition includes:

!(+, V1, V2) & •N, if V1 or V2 = •N/C.

The remaining cases are similarly straightforward.The revised reduction relation reduces an operation, non-

deterministically, to any answer in the ! relation.

3.2 Branching on symbolic valuesThe shift from the semantics of section 2 to section 3 also in-volves what appears to be a cosmetic change in the reductionof conditionals, e.g., from

if tt E1 E2 !"# E1

toif V E1 E2 !"# E1 if !(false?, V ) & !.

In the absence of symbolic values, the two relations areequivalent, but once symbolic values are introduced, thelatter handles branching on potentially symbolic values by

nal blame labels.1 The monitor of a flat contract reduces toan if-expression which tests whether the predicate holds. Ifit does, the value is returned. Otherwise, a contract error issignaled with appropriate blame.

3. Symbolic PCF with ContractsWe now present an extension to Contract PCF and its seman-tics that enriches the language with symbolic values, drawnfrom the language of contracts. The key idea of SCPCF isto take the values of CPCF as “pre”-values U and add a no-tion of an unknown values (of type T ), written “•T ”. Purelyunknown values have arbitrary behavior, but we refine un-knowns by attaching a set of contracts that specify an agree-ment between the program and the missing component. Suchrefinements can guide an operational characterization of aprogram. Pre-values are refined by a set of contracts to forma value, U/C, where C ranges over sets of contracts.

The high-level goal of the following semantics is to en-able the running of programs with unknown components.The main requirement is that the results of running suchcomputations should soundly and precisely approximate theresult of running that same program after replacing an un-known with any allowable value. More precisely, if a pro-gram involving some value V produces an answer A, thenabstracting away that value to an unknown should producean approximation of A:

if E [V ] !"## A and $ V : T , then E [•T ] !"## A!,

where A! “approximates” A.

Notation: Abstract (or synonymously: symbolic) values !Vrange over values of the form •T /C. Whenever the refine-ment of a value is irrelevant, we omit the C set. We writeV · C for U/C % {C} where V = U/C.

The semantics given below replace that of section 2,equipping the operational semantics with an interpretationof symbolic values. (The semantics of contract checking isdeferred for the moment.)

To do so requires two changes:

1. the ! relation must be extended to interpret operationswhen applied to symbolic values, and

2. the one-step reduction relation must be extended to thecases of (1) branching on a (potentially) symbolic value,and (2) applying a symbolic function.

3.1 Operations on symbolic valuesTypically, the interpretation of operations is defined by afunction ! that maps an operation and argument values to

1 For simplicity, we present the so-called lax dependent contract rule; ourimplementation uses indy [13], obtained by replacing the contractum with:

!X :T.monf,gh ([monf,hh (C1, X)/X]C2, V mong,fh (C1, X)).

Symbolic PCF with Contracts

Prevalues U ::= •T | !X :T.E | 0 | 1 | " 1 | . . . | tt | !Values V ::= U/{C, . . . }

Semantics for Symbolic PCF with Contracts E !"# E!

if V E1 E2 !"# E1 if !(false?, V ) & !

if V E1 E2 !"# E2 if !(false?, V ) & tt

(!X :T.E) V !"# [V/X]E

µX :T .E !"# [µX :T .E/X]E

O("V ) !"# A if !(O, "V ) & A

(•T"T !/C) V !"# •T !

/{[V/X]C2 | C1 !#!X :T.C2 ' C}(•T"T !

/C) V !"# havocT V

an answer, e.g. !(add1, 0) = 1. The result of applying aprimitive may either be a value in case the operation isdefined on its given arguments, or blame in case it is not.

The extension of ! to interpret symbolic values is largelystraightforward. It starts by generalizing ! from a functionfrom an operation and values to an answer, to a relationbetween operations, values, and answers (or equivalently, toa function from an operation and values to sets of answers).This enables multiple results when a symbolic value does notconvey enough information to uniquely determine a singleresult. For example, !(zero?, 0) = {tt}, but !(zero?, •N) ={tt,!}. From here, all that remains is adding appropriateclauses to the definition of ! for handling symbolic values.As an example, the definition includes:

!(+, V1, V2) & •N, if V1 or V2 = •N/C.

The remaining cases are similarly straightforward.The revised reduction relation reduces an operation, non-

deterministically, to any answer in the ! relation.

3.2 Branching on symbolic valuesThe shift from the semantics of section 2 to section 3 also in-volves what appears to be a cosmetic change in the reductionof conditionals, e.g., from

if tt E1 E2 !"# E1

toif V E1 E2 !"# E1 if !(false?, V ) & !.

In the absence of symbolic values, the two relations areequivalent, but once symbolic values are introduced, thelatter handles branching on potentially symbolic values bydeferring to ! to determine if V is possibly true. Conse-quently branching on •B results in both E1 and E2 since!(false?, •B) = {tt,!}. Without this slight refactoring forconditionals, additional cases for the reduction relation arerequired, and these cases would largely mimic the existing

if reductions. By reformulating in terms of !, we enable theuniform reduction of abstract and concrete values.

3.3 Applying symbolic functionsWhen applying a symbolic function V , the reduction relationmust take two distinct possibilities into account. The first isthat although the argument to the symbolic function escapes,no failure occurs in the unknown context, so the functionreturns an abstract value refined by the range contracts ofthe function. The second is that the use of V in a unknowncontext results in the blame of V . To discover if blaming Vis possible we rely upon a havoc function, which iterativelyexplores the behavior of V for possible blame. Its onlypurpose is to uncover blame, thus it never produces a value;it either diverges or blames V . In this simplified model, theonly behavioral values are functions, so we represent allpossible uses of the escaped value by iteratively applying itto unknown values. This construction represents a universal“demonic” context to discover a way to blame V if possible,and we have named the function havoc to emphasize theanalogy to Boogie’s havoc function [14], which serves thesame purpose, but in a first-order setting.

The havoc function is indexed by the type of its argu-ment. At base type, values do not have behavior, so havocsimply produces a diverging computation. At function type,havoc produces a function that applies its argument to an ap-propriately typed unknown input value and then recursivelyapplies havoc at the result type to the output:

havocB = µx.x

havocT!T ! = !x :T ! T ".havocT !(x •T )

This means that havocT V either diverges or producesblame, and thus never introduces spurious results, and fur-ther that applications of havocT can be given whatever typeis required for the context.

To see how havoc finds all possible errors in a term,consider the following function guarded by a contract (themon function wraps a value with a contract):

mon(!f :N ! N.sqrt (f 0), (any "!any) "!any)

where any is the trivial contract flat(!x.tt) and sqrt has thetype N ! N and contract flat(positive?) "! flat(positive?).If we then apply havoc to this term at the appropriate type,it will supply the input •N!N for f. When this abstract valueis applied to 0, it reduces both to havocN 0, a divergingterm that produces no blame, and the symbolic number •N.Finally, sqrt is applied to •N, which both passes and fails thecontract check on sqrt, since •N represents both positive andnon-positive numbers; the latter demonstrates the originalfunction could be blamed.

In contrast, if the original term was wrapped in the con-tract (any "! flat(positive?)) "! any, then the abstract value•N!N would have been wrapped in the contract any "!

flat(positive?). When the wrapped abstract function is ap-plied to 0, it then produces the more precise abstract value•N · flat(positive?) as the input to sqrt and fails to blame theoriginal function.

The ability of havoc to find blame if possible is key to oursoundness result.

3.4 Contract checking symbolic valuesWe now turn to the revised semantics for contract checkingreductions in the presence of symbolic values. The key ideasare that we

1. avoid checking any contracts which a value provablysatisfies, and

2. add flat contracts to a value’s refinement set whenever acontract check against that value succeeds.

To implement the first idea, we add a reduction relationthat sidesteps a contract check and just produces the checkedvalue whenever the value proves it satisfies the contract.To implement the second idea, we revise the flat contractchecking reduction relation to produce not just the value, butthe value refined by the contract in the success branch of aflat contract check.

Contract checking, revisited

monf,gh (C, V ) "#! V if $ V : C !

monf,gh (flat(E), V ) "#!if (E V ) (V · flat(E)) blamefg if % $ V : flat(E)!

monf,gh (C1 "!!X :T.C2, V ) "#!!X :T.monf,gh (C2, V mong,fh (C1, X))

if % $ V : C1 "!!X :T.C2 !

The judgment $ V : C ! denotes that V provably satis-fies the contract C, which we read as “V proves C.” Oursystem is parametric with respect to this provability relationand the precision of the symbolic semantics improves as thepower of the proof system increases. For concreteness, webegin by considering the following simple, yet useful proofsystem which asserts a symbolic value proves any contract itis refined by:

C & C$ V/C : C !

As we will see subsequently, this relation can easily beextended to handle more sophisticated reasoning.

Taken together, the revised contract checking relation andproves relation allow values to remember contracts oncethey are checked and to avoid rechecking in subsequentcomputations. Consider the following program with abstractpieces:

let keygen=mon(unit "!flat(prime?), •)rsa =mon(flat(prime?) "!(any "!any), •)

in rsa (keygen ()) “Plaintext”

Page 66: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Semantics

Type-based ModularAnalysis

nal blame labels.1 The monitor of a flat contract reduces toan if-expression which tests whether the predicate holds. Ifit does, the value is returned. Otherwise, a contract error issignaled with appropriate blame.

3. Symbolic PCF with ContractsWe now present an extension to Contract PCF and its seman-tics that enriches the language with symbolic values, drawnfrom the language of contracts. The key idea of SCPCF isto take the values of CPCF as “pre”-values U and add a no-tion of an unknown values (of type T ), written “•T ”. Purelyunknown values have arbitrary behavior, but we refine un-knowns by attaching a set of contracts that specify an agree-ment between the program and the missing component. Suchrefinements can guide an operational characterization of aprogram. Pre-values are refined by a set of contracts to forma value, U/C, where C ranges over sets of contracts.

The high-level goal of the following semantics is to en-able the running of programs with unknown components.The main requirement is that the results of running suchcomputations should soundly and precisely approximate theresult of running that same program after replacing an un-known with any allowable value. More precisely, if a pro-gram involving some value V produces an answer A, thenabstracting away that value to an unknown should producean approximation of A:

if E [V ] !"## A and $ V : T , then E [•T ] !"## A!,

where A! “approximates” A.

Notation: Abstract (or synonymously: symbolic) values !Vrange over values of the form •T /C. Whenever the refine-ment of a value is irrelevant, we omit the C set. We writeV · C for U/C % {C} where V = U/C.

The semantics given below replace that of section 2,equipping the operational semantics with an interpretationof symbolic values. (The semantics of contract checking isdeferred for the moment.)

To do so requires two changes:

1. the ! relation must be extended to interpret operationswhen applied to symbolic values, and

2. the one-step reduction relation must be extended to thecases of (1) branching on a (potentially) symbolic value,and (2) applying a symbolic function.

3.1 Operations on symbolic valuesTypically, the interpretation of operations is defined by afunction ! that maps an operation and argument values to

1 For simplicity, we present the so-called lax dependent contract rule; ourimplementation uses indy [13], obtained by replacing the contractum with:

!X :T.monf,gh ([monf,hh (C1, X)/X]C2, V mong,fh (C1, X)).

Symbolic PCF with Contracts

Prevalues U ::= •T | !X :T.E | 0 | 1 | " 1 | . . . | tt | !Values V ::= U/{C, . . . }

Semantics for Symbolic PCF with Contracts E !"# E!

if V E1 E2 !"# E1 if !(false?, V ) & !

if V E1 E2 !"# E2 if !(false?, V ) & tt

(!X :T.E) V !"# [V/X]E

µX :T .E !"# [µX :T .E/X]E

O("V ) !"# A if !(O, "V ) & A

(•T"T !/C) V !"# •T !

/{[V/X]C2 | C1 !#!X :T.C2 ' C}(•T"T !

/C) V !"# havocT V

if •T E1 E2 !"# E1

if •T E1 E2 !"# E2

(•T"T !) V !"# •T !

(•T"T !) V !"# havocT V

an answer, e.g. !(add1, 0) = 1. The result of applying aprimitive may either be a value in case the operation isdefined on its given arguments, or blame in case it is not.

The extension of ! to interpret symbolic values is largelystraightforward. It starts by generalizing ! from a functionfrom an operation and values to an answer, to a relationbetween operations, values, and answers (or equivalently, toa function from an operation and values to sets of answers).This enables multiple results when a symbolic value does notconvey enough information to uniquely determine a singleresult. For example, !(zero?, 0) = {tt}, but !(zero?, •N) ={tt,!}. From here, all that remains is adding appropriateclauses to the definition of ! for handling symbolic values.As an example, the definition includes:

!(+, V1, V2) & •N, if V1 or V2 = •N/C.

The remaining cases are similarly straightforward.The revised reduction relation reduces an operation, non-

deterministically, to any answer in the ! relation.

3.2 Branching on symbolic valuesThe shift from the semantics of section 2 to section 3 also in-volves what appears to be a cosmetic change in the reductionof conditionals, e.g., from

if tt E1 E2 !"# E1

toif V E1 E2 !"# E1 if !(false?, V ) & !.

In the absence of symbolic values, the two relations areequivalent, but once symbolic values are introduced, thelatter handles branching on potentially symbolic values by

2. Contracts and Contract PCFThe basic building block of our specification system isbehavioral software contracts. Originally introduced byMeyer [31], contracts are executable specifications that sit atthe boundary between software components. In a first-ordersetting, properly assessing which component violated a con-tract at run-time is straightforward. Matters are complicatedwhen higher-order values such as functions or objects are in-cluded in the language. Findler and Felleisen [17] introducedthe notion of blame and established a semantic frameworkfor properly assessing blame at run-time in a higher-orderlanguage, providing the theoretical basis for contract sys-tems such as Racket’s.

(module double(provide [dbl ((even? -> even?)

-> (even? -> even?))])(define dbl (! (f) (! (x) (f (f x))))))

> (dbl (! (x) 7))

top-level broke the contract on dbl;expected <even?>, given: 7

To illustrate, consider the program above, which consistsof a module and top-level expression. Module double pro-vides a dbl function that implements twice-iterated applica-tion, operating on functions on even numbers. The top-levelexpression makes use of the dbl function, but incorrectly—dbl is applied to a function that produces 7.

Contract checking and blame assignment in a higher-order program is complicated by the fact that it is not de-cidable in general whether the argument of dbl is a functionfrom and to even numbers. Thus, higher-order contracts arepushed down into delayed lower-order checks, but care mustbe taken to get blame right. In our example, the top-levelis blamed, and rightly so, even though even? witnesses theviolation when f is applied to x while executing dbl.

2.1 Contract PCFDimoulas et al. [12, 13] introduce Contract PCF as a corecalculus for the investigation of contracts, which we take asthe starting point for our model. CPCF extends PCF [33]with contracts for base values and first-class functions. Weprovide a brief recap of the syntax and semantics of CPCF.

Contracts for flat values, flat(E), employ predicates thatmay use the full expressive power of CPCF. Function con-tracts, C1 !" C2, consist of a pre-condition contract C1 forthe argument to the function and a post-condition contractC2 for the function’s result. Dependent function contracts,C1 !"!X.C2, bind X to the argument of the function in thepost-condition contract C2, and thus express a dependencybetween a function’s input and result. In the remainder of thepaper, we treat the non-dependent function contract C1 !"C2

as shorthand for C1 !"!X.C2 where X is fresh.

PCF with Contracts

Types T ::= B | T " T | con(T )Base types B ::= N | BTerms E ::= A | X | E E | µX :T .E | if E E E

| O1(E) | O2(E,E) | monf,ff (C,E)

Operations O1 ::= zero? | false? | . . .O2 ::= + | # | $ | % | . . .

Contracts C ::= flat(E) | C !"C | C !"!X :T.C

Answers A ::= V | E [blameff ]

Values V ::= !X :T.E | 0 | 1 | # 1 | . . . | tt | !Evaluation E ::= [ ] | E E | V E | O2(E , E) | O2(V, E)contexts | O1(E) | if E E E | monf,gh (C, E)

Semantics for PCF with Contracts E !#" E!

if tt E1 E2 !#" E1

if ! E1 E2 !#" E2

(!X :T.E) V !#" [V/X]E

µX :T .E !#" [µX :T .E/X]E

O(!V ) !#" A if "(O, !V ) = A

monf,gh (C1 !"!X :T.C2, V ) !#"!X :T.monf,gh (C2, (V mong,fh (C1, X)))

monf,gh (flat(E), V ) !#" if (E V ) V blamefh

A contract C is attached to an expression with the monitorconstruct monf,gh (C,E), which carries three labels: f , g, andh, denoting the names of components which may be blamedfor contract failure. (An implementation would synthesizethese names from the source code.) The monitor checksany interaction between the expression and its context is inaccordance with the contract.

Component labels play an important role in case a con-tract failure is detected during contract checking. In such acase, blame is assigned with the blamefg construct, whichstates that the component named f broke its contract with g.

CPCF is equipped with a standard type system for PCFplus the addition of a contract type con(T ), which denotesthe set of contracts for values of type T [12, 13]. The typesystem is straightforward, so for the sake of space, we deferthe details to an appendix (§A.1).

The semantics of CPCF are given as a call-by-value re-duction relation on programs. One-step reduction E !#" E!

is defined above, contextually closed over evaluation con-texts E ; its reflexive transitive closure is written E !#"" E!.

The first five cases of the reduction relation are stan-dard for PCF. The remaining two cases implement con-tract checking for function contracts and flat contracts, re-spectively. The monitor of a function contract on a func-tion reduces to a function that monitors its input with re-versed blame labels and monitors its output with the origi-

Page 67: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Contract PCF

Page 68: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

2. Contracts and Contract PCFThe basic building block of our specification system isbehavioral software contracts. Originally introduced byMeyer [31], contracts are executable specifications that sit atthe boundary between software components. In a first-ordersetting, properly assessing which component violated a con-tract at run-time is straightforward. Matters are complicatedwhen higher-order values such as functions or objects are in-cluded in the language. Findler and Felleisen [17] introducedthe notion of blame and established a semantic frameworkfor properly assessing blame at run-time in a higher-orderlanguage, providing the theoretical basis for contract sys-tems such as Racket’s.

(module double(provide [dbl ((even? -> even?)

-> (even? -> even?))])(define dbl (! (f) (! (x) (f (f x))))))

> (dbl (! (x) 7))

top-level broke the contract on dbl;expected <even?>, given: 7

To illustrate, consider the program above, which consistsof a module and top-level expression. Module double pro-vides a dbl function that implements twice-iterated applica-tion, operating on functions on even numbers. The top-levelexpression makes use of the dbl function, but incorrectly—dbl is applied to a function that produces 7.

Contract checking and blame assignment in a higher-order program is complicated by the fact that it is not de-cidable in general whether the argument of dbl is a functionfrom and to even numbers. Thus, higher-order contracts arepushed down into delayed lower-order checks, but care mustbe taken to get blame right. In our example, the top-levelis blamed, and rightly so, even though even? witnesses theviolation when f is applied to x while executing dbl.

2.1 Contract PCFDimoulas et al. [12, 13] introduce Contract PCF as a corecalculus for the investigation of contracts, which we take asthe starting point for our model. CPCF extends PCF [33]with contracts for base values and first-class functions. Weprovide a brief recap of the syntax and semantics of CPCF.

Contracts for flat values, flat(E), employ predicates thatmay use the full expressive power of CPCF. Function con-tracts, C1 !" C2, consist of a pre-condition contract C1 forthe argument to the function and a post-condition contractC2 for the function’s result. Dependent function contracts,C1 !"!X.C2, bind X to the argument of the function in thepost-condition contract C2, and thus express a dependencybetween a function’s input and result. In the remainder of thepaper, we treat the non-dependent function contract C1 !"C2

as shorthand for C1 !"!X.C2 where X is fresh.

PCF with Contracts

Types T ::= B | T " T | con(T )Base types B ::= N | BTerms E ::= A | X | E E | µX :T .E | if E E E

| O1(E) | O2(E,E) | monf,ff (C,E)

Operations O1 ::= zero? | false? | . . .O2 ::= + | # | $ | % | . . .

Contracts C ::= flat(E) | C !"C | C !"!X :T.C

Answers A ::= V | E [blameff ]

Values V ::= !X :T.E | 0 | 1 | # 1 | . . . | tt | !Evaluation E ::= [ ] | E E | V E | O2(E , E) | O2(V, E)contexts | O1(E) | if E E E | monf,gh (C, E)

Semantics for PCF with Contracts E !#" E!

if tt E1 E2 !#" E1

if ! E1 E2 !#" E2

(!X :T.E) V !#" [V/X]E

µX :T .E !#" [µX :T .E/X]E

O(!V ) !#" A if "(O, !V ) = A

monf,gh (C1 !"!X :T.C2, V ) !#"!X :T.monf,gh (C2, (V mong,fh (C1, X)))

monf,gh (flat(E), V ) !#" if (E V ) V blamefh

A contract C is attached to an expression with the monitorconstruct monf,gh (C,E), which carries three labels: f , g, andh, denoting the names of components which may be blamedfor contract failure. (An implementation would synthesizethese names from the source code.) The monitor checksany interaction between the expression and its context is inaccordance with the contract.

Component labels play an important role in case a con-tract failure is detected during contract checking. In such acase, blame is assigned with the blamefg construct, whichstates that the component named f broke its contract with g.

CPCF is equipped with a standard type system for PCFplus the addition of a contract type con(T ), which denotesthe set of contracts for values of type T [12, 13]. The typesystem is straightforward, so for the sake of space, we deferthe details to an appendix (§A.1).

The semantics of CPCF are given as a call-by-value re-duction relation on programs. One-step reduction E !#" E!

is defined above, contextually closed over evaluation con-texts E ; its reflexive transitive closure is written E !#"" E!.

The first five cases of the reduction relation are stan-dard for PCF. The remaining two cases implement con-tract checking for function contracts and flat contracts, re-spectively. The monitor of a function contract on a func-tion reduces to a function that monitors its input with re-versed blame labels and monitors its output with the origi-

2. Contracts and Contract PCFThe basic building block of our specification system isbehavioral software contracts. Originally introduced byMeyer [31], contracts are executable specifications that sit atthe boundary between software components. In a first-ordersetting, properly assessing which component violated a con-tract at run-time is straightforward. Matters are complicatedwhen higher-order values such as functions or objects are in-cluded in the language. Findler and Felleisen [17] introducedthe notion of blame and established a semantic frameworkfor properly assessing blame at run-time in a higher-orderlanguage, providing the theoretical basis for contract sys-tems such as Racket’s.

(module double(provide [dbl ((even? -> even?)

-> (even? -> even?))])(define dbl (! (f) (! (x) (f (f x))))))

> (dbl (! (x) 7))

top-level broke the contract on dbl;expected <even?>, given: 7

To illustrate, consider the program above, which consistsof a module and top-level expression. Module double pro-vides a dbl function that implements twice-iterated applica-tion, operating on functions on even numbers. The top-levelexpression makes use of the dbl function, but incorrectly—dbl is applied to a function that produces 7.

Contract checking and blame assignment in a higher-order program is complicated by the fact that it is not de-cidable in general whether the argument of dbl is a functionfrom and to even numbers. Thus, higher-order contracts arepushed down into delayed lower-order checks, but care mustbe taken to get blame right. In our example, the top-levelis blamed, and rightly so, even though even? witnesses theviolation when f is applied to x while executing dbl.

2.1 Contract PCFDimoulas et al. [12, 13] introduce Contract PCF as a corecalculus for the investigation of contracts, which we take asthe starting point for our model. CPCF extends PCF [33]with contracts for base values and first-class functions. Weprovide a brief recap of the syntax and semantics of CPCF.

Contracts for flat values, flat(E), employ predicates thatmay use the full expressive power of CPCF. Function con-tracts, C1 !" C2, consist of a pre-condition contract C1 forthe argument to the function and a post-condition contractC2 for the function’s result. Dependent function contracts,C1 !"!X.C2, bind X to the argument of the function in thepost-condition contract C2, and thus express a dependencybetween a function’s input and result. In the remainder of thepaper, we treat the non-dependent function contract C1 !"C2

as shorthand for C1 !"!X.C2 where X is fresh.

PCF with Contracts

Types T ::= B | T " T | con(T )Base types B ::= N | BTerms E ::= A | X | E E | µX :T .E | if E E E

| O1(E) | O2(E,E) | monf,ff (C,E)

Operations O1 ::= zero? | false? | . . .O2 ::= + | # | $ | % | . . .

Contracts C ::= flat(E) | C !"C | C !"!X :T.C

Answers A ::= V | E [blameff ]

Values V ::= !X :T.E | 0 | 1 | # 1 | . . . | tt | !Evaluation E ::= [ ] | E E | V E | O2(E , E) | O2(V, E)contexts | O1(E) | if E E E | monf,gh (C, E)

Semantics for PCF with Contracts E !#" E!

if tt E1 E2 !#" E1

if ! E1 E2 !#" E2

(!X :T.E) V !#" [V/X]E

µX :T .E !#" [µX :T .E/X]E

O(!V ) !#" A if "(O, !V ) = A

monf,gh (C1 !"!X :T.C2, V ) !#"!X :T.monf,gh (C2, (V mong,fh (C1, X)))

monf,gh (flat(E), V ) !#" if (E V ) V blamefh

A contract C is attached to an expression with the monitorconstruct monf,gh (C,E), which carries three labels: f , g, andh, denoting the names of components which may be blamedfor contract failure. (An implementation would synthesizethese names from the source code.) The monitor checksany interaction between the expression and its context is inaccordance with the contract.

Component labels play an important role in case a con-tract failure is detected during contract checking. In such acase, blame is assigned with the blamefg construct, whichstates that the component named f broke its contract with g.

CPCF is equipped with a standard type system for PCFplus the addition of a contract type con(T ), which denotesthe set of contracts for values of type T [12, 13]. The typesystem is straightforward, so for the sake of space, we deferthe details to an appendix (§A.1).

The semantics of CPCF are given as a call-by-value re-duction relation on programs. One-step reduction E !#" E!

is defined above, contextually closed over evaluation con-texts E ; its reflexive transitive closure is written E !#"" E!.

The first five cases of the reduction relation are stan-dard for PCF. The remaining two cases implement con-tract checking for function contracts and flat contracts, re-spectively. The monitor of a function contract on a func-tion reduces to a function that monitors its input with re-versed blame labels and monitors its output with the origi-

Page 69: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

SymbolicContract PCF

Page 70: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

nal blame labels.1 The monitor of a flat contract reduces toan if-expression which tests whether the predicate holds. Ifit does, the value is returned. Otherwise, a contract error issignaled with appropriate blame.

3. Symbolic PCF with ContractsWe now present an extension to Contract PCF and its seman-tics that enriches the language with symbolic values, drawnfrom the language of contracts. The key idea of SCPCF isto take the values of CPCF as “pre”-values U and add a no-tion of an unknown values (of type T ), written “•T ”. Purelyunknown values have arbitrary behavior, but we refine un-knowns by attaching a set of contracts that specify an agree-ment between the program and the missing component. Suchrefinements can guide an operational characterization of aprogram. Pre-values are refined by a set of contracts to forma value, U/C, where C ranges over sets of contracts.

The high-level goal of the following semantics is to en-able the running of programs with unknown components.The main requirement is that the results of running suchcomputations should soundly and precisely approximate theresult of running that same program after replacing an un-known with any allowable value. More precisely, if a pro-gram involving some value V produces an answer A, thenabstracting away that value to an unknown should producean approximation of A:

if E [V ] !"## A and $ V : T , then E [•T ] !"## A!,

where A! “approximates” A.

Notation: Abstract (or synonymously: symbolic) values !Vrange over values of the form •T /C. Whenever the refine-ment of a value is irrelevant, we omit the C set. We writeV · C for U/C % {C} where V = U/C.

The semantics given below replace that of section 2,equipping the operational semantics with an interpretationof symbolic values. (The semantics of contract checking isdeferred for the moment.)

To do so requires two changes:

1. the ! relation must be extended to interpret operationswhen applied to symbolic values, and

2. the one-step reduction relation must be extended to thecases of (1) branching on a (potentially) symbolic value,and (2) applying a symbolic function.

3.1 Operations on symbolic valuesTypically, the interpretation of operations is defined by afunction ! that maps an operation and argument values to

1 For simplicity, we present the so-called lax dependent contract rule; ourimplementation uses indy [13], obtained by replacing the contractum with:

!X :T.monf,gh ([monf,hh (C1, X)/X]C2, V mong,fh (C1, X)).

Symbolic PCF with Contracts

Prevalues U ::= •T | !X :T.E | 0 | 1 | " 1 | . . . | tt | !Values V ::= U/{C, . . . }

Semantics for Symbolic PCF with Contracts E !"# E!

if V E1 E2 !"# E1 if !(false?, V ) & !

if V E1 E2 !"# E2 if !(false?, V ) & tt

(!X :T.E) V !"# [V/X]E

µX :T .E !"# [µX :T .E/X]E

O("V ) !"# A if !(O, "V ) & A

(•T"T !/C) V !"# •T !

/{[V/X]C2 | C1 !#!X :T.C2 ' C}(•T"T !

/C) V !"# havocT V

an answer, e.g. !(add1, 0) = 1. The result of applying aprimitive may either be a value in case the operation isdefined on its given arguments, or blame in case it is not.

The extension of ! to interpret symbolic values is largelystraightforward. It starts by generalizing ! from a functionfrom an operation and values to an answer, to a relationbetween operations, values, and answers (or equivalently, toa function from an operation and values to sets of answers).This enables multiple results when a symbolic value does notconvey enough information to uniquely determine a singleresult. For example, !(zero?, 0) = {tt}, but !(zero?, •N) ={tt,!}. From here, all that remains is adding appropriateclauses to the definition of ! for handling symbolic values.As an example, the definition includes:

!(+, V1, V2) & •N, if V1 or V2 = •N/C.

The remaining cases are similarly straightforward.The revised reduction relation reduces an operation, non-

deterministically, to any answer in the ! relation.

3.2 Branching on symbolic valuesThe shift from the semantics of section 2 to section 3 also in-volves what appears to be a cosmetic change in the reductionof conditionals, e.g., from

if tt E1 E2 !"# E1

toif V E1 E2 !"# E1 if !(false?, V ) & !.

In the absence of symbolic values, the two relations areequivalent, but once symbolic values are introduced, thelatter handles branching on potentially symbolic values bydeferring to ! to determine if V is possibly true. Conse-quently branching on •B results in both E1 and E2 since!(false?, •B) = {tt,!}. Without this slight refactoring forconditionals, additional cases for the reduction relation arerequired, and these cases would largely mimic the existing

Page 71: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

if reductions. By reformulating in terms of !, we enable theuniform reduction of abstract and concrete values.

3.3 Applying symbolic functionsWhen applying a symbolic function V , the reduction relationmust take two distinct possibilities into account. The first isthat although the argument to the symbolic function escapes,no failure occurs in the unknown context, so the functionreturns an abstract value refined by the range contracts ofthe function. The second is that the use of V in a unknowncontext results in the blame of V . To discover if blaming Vis possible we rely upon a havoc function, which iterativelyexplores the behavior of V for possible blame. Its onlypurpose is to uncover blame, thus it never produces a value;it either diverges or blames V . In this simplified model, theonly behavioral values are functions, so we represent allpossible uses of the escaped value by iteratively applying itto unknown values. This construction represents a universal“demonic” context to discover a way to blame V if possible,and we have named the function havoc to emphasize theanalogy to Boogie’s havoc function [14], which serves thesame purpose, but in a first-order setting.

The havoc function is indexed by the type of its argu-ment. At base type, values do not have behavior, so havocsimply produces a diverging computation. At function type,havoc produces a function that applies its argument to an ap-propriately typed unknown input value and then recursivelyapplies havoc at the result type to the output:

havocB = µx.x

havocT!T ! = !x :T ! T ".havocT !(x •T )

This means that havocT V either diverges or producesblame, and thus never introduces spurious results, and fur-ther that applications of havocT can be given whatever typeis required for the context.

To see how havoc finds all possible errors in a term,consider the following function guarded by a contract (themon function wraps a value with a contract):

mon(!f :N ! N.sqrt (f 0), (any "!any) "!any)

where any is the trivial contract flat(!x.tt) and sqrt has thetype N ! N and contract flat(positive?) "! flat(positive?).If we then apply havoc to this term at the appropriate type,it will supply the input •N!N for f. When this abstract valueis applied to 0, it reduces both to havocN 0, a divergingterm that produces no blame, and the symbolic number •N.Finally, sqrt is applied to •N, which both passes and fails thecontract check on sqrt, since •N represents both positive andnon-positive numbers; the latter demonstrates the originalfunction could be blamed.

In contrast, if the original term was wrapped in the con-tract (any "! flat(positive?)) "! any, then the abstract value•N!N would have been wrapped in the contract any "!

flat(positive?). When the wrapped abstract function is ap-plied to 0, it then produces the more precise abstract value•N · flat(positive?) as the input to sqrt and fails to blame theoriginal function.

The ability of havoc to find blame if possible is key to oursoundness result.

3.4 Contract checking symbolic valuesWe now turn to the revised semantics for contract checkingreductions in the presence of symbolic values. The key ideasare that we

1. avoid checking any contracts which a value provablysatisfies, and

2. add flat contracts to a value’s refinement set whenever acontract check against that value succeeds.

To implement the first idea, we add a reduction relationthat sidesteps a contract check and just produces the checkedvalue whenever the value proves it satisfies the contract.To implement the second idea, we revise the flat contractchecking reduction relation to produce not just the value, butthe value refined by the contract in the success branch of aflat contract check.

Contract checking, revisited

monf,gh (C, V ) "#! V if $ V : C !

monf,gh (flat(E), V ) "#!if (E V ) (V · flat(E)) blamefg if % $ V : flat(E)!

monf,gh (C1 "!!X :T.C2, V ) "#!!X :T.monf,gh (C2, V mong,fh (C1, X))

if % $ V : C1 "!!X :T.C2 !

The judgment $ V : C ! denotes that V provably satis-fies the contract C, which we read as “V proves C.” Oursystem is parametric with respect to this provability relationand the precision of the symbolic semantics improves as thepower of the proof system increases. For concreteness, webegin by considering the following simple, yet useful proofsystem which asserts a symbolic value proves any contract itis refined by:

C & C$ V/C : C !

As we will see subsequently, this relation can easily beextended to handle more sophisticated reasoning.

Taken together, the revised contract checking relation andproves relation allow values to remember contracts oncethey are checked and to avoid rechecking in subsequentcomputations. Consider the following program with abstractpieces:

let keygen=mon(unit "!flat(prime?), •)rsa =mon(flat(prime?) "!(any "!any), •)

in rsa (keygen ()) “Plaintext”

Page 72: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

if reductions. By reformulating in terms of !, we enable theuniform reduction of abstract and concrete values.

3.3 Applying symbolic functionsWhen applying a symbolic function V , the reduction relationmust take two distinct possibilities into account. The first isthat although the argument to the symbolic function escapes,no failure occurs in the unknown context, so the functionreturns an abstract value refined by the range contracts ofthe function. The second is that the use of V in a unknowncontext results in the blame of V . To discover if blaming Vis possible we rely upon a havoc function, which iterativelyexplores the behavior of V for possible blame. Its onlypurpose is to uncover blame, thus it never produces a value;it either diverges or blames V . In this simplified model, theonly behavioral values are functions, so we represent allpossible uses of the escaped value by iteratively applying itto unknown values. This construction represents a universal“demonic” context to discover a way to blame V if possible,and we have named the function havoc to emphasize theanalogy to Boogie’s havoc function [14], which serves thesame purpose, but in a first-order setting.

The havoc function is indexed by the type of its argu-ment. At base type, values do not have behavior, so havocsimply produces a diverging computation. At function type,havoc produces a function that applies its argument to an ap-propriately typed unknown input value and then recursivelyapplies havoc at the result type to the output:

havocB = µx.x

havocT!T ! = !x :T ! T ".havocT !(x •T )

This means that havocT V either diverges or producesblame, and thus never introduces spurious results, and fur-ther that applications of havocT can be given whatever typeis required for the context.

To see how havoc finds all possible errors in a term,consider the following function guarded by a contract (themon function wraps a value with a contract):

mon(!f :N ! N.sqrt (f 0), (any "!any) "!any)

where any is the trivial contract flat(!x.tt) and sqrt has thetype N ! N and contract flat(positive?) "! flat(positive?).If we then apply havoc to this term at the appropriate type,it will supply the input •N!N for f. When this abstract valueis applied to 0, it reduces both to havocN 0, a divergingterm that produces no blame, and the symbolic number •N.Finally, sqrt is applied to •N, which both passes and fails thecontract check on sqrt, since •N represents both positive andnon-positive numbers; the latter demonstrates the originalfunction could be blamed.

In contrast, if the original term was wrapped in the con-tract (any "! flat(positive?)) "! any, then the abstract value•N!N would have been wrapped in the contract any "!

flat(positive?). When the wrapped abstract function is ap-plied to 0, it then produces the more precise abstract value•N · flat(positive?) as the input to sqrt and fails to blame theoriginal function.

The ability of havoc to find blame if possible is key to oursoundness result.

3.4 Contract checking symbolic valuesWe now turn to the revised semantics for contract checkingreductions in the presence of symbolic values. The key ideasare that we

1. avoid checking any contracts which a value provablysatisfies, and

2. add flat contracts to a value’s refinement set whenever acontract check against that value succeeds.

To implement the first idea, we add a reduction relationthat sidesteps a contract check and just produces the checkedvalue whenever the value proves it satisfies the contract.To implement the second idea, we revise the flat contractchecking reduction relation to produce not just the value, butthe value refined by the contract in the success branch of aflat contract check.

Contract checking, revisited

monf,gh (C, V ) "#! V if $ V : C !

monf,gh (flat(E), V ) "#!if (E V ) (V · flat(E)) blamefg if % $ V : flat(E)!

monf,gh (C1 "!!X :T.C2, V ) "#!!X :T.monf,gh (C2, V mong,fh (C1, X))

if % $ V : C1 "!!X :T.C2 !

The judgment $ V : C ! denotes that V provably satis-fies the contract C, which we read as “V proves C.” Oursystem is parametric with respect to this provability relationand the precision of the symbolic semantics improves as thepower of the proof system increases. For concreteness, webegin by considering the following simple, yet useful proofsystem which asserts a symbolic value proves any contract itis refined by:

C & C$ V/C : C !

As we will see subsequently, this relation can easily beextended to handle more sophisticated reasoning.

Taken together, the revised contract checking relation andproves relation allow values to remember contracts oncethey are checked and to avoid rechecking in subsequentcomputations. Consider the following program with abstractpieces:

let keygen=mon(unit "!flat(prime?), •)rsa =mon(flat(prime?) "!(any "!any), •)

in rsa (keygen ()) “Plaintext”

if reductions. By reformulating in terms of !, we enable theuniform reduction of abstract and concrete values.

3.3 Applying symbolic functionsWhen applying a symbolic function V , the reduction relationmust take two distinct possibilities into account. The first isthat although the argument to the symbolic function escapes,no failure occurs in the unknown context, so the functionreturns an abstract value refined by the range contracts ofthe function. The second is that the use of V in a unknowncontext results in the blame of V . To discover if blaming Vis possible we rely upon a havoc function, which iterativelyexplores the behavior of V for possible blame. Its onlypurpose is to uncover blame, thus it never produces a value;it either diverges or blames V . In this simplified model, theonly behavioral values are functions, so we represent allpossible uses of the escaped value by iteratively applying itto unknown values. This construction represents a universal“demonic” context to discover a way to blame V if possible,and we have named the function havoc to emphasize theanalogy to Boogie’s havoc function [14], which serves thesame purpose, but in a first-order setting.

The havoc function is indexed by the type of its argu-ment. At base type, values do not have behavior, so havocsimply produces a diverging computation. At function type,havoc produces a function that applies its argument to an ap-propriately typed unknown input value and then recursivelyapplies havoc at the result type to the output:

havocB = µx.x

havocT!T ! = !x :T ! T ".havocT !(x •T )

This means that havocT V either diverges or producesblame, and thus never introduces spurious results, and fur-ther that applications of havocT can be given whatever typeis required for the context.

To see how havoc finds all possible errors in a term,consider the following function guarded by a contract (themon function wraps a value with a contract):

mon(!f :N ! N.sqrt (f 0), (any "!any) "!any)

where any is the trivial contract flat(!x.tt) and sqrt has thetype N ! N and contract flat(positive?) "! flat(positive?).If we then apply havoc to this term at the appropriate type,it will supply the input •N!N for f. When this abstract valueis applied to 0, it reduces both to havocN 0, a divergingterm that produces no blame, and the symbolic number •N.Finally, sqrt is applied to •N, which both passes and fails thecontract check on sqrt, since •N represents both positive andnon-positive numbers; the latter demonstrates the originalfunction could be blamed.

In contrast, if the original term was wrapped in the con-tract (any "! flat(positive?)) "! any, then the abstract value•N!N would have been wrapped in the contract any "!

flat(positive?). When the wrapped abstract function is ap-plied to 0, it then produces the more precise abstract value•N · flat(positive?) as the input to sqrt and fails to blame theoriginal function.

The ability of havoc to find blame if possible is key to oursoundness result.

3.4 Contract checking symbolic valuesWe now turn to the revised semantics for contract checkingreductions in the presence of symbolic values. The key ideasare that we

1. avoid checking any contracts which a value provablysatisfies, and

2. add flat contracts to a value’s refinement set whenever acontract check against that value succeeds.

To implement the first idea, we add a reduction relationthat sidesteps a contract check and just produces the checkedvalue whenever the value proves it satisfies the contract.To implement the second idea, we revise the flat contractchecking reduction relation to produce not just the value, butthe value refined by the contract in the success branch of aflat contract check.

Contract checking, revisited

monf,gh (C, V ) "#! V if $ V : C !

monf,gh (flat(E), V ) "#!if (E V ) (V · flat(E)) blamefg if % $ V : flat(E)!

monf,gh (C1 "!!X :T.C2, V ) "#!!X :T.monf,gh (C2, V mong,fh (C1, X))

if % $ V : C1 "!!X :T.C2 !

The judgment $ V : C ! denotes that V provably satis-fies the contract C, which we read as “V proves C.” Oursystem is parametric with respect to this provability relationand the precision of the symbolic semantics improves as thepower of the proof system increases. For concreteness, webegin by considering the following simple, yet useful proofsystem which asserts a symbolic value proves any contract itis refined by:

C & C$ V/C : C !

As we will see subsequently, this relation can easily beextended to handle more sophisticated reasoning.

Taken together, the revised contract checking relation andproves relation allow values to remember contracts oncethey are checked and to avoid rechecking in subsequentcomputations. Consider the following program with abstractpieces:

let keygen=mon(unit "!flat(prime?), •)rsa =mon(flat(prime?) "!(any "!any), •)

in rsa (keygen ()) “Plaintext”

Page 73: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

SymbolicCore Racket

Page 74: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Modular Contract Analysis

P,Q ::= !MEM,N ::= (module f C V )E,E! ::= f ! | X | A | E E! | if E E E | O !E! | µX.E

| mon!,!! (C,E)U ::= n | tt | ! | (!X.E) | • | (V, V ) | emptyV ::= U/CC,D ::= X | C !"!X.C | flat(E)

| #C,C$ | C % C | C & C | µX.CO ::= add1 | car | cdr | cons | + | = | o? | . . .o? ::= nat? | bool? | empty? | cons? | proc? | false?A ::= V | E [blame!!]

Figure 2. Syntax of Symbolic Core Racket

the module they appear in; this label is used as the nega-tive party for the module’s contract. Applications are alsolabeled; this label is used if the application fails. Pair val-ues and the empty list constant are standard, along with theiroperations. Since the language is untyped, we add standardtype predicates such as nat?.

The new contract forms include pair contracts, #C,D$,conjunction, C&D, and disjunction, C%D, of contracts, andexplicit recursive contracts with contract variables, µX.C.

Contract checks monf,gh (C,E), which will now be in-serted automatically by the operational semantics, take allof their labels from the names of modules, with the thirdlabel h representing the module in which the contract orig-inally appeared. As before, f represents the positive partyto the contract, blamed if the expression does not meet thecontract, and g is the negative party, blamed if the contextdoes not satisfy its obligations. Whenever these annotationscan be inferred from context, we omit them; in particular,in the definition of relations, it is assumed all checks of theform mon(C,E) have identical annotations. We omit labelson applications whenever they provably cannot be blamed,e.g. when the operand is known to be a function.

A blame expression, blame!!! , now indicates that the mod-ule (or the top-level expression) named by " broke its con-tract with "!, which may be the name of a module f , thetop-level expression †, or the language, indicated by !, inthe case of primitive errors.

Syntactic requirements: We make the following assump-tions of initial programs P : programs are closed, every mod-ule reference and application is labeled with the enclosingmodule name, or † for the top-level expression, operationsare applied with the correct arity, abstract values only appearin opaque module definitions, and no monitors or blame ex-pressions appear in source programs.

We also require that recursive contracts be productive,meaning either a function or pair contract constructor mustoccur between binding and reference. We also require thatcontracts in the source program are closed, both with respect

to !-bound and contract variables. Following standard prac-tice, we will say that a contract is higher-order if it syntac-tically contains a function contract; otherwise, the contractis flat. Flat contracts can be checked immediately, whereashigher-order contracts potentially require delayed checks.All predicate contracts are necessarily flat.

Disjunction of contracts: For disjunctions, we require thatat most one disjunct is higher-order and without loss of gen-erality, we assume it is the right disjunct. The reason for thisrestriction is that we must choose at the time of the initialcheck of the contract which disjunct to use—we cannot justtry both because higher-order checks must be delayed. InRacket, disjunction is thus restricted to contracts that are dis-tinguishable in a first-order way, which we simplify to therestriction that only one can be higher-order.

4.2 ReductionsEvaluation is modeled with one-step reduction on programs,P !'" Q. Since the module context consists solely of syn-tactic values, all computation occurs by reduction of the top-level expression. Thus program steps are defined in termsof top-level expression steps, carried out in the context ofseveral module definitions. We model this with a reductionrelation on expressions in a module context, which we write!M ( E !'" E!. We omit the the module context where it

is not used and write E !'" E! instead. Our reduction sys-tem is given with evaluation contexts, which are identical tothose of SCPCF in section 3.

We present the definition of this relation in several parts.

4.2.1 Applications, operations, and conditionalsFirst, the definition of procedure applications, conditionals,and primitive operations is as usual for a call-by-value lan-guage. Primitive operations are interpreted by a # relation(rather than a function), just as in section 3. The reductionrelation for these terms is defined as follows:

Basic reductions E !'" E!

((!X.E) V )! !'" [V/X]E(V V !)! !'" blame!! if #(proc?, V ) ) !(O !V )! !'" A if #(O!, !V ) ) A

if V E E! !'" E if #(false?, V ) ) !if V E E! !'" E! if #(false?, V ) ) tt

Again, we rely on # not only to interpret operations, butalso to determine if a value is a procedure or !; this allowsuniform handling of abstract values, which may (dependingon their remembered contracts) be treated as both true andfalse. We add a reduction to blame!! when applications aremisused; the program has here broken the contract with thelanguage, which is no longer checked statically by the typesystem as it was in SCPCF. Additionally, our rules for iffollow the Lisp tradition, which Racket adopts, in treatingall non-! values as true.

P,Q ::= !MEM,N ::= (module f C V )E,E! ::= f ! | X | A | E E! | if E E E | O !E! | µX.E

| mon!,!! (C,E)U ::= n | tt | ! | (!X.E) | • | (V, V ) | emptyV ::= U/CC,D ::= X | C !"!X.C | flat(E)

| #C,C$ | C % C | C & C | µX.CO ::= add1 | car | cdr | cons | + | = | o? | . . .o? ::= nat? | bool? | empty? | cons? | proc? | false?A ::= V | E [blame!!]

Figure 2. Syntax of Symbolic Core Racket

the module they appear in; this label is used as the nega-tive party for the module’s contract. Applications are alsolabeled; this label is used if the application fails. Pair val-ues and the empty list constant are standard, along with theiroperations. Since the language is untyped, we add standardtype predicates such as nat?.

The new contract forms include pair contracts, #C,D$,conjunction, C&D, and disjunction, C%D, of contracts, andexplicit recursive contracts with contract variables, µX.C.

Contract checks monf,gh (C,E), which will now be in-serted automatically by the operational semantics, take allof their labels from the names of modules, with the thirdlabel h representing the module in which the contract orig-inally appeared. As before, f represents the positive partyto the contract, blamed if the expression does not meet thecontract, and g is the negative party, blamed if the contextdoes not satisfy its obligations. Whenever these annotationscan be inferred from context, we omit them; in particular,in the definition of relations, it is assumed all checks of theform mon(C,E) have identical annotations. We omit labelson applications whenever they provably cannot be blamed,e.g. when the operand is known to be a function.

A blame expression, blame!!! , now indicates that the mod-ule (or the top-level expression) named by " broke its con-tract with "!, which may be the name of a module f , thetop-level expression †, or the language, indicated by !, inthe case of primitive errors.

Syntactic requirements: We make the following assump-tions of initial programs P : programs are closed, every mod-ule reference and application is labeled with the enclosingmodule name, or † for the top-level expression, operationsare applied with the correct arity, abstract values only appearin opaque module definitions, and no monitors or blame ex-pressions appear in source programs.

We also require that recursive contracts be productive,meaning either a function or pair contract constructor mustoccur between binding and reference. We also require thatcontracts in the source program are closed, both with respect

to !-bound and contract variables. Following standard prac-tice, we will say that a contract is higher-order if it syntac-tically contains a function contract; otherwise, the contractis flat. Flat contracts can be checked immediately, whereashigher-order contracts potentially require delayed checks.All predicate contracts are necessarily flat.

Disjunction of contracts: For disjunctions, we require thatat most one disjunct is higher-order and without loss of gen-erality, we assume it is the right disjunct. The reason for thisrestriction is that we must choose at the time of the initialcheck of the contract which disjunct to use—we cannot justtry both because higher-order checks must be delayed. InRacket, disjunction is thus restricted to contracts that are dis-tinguishable in a first-order way, which we simplify to therestriction that only one can be higher-order.

4.2 ReductionsEvaluation is modeled with one-step reduction on programs,P !'" Q. Since the module context consists solely of syn-tactic values, all computation occurs by reduction of the top-level expression. Thus program steps are defined in termsof top-level expression steps, carried out in the context ofseveral module definitions. We model this with a reductionrelation on expressions in a module context, which we write!M ( E !'" E!. We omit the the module context where it

is not used and write E !'" E! instead. Our reduction sys-tem is given with evaluation contexts, which are identical tothose of SCPCF in section 3.

We present the definition of this relation in several parts.

4.2.1 Applications, operations, and conditionalsFirst, the definition of procedure applications, conditionals,and primitive operations is as usual for a call-by-value lan-guage. Primitive operations are interpreted by a # relation(rather than a function), just as in section 3. The reductionrelation for these terms is defined as follows:

Basic reductions E !'" E!

((!X.E) V )! !'" [V/X]E(V V !)! !'" blame!! if #(proc?, V ) ) !(O !V )! !'" A if #(O!, !V ) ) A

if V E E! !'" E if #(false?, V ) ) !if V E E! !'" E! if #(false?, V ) ) tt

Again, we rely on # not only to interpret operations, butalso to determine if a value is a procedure or !; this allowsuniform handling of abstract values, which may (dependingon their remembered contracts) be treated as both true andfalse. We add a reduction to blame!! when applications aremisused; the program has here broken the contract with thelanguage, which is no longer checked statically by the typesystem as it was in SCPCF. Additionally, our rules for iffollow the Lisp tradition, which Racket adopts, in treatingall non-! values as true.

Primitive operations (concrete values) !(O!, "V ) ! A

!(add1, n) ! n+ 1!(+, n,m) ! n+m!(car, (V, V !)) ! V!(cdr, (V, V !)) ! V !

Primitive operations (abstract values)

" V : o?! =# !(o?, V ) ! tt" V : o?" =# !(o?, V ) ! !" V : o? ? =# !(o?, V ) ! •/{flat(bool?)}" V : nat?! =# !(add1, V ) ! •/{flat(nat?)}" V : nat?" =# !(add1!, V ) ! blame!add1" V : nat? ? =# !(add1, V ) ! •/flat(nat?)

$ !(add1!, V ) ! blame!add1" V : cons?! =# !(car, V ) ! #1(V )" V : cons?" =# !(car!, V ) ! blame!car" V : cons? ? =# !(car, V ) ! #1(V )

$ !(car!, V ) ! blame!car

otherwise !(O!, "V ) ! blame!!

Figure 3. Basic operations

4.2.2 Basic operationsBasic operations, as with procedures and conditionals, fol-low SCPCF closely. Operations on concrete values are stan-dard, and we present only a few selected cases. Operationson abstract values are more interesting. A few selected casesare given in figure 3 as examples. Otherwise, the definitionof ! for concrete values is standard and we relegate the re-mainder to the auxiliary materials (§A.2).

When applying base operations to abstract values, the re-sults are potentially complex. For example, add1 • mightproduce any natural number, or it might go wrong, depend-ing on what value • represents. We represent this in ! witha combination of non-determinism, where ! relates an oper-ation and its inputs to multiple answers, as well as abstractvalues as results, to handle the arbitrary natural numbers orbooleans that might be produced. A representative selectionof the ! definition for abstract values is presented in figure 3.

The definition of ! relies on a proof system relatingpredicates and values, just as with contract checking. Here," V : o?! means that V is known to satisfy o?, " V : o?"means that V is known not to satisfy o?, and " V : o? ?means neither is known. For example, " 7 : nat?!, " tt :cons?", and " • : o? ? for any o?. (Again, our system isparametric with respect to this proof system, although wepresent a useful instance in section 4.3.) Finally, if no casematches, then an appropriate error is produced.

Labels on operations come from the application site of theoperation in the program, e.g., (add1 5)!, so that the appro-priate module can be blamed when primitive operations are

misused, as in the last case, and are omitted where irrelevant.When primitive operations are misused, the violated contractis on !, standing for the programming language itself, justas in the rule for application of non-functions.

4.2.3 Module referencesTo handle references to module-bound variables, we definea module environment that describes the module context "M .Using the module reference annotation, the environment dis-tinguishes between self references and external references.When an external module is referenced (f %= g), its valueis wrapped in a contract check; a self-reference is resolvedto its (unchecked) value. This distinction implements the no-tion of “contracts as boundaries” [17], in other words, con-tracts are an agreement between the module and its context,and the module can behave internally as it likes.

Module references "M " fg &'( E

"M " ff &'( V if (module f C V )) "M"M " fg &'( monf,gf (C, V ) if (module f C V )) "M"M " fg &'( monf,gf (C, • · C) if (module f C •)) "M

4.2.4 Contract checkingWith the basic rules handled, we now turn to the heart of thesystem, contract checking. As in section 3, as computation iscarried out, we can discover properties of values that may beuseful in subsequently avoiding spurious contract errors. Ourprimary mechanism for remembering such discoveries is toadd properties, encoded as contracts, to values as soon as thecomputational process proves them. If a value passes a flatcontract check, we add the checked contract to the value’sremembered set. Subsequent checks of the same contract arethus avoided. We divide contract checking reductions intotwo categories, those for flat contracts and those for higher-order contracts, and consider each in turn.

Flat contracts: First, checking flat contracts is handled bythree rules, presented in figure 4, depending on whether thevalue has already passed the relevant contract.

The first two rules consider the case where the valuedefinitely does pass the contract, written " V : C ! (“Vproves C”), or does not pass, written " V : C " (“V refutesC”). If neither of these is the case, written " V : C ?, thethird rule implements a contract check by compiling it toan if-expression. The test is an application of the functiongenerated by FC(C) to V . If the test succeeds, V · C isproduced. Otherwise, the positive party, here f , is blamedfor breaking the contract on h.

The three judgments checking the relation between valuesand contracts are a simple proof system; by parameterizingover these relations, we enable our system to make use ofsophisticated existing decision procedures. For the moment,

Primitive operations (concrete values) !(O!, "V ) ! A

!(add1, n) ! n+ 1!(+, n,m) ! n+m!(car, (V, V !)) ! V!(cdr, (V, V !)) ! V !

Primitive operations (abstract values)

" V : o?! =# !(o?, V ) ! tt" V : o?" =# !(o?, V ) ! !" V : o? ? =# !(o?, V ) ! •/{flat(bool?)}" V : nat?! =# !(add1, V ) ! •/{flat(nat?)}" V : nat?" =# !(add1!, V ) ! blame!add1" V : nat? ? =# !(add1, V ) ! •/flat(nat?)

$ !(add1!, V ) ! blame!add1" V : cons?! =# !(car, V ) ! #1(V )" V : cons?" =# !(car!, V ) ! blame!car" V : cons? ? =# !(car, V ) ! #1(V )

$ !(car!, V ) ! blame!car

otherwise !(O!, "V ) ! blame!!

Figure 3. Basic operations

4.2.2 Basic operationsBasic operations, as with procedures and conditionals, fol-low SCPCF closely. Operations on concrete values are stan-dard, and we present only a few selected cases. Operationson abstract values are more interesting. A few selected casesare given in figure 3 as examples. Otherwise, the definitionof ! for concrete values is standard and we relegate the re-mainder to the auxiliary materials (§A.2).

When applying base operations to abstract values, the re-sults are potentially complex. For example, add1 • mightproduce any natural number, or it might go wrong, depend-ing on what value • represents. We represent this in ! witha combination of non-determinism, where ! relates an oper-ation and its inputs to multiple answers, as well as abstractvalues as results, to handle the arbitrary natural numbers orbooleans that might be produced. A representative selectionof the ! definition for abstract values is presented in figure 3.

The definition of ! relies on a proof system relatingpredicates and values, just as with contract checking. Here," V : o?! means that V is known to satisfy o?, " V : o?"means that V is known not to satisfy o?, and " V : o? ?means neither is known. For example, " 7 : nat?!, " tt :cons?", and " • : o? ? for any o?. (Again, our system isparametric with respect to this proof system, although wepresent a useful instance in section 4.3.) Finally, if no casematches, then an appropriate error is produced.

Labels on operations come from the application site of theoperation in the program, e.g., (add1 5)!, so that the appro-priate module can be blamed when primitive operations are

misused, as in the last case, and are omitted where irrelevant.When primitive operations are misused, the violated contractis on !, standing for the programming language itself, justas in the rule for application of non-functions.

4.2.3 Module referencesTo handle references to module-bound variables, we definea module environment that describes the module context "M .Using the module reference annotation, the environment dis-tinguishes between self references and external references.When an external module is referenced (f %= g), its valueis wrapped in a contract check; a self-reference is resolvedto its (unchecked) value. This distinction implements the no-tion of “contracts as boundaries” [17], in other words, con-tracts are an agreement between the module and its context,and the module can behave internally as it likes.

Module references "M " fg &'( E

"M " ff &'( V if (module f C V )) "M"M " fg &'( monf,gf (C, V ) if (module f C V )) "M"M " fg &'( monf,gf (C, • · C) if (module f C •)) "M

4.2.4 Contract checkingWith the basic rules handled, we now turn to the heart of thesystem, contract checking. As in section 3, as computation iscarried out, we can discover properties of values that may beuseful in subsequently avoiding spurious contract errors. Ourprimary mechanism for remembering such discoveries is toadd properties, encoded as contracts, to values as soon as thecomputational process proves them. If a value passes a flatcontract check, we add the checked contract to the value’sremembered set. Subsequent checks of the same contract arethus avoided. We divide contract checking reductions intotwo categories, those for flat contracts and those for higher-order contracts, and consider each in turn.

Flat contracts: First, checking flat contracts is handled bythree rules, presented in figure 4, depending on whether thevalue has already passed the relevant contract.

The first two rules consider the case where the valuedefinitely does pass the contract, written " V : C ! (“Vproves C”), or does not pass, written " V : C " (“V refutesC”). If neither of these is the case, written " V : C ?, thethird rule implements a contract check by compiling it toan if-expression. The test is an application of the functiongenerated by FC(C) to V . If the test succeeds, V · C isproduced. Otherwise, the positive party, here f , is blamedfor breaking the contract on h.

The three judgments checking the relation between valuesand contracts are a simple proof system; by parameterizingover these relations, we enable our system to make use ofsophisticated existing decision procedures. For the moment,

Primitive operations (concrete values) !(O!, "V ) ! A

!(add1, n) ! n+ 1!(+, n,m) ! n+m!(car, (V, V !)) ! V!(cdr, (V, V !)) ! V !

Primitive operations (abstract values)

" V : o?! =# !(o?, V ) ! tt" V : o?" =# !(o?, V ) ! !" V : o? ? =# !(o?, V ) ! •/{flat(bool?)}" V : nat?! =# !(add1, V ) ! •/{flat(nat?)}" V : nat?" =# !(add1!, V ) ! blame!add1" V : nat? ? =# !(add1, V ) ! •/flat(nat?)

$ !(add1!, V ) ! blame!add1" V : cons?! =# !(car, V ) ! #1(V )" V : cons?" =# !(car!, V ) ! blame!car" V : cons? ? =# !(car, V ) ! #1(V )

$ !(car!, V ) ! blame!car

otherwise !(O!, "V ) ! blame!!

Figure 3. Basic operations

4.2.2 Basic operationsBasic operations, as with procedures and conditionals, fol-low SCPCF closely. Operations on concrete values are stan-dard, and we present only a few selected cases. Operationson abstract values are more interesting. A few selected casesare given in figure 3 as examples. Otherwise, the definitionof ! for concrete values is standard and we relegate the re-mainder to the auxiliary materials (§A.2).

When applying base operations to abstract values, the re-sults are potentially complex. For example, add1 • mightproduce any natural number, or it might go wrong, depend-ing on what value • represents. We represent this in ! witha combination of non-determinism, where ! relates an oper-ation and its inputs to multiple answers, as well as abstractvalues as results, to handle the arbitrary natural numbers orbooleans that might be produced. A representative selectionof the ! definition for abstract values is presented in figure 3.

The definition of ! relies on a proof system relatingpredicates and values, just as with contract checking. Here," V : o?! means that V is known to satisfy o?, " V : o?"means that V is known not to satisfy o?, and " V : o? ?means neither is known. For example, " 7 : nat?!, " tt :cons?", and " • : o? ? for any o?. (Again, our system isparametric with respect to this proof system, although wepresent a useful instance in section 4.3.) Finally, if no casematches, then an appropriate error is produced.

Labels on operations come from the application site of theoperation in the program, e.g., (add1 5)!, so that the appro-priate module can be blamed when primitive operations are

misused, as in the last case, and are omitted where irrelevant.When primitive operations are misused, the violated contractis on !, standing for the programming language itself, justas in the rule for application of non-functions.

4.2.3 Module referencesTo handle references to module-bound variables, we definea module environment that describes the module context "M .Using the module reference annotation, the environment dis-tinguishes between self references and external references.When an external module is referenced (f %= g), its valueis wrapped in a contract check; a self-reference is resolvedto its (unchecked) value. This distinction implements the no-tion of “contracts as boundaries” [17], in other words, con-tracts are an agreement between the module and its context,and the module can behave internally as it likes.

Module references "M " fg &'( E

"M " ff &'( V if (module f C V )) "M"M " fg &'( monf,gf (C, V ) if (module f C V )) "M"M " fg &'( monf,gf (C, • · C) if (module f C •)) "M

4.2.4 Contract checkingWith the basic rules handled, we now turn to the heart of thesystem, contract checking. As in section 3, as computation iscarried out, we can discover properties of values that may beuseful in subsequently avoiding spurious contract errors. Ourprimary mechanism for remembering such discoveries is toadd properties, encoded as contracts, to values as soon as thecomputational process proves them. If a value passes a flatcontract check, we add the checked contract to the value’sremembered set. Subsequent checks of the same contract arethus avoided. We divide contract checking reductions intotwo categories, those for flat contracts and those for higher-order contracts, and consider each in turn.

Flat contracts: First, checking flat contracts is handled bythree rules, presented in figure 4, depending on whether thevalue has already passed the relevant contract.

The first two rules consider the case where the valuedefinitely does pass the contract, written " V : C ! (“Vproves C”), or does not pass, written " V : C " (“V refutesC”). If neither of these is the case, written " V : C ?, thethird rule implements a contract check by compiling it toan if-expression. The test is an application of the functiongenerated by FC(C) to V . If the test succeeds, V · C isproduced. Otherwise, the positive party, here f , is blamedfor breaking the contract on h.

The three judgments checking the relation between valuesand contracts are a simple proof system; by parameterizingover these relations, we enable our system to make use ofsophisticated existing decision procedures. For the moment,

Flat contract reduction mon(C, V ) !"# E!

monf,gh (C, V ) !"# V · C if C is flat and $ V : C !

monf,gh (C, V ) !"# blamefh if C is flat and $ V : C "

monf,gh (C, V ) !"# if (FC(C) V ) (V · C) blamefhif C is flat and $ V : C ?

Flat contract checking FC(C) = E

FC(µX.C) = µX.FC(C)FC(X) = X

FC(flat(E)) = EFC(C1 % C2) = !y.if (FC(C1) y) (FC(C2) y) !FC(C1 & C2) = !y.if (FC(C1) y) tt (FC(C2) y)FC('C1,C2() =!y.(and (cons? y) (FC(C1) (car y)) (FC(C2) (cdr y)))

Figure 4. Flat contracts

the key property is that $ V · C : C ! holds, just as in sec-tion 3.4, and further details are discussed in section 4.3.

Compiling flat checks to predicates: The FC metafunc-tion, also in figure 4, takes a flat contract and produces thesource code of a function, which when applied to a valueproduces true or false indicating whether the value passes thecontract. The additional complexity over the similar rules ofsections 2 and 3 handles the addition of flat contracts con-taining recursive contracts, disjunctive and conjunctive con-tracts, and pair contracts. In particular, to check disjunctivecontracts, we must test if the left disjunct passes the contract,and branch on the result, whereas our earlier reduction rulesfor flat contracts simply fail for contracts that don’t pass.

As an example, the expression monf,gh (flat(nat?), V ) re-duces to if (nat? V ) V blamefh, but using this reduction tocheck the left disjunct of mon(flat(nat?) & flat(bool?), tt)would cause a blame error, which is obviously not the in-tended result. Instead, the rules for FC generate the checkif ((nat? tt) & (bool? tt)) tt blame, which then succeeds.

Higher-order contracts: The next set of reduction rules,presented in figure 5, defines the behavior of higher-ordercontract checks; we assume here that the contract is not flat.

In the first rule, we again use the !-expansion techniquepioneered by Findler and Felleisen [17] to decompose ahigher-order contract into subcomponents. This rule only ap-plies if the contracted value V is indeed a function, as indi-cated by proc? (In SCPCF, this side-condition is unneces-sary thanks to the type system). Otherwise, the second ruleblames the positive party of a function contract when thesupplied value is not a function.

The remaining rules handle higher-order contracts thatare not immediately function contracts, such as pairs of func-tion contracts. The first two are for pair contracts. If the valueis determined to be a pair by cons?, then the components are

Function contract reduction mon(C, V ) !"# E!

monf,gh (C !#!X.D, V ) !"#(!X.monf,gh (D, (V mong,fh (C,X))))

if "(proc?, V ) ) tt

monf,gh (C !#!X.D, V ) !"# blamefh if "(proc?, V ) ) !

Other higher-order contract reductions

mon('C,D(, V ) !"#(cons mon(C, car V !)mon(D, cdr V !))

if "(cons?, V ) ) tt and V ! = V · flat(cons?)monf,gh ('C,D(, V ) !"# blamefh if "(cons?, V ) ) !

mon(µX.C, V ) !"# mon([µX.C/X]C, V )

mon(C %D,V ) !"# mon(D,mon(C, V ))

mon(C &D,V ) !"# if (FC(C) V ) (V · C)mon(D,V )if $ V : C ?

mon(C &D,V ) !"# V if $ V : C !

mon(C &D,V ) !"# mon(D,V ) if $ V : C "

Figure 5. Higher-order contract reduction

extracted using car and cdr and checked against the rele-vant portions of the contract. Otherwise, then the programreduces to blame, analogous to function contracts.

The last set of rules decompose combinations of higher-order contracts. Recursive contracts are unrolled. (Produc-tivity ensures that contracts do not unroll forever.) Conjunc-tions are split into their components, with the left checkedbefore the right. For higher-order disjunctions, we rely onthe invariant that only the right disjunct is higher-order anduse FC for the check of the left. When possible, we omit thischeck by using the proof system (see the final two rules).

4.2.5 Applying abstract valuesAgain, application of abstract values poses a challenge, justas it did in section 3. In contrast, the system must nowexplore more possible behaviors of abstract operators andit can no longer be guided by the type. Fortunately, abstractvalues provide the tools to express the needed computation.

Applying abstract values E !"# E! where !V = •/C!V V ! !"# •/{[!V /X]D | (C !#!X.D) * C}

if "(proc?, !V ) ) tt!V V ! !"# havoc V ! if "(proc?, !V ) ) tt

havoc = µy.(!x.AMB({y (x •), y (car x), y (cdr x)}))

AMB({E}) = EAMB({E,E1, . . . }) = if • E AMB({E1, . . . })

Flat contract reduction mon(C, V ) !"# E!

monf,gh (C, V ) !"# V · C if C is flat and $ V : C !

monf,gh (C, V ) !"# blamefh if C is flat and $ V : C "

monf,gh (C, V ) !"# if (FC(C) V ) (V · C) blamefhif C is flat and $ V : C ?

Flat contract checking FC(C) = E

FC(µX.C) = µX.FC(C)FC(X) = X

FC(flat(E)) = EFC(C1 % C2) = !y.if (FC(C1) y) (FC(C2) y) !FC(C1 & C2) = !y.if (FC(C1) y) tt (FC(C2) y)FC('C1,C2() =!y.(and (cons? y) (FC(C1) (car y)) (FC(C2) (cdr y)))

Figure 4. Flat contracts

the key property is that $ V · C : C ! holds, just as in sec-tion 3.4, and further details are discussed in section 4.3.

Compiling flat checks to predicates: The FC metafunc-tion, also in figure 4, takes a flat contract and produces thesource code of a function, which when applied to a valueproduces true or false indicating whether the value passes thecontract. The additional complexity over the similar rules ofsections 2 and 3 handles the addition of flat contracts con-taining recursive contracts, disjunctive and conjunctive con-tracts, and pair contracts. In particular, to check disjunctivecontracts, we must test if the left disjunct passes the contract,and branch on the result, whereas our earlier reduction rulesfor flat contracts simply fail for contracts that don’t pass.

As an example, the expression monf,gh (flat(nat?), V ) re-duces to if (nat? V ) V blamefh, but using this reduction tocheck the left disjunct of mon(flat(nat?) & flat(bool?), tt)would cause a blame error, which is obviously not the in-tended result. Instead, the rules for FC generate the checkif ((nat? tt) & (bool? tt)) tt blame, which then succeeds.

Higher-order contracts: The next set of reduction rules,presented in figure 5, defines the behavior of higher-ordercontract checks; we assume here that the contract is not flat.

In the first rule, we again use the !-expansion techniquepioneered by Findler and Felleisen [17] to decompose ahigher-order contract into subcomponents. This rule only ap-plies if the contracted value V is indeed a function, as indi-cated by proc? (In SCPCF, this side-condition is unneces-sary thanks to the type system). Otherwise, the second ruleblames the positive party of a function contract when thesupplied value is not a function.

The remaining rules handle higher-order contracts thatare not immediately function contracts, such as pairs of func-tion contracts. The first two are for pair contracts. If the valueis determined to be a pair by cons?, then the components are

Function contract reduction mon(C, V ) !"# E!

monf,gh (C !#!X.D, V ) !"#(!X.monf,gh (D, (V mong,fh (C,X))))

if "(proc?, V ) ) tt

monf,gh (C !#!X.D, V ) !"# blamefh if "(proc?, V ) ) !

Other higher-order contract reductions

mon('C,D(, V ) !"#(cons mon(C, car V !)mon(D, cdr V !))

if "(cons?, V ) ) tt and V ! = V · flat(cons?)monf,gh ('C,D(, V ) !"# blamefh if "(cons?, V ) ) !

mon(µX.C, V ) !"# mon([µX.C/X]C, V )

mon(C %D,V ) !"# mon(D,mon(C, V ))

mon(C &D,V ) !"# if (FC(C) V ) (V · C)mon(D,V )if $ V : C ?

mon(C &D,V ) !"# V if $ V : C !

mon(C &D,V ) !"# mon(D,V ) if $ V : C "

Figure 5. Higher-order contract reduction

extracted using car and cdr and checked against the rele-vant portions of the contract. Otherwise, then the programreduces to blame, analogous to function contracts.

The last set of rules decompose combinations of higher-order contracts. Recursive contracts are unrolled. (Produc-tivity ensures that contracts do not unroll forever.) Conjunc-tions are split into their components, with the left checkedbefore the right. For higher-order disjunctions, we rely onthe invariant that only the right disjunct is higher-order anduse FC for the check of the left. When possible, we omit thischeck by using the proof system (see the final two rules).

4.2.5 Applying abstract valuesAgain, application of abstract values poses a challenge, justas it did in section 3. In contrast, the system must nowexplore more possible behaviors of abstract operators andit can no longer be guided by the type. Fortunately, abstractvalues provide the tools to express the needed computation.

Applying abstract values E !"# E! where !V = •/C!V V ! !"# •/{[!V /X]D | (C !#!X.D) * C}

if "(proc?, !V ) ) tt!V V ! !"# havoc V ! if "(proc?, !V ) ) tt

havoc = µy.(!x.AMB({y (x •), y (car x), y (cdr x)}))

AMB({E}) = EAMB({E,E1, . . . }) = if • E AMB({E1, . . . })

Flat contract reduction mon(C, V ) !"# E!

monf,gh (C, V ) !"# V · C if C is flat and $ V : C !

monf,gh (C, V ) !"# blamefh if C is flat and $ V : C "

monf,gh (C, V ) !"# if (FC(C) V ) (V · C) blamefhif C is flat and $ V : C ?

Flat contract checking FC(C) = E

FC(µX.C) = µX.FC(C)FC(X) = X

FC(flat(E)) = EFC(C1 % C2) = !y.if (FC(C1) y) (FC(C2) y) !FC(C1 & C2) = !y.if (FC(C1) y) tt (FC(C2) y)FC('C1,C2() =!y.(and (cons? y) (FC(C1) (car y)) (FC(C2) (cdr y)))

Figure 4. Flat contracts

the key property is that $ V · C : C ! holds, just as in sec-tion 3.4, and further details are discussed in section 4.3.

Compiling flat checks to predicates: The FC metafunc-tion, also in figure 4, takes a flat contract and produces thesource code of a function, which when applied to a valueproduces true or false indicating whether the value passes thecontract. The additional complexity over the similar rules ofsections 2 and 3 handles the addition of flat contracts con-taining recursive contracts, disjunctive and conjunctive con-tracts, and pair contracts. In particular, to check disjunctivecontracts, we must test if the left disjunct passes the contract,and branch on the result, whereas our earlier reduction rulesfor flat contracts simply fail for contracts that don’t pass.

As an example, the expression monf,gh (flat(nat?), V ) re-duces to if (nat? V ) V blamefh, but using this reduction tocheck the left disjunct of mon(flat(nat?) & flat(bool?), tt)would cause a blame error, which is obviously not the in-tended result. Instead, the rules for FC generate the checkif ((nat? tt) & (bool? tt)) tt blame, which then succeeds.

Higher-order contracts: The next set of reduction rules,presented in figure 5, defines the behavior of higher-ordercontract checks; we assume here that the contract is not flat.

In the first rule, we again use the !-expansion techniquepioneered by Findler and Felleisen [17] to decompose ahigher-order contract into subcomponents. This rule only ap-plies if the contracted value V is indeed a function, as indi-cated by proc? (In SCPCF, this side-condition is unneces-sary thanks to the type system). Otherwise, the second ruleblames the positive party of a function contract when thesupplied value is not a function.

The remaining rules handle higher-order contracts thatare not immediately function contracts, such as pairs of func-tion contracts. The first two are for pair contracts. If the valueis determined to be a pair by cons?, then the components are

Function contract reduction mon(C, V ) !"# E!

monf,gh (C !#!X.D, V ) !"#(!X.monf,gh (D, (V mong,fh (C,X))))

if "(proc?, V ) ) tt

monf,gh (C !#!X.D, V ) !"# blamefh if "(proc?, V ) ) !

Other higher-order contract reductions

mon('C,D(, V ) !"#(cons mon(C, car V !)mon(D, cdr V !))

if "(cons?, V ) ) tt and V ! = V · flat(cons?)monf,gh ('C,D(, V ) !"# blamefh if "(cons?, V ) ) !

mon(µX.C, V ) !"# mon([µX.C/X]C, V )

mon(C %D,V ) !"# mon(D,mon(C, V ))

mon(C &D,V ) !"# if (FC(C) V ) (V · C)mon(D,V )if $ V : C ?

mon(C &D,V ) !"# V if $ V : C !

mon(C &D,V ) !"# mon(D,V ) if $ V : C "

Figure 5. Higher-order contract reduction

extracted using car and cdr and checked against the rele-vant portions of the contract. Otherwise, then the programreduces to blame, analogous to function contracts.

The last set of rules decompose combinations of higher-order contracts. Recursive contracts are unrolled. (Produc-tivity ensures that contracts do not unroll forever.) Conjunc-tions are split into their components, with the left checkedbefore the right. For higher-order disjunctions, we rely onthe invariant that only the right disjunct is higher-order anduse FC for the check of the left. When possible, we omit thischeck by using the proof system (see the final two rules).

4.2.5 Applying abstract valuesAgain, application of abstract values poses a challenge, justas it did in section 3. In contrast, the system must nowexplore more possible behaviors of abstract operators andit can no longer be guided by the type. Fortunately, abstractvalues provide the tools to express the needed computation.

Applying abstract values E !"# E! where !V = •/C!V V ! !"# •/{[!V /X]D | (C !#!X.D) * C}

if "(proc?, !V ) ) tt!V V ! !"# havoc V ! if "(proc?, !V ) ) tt

havoc = µy.(!x.AMB({y (x •), y (car x), y (cdr x)}))

AMB({E}) = EAMB({E,E1, . . . }) = if • E AMB({E1, . . . })

Flat contract reduction mon(C, V ) !"# E!

monf,gh (C, V ) !"# V · C if C is flat and $ V : C !

monf,gh (C, V ) !"# blamefh if C is flat and $ V : C "

monf,gh (C, V ) !"# if (FC(C) V ) (V · C) blamefhif C is flat and $ V : C ?

Flat contract checking FC(C) = E

FC(µX.C) = µX.FC(C)FC(X) = X

FC(flat(E)) = EFC(C1 % C2) = !y.if (FC(C1) y) (FC(C2) y) !FC(C1 & C2) = !y.if (FC(C1) y) tt (FC(C2) y)FC('C1,C2() =!y.(and (cons? y) (FC(C1) (car y)) (FC(C2) (cdr y)))

Figure 4. Flat contracts

the key property is that $ V · C : C ! holds, just as in sec-tion 3.4, and further details are discussed in section 4.3.

Compiling flat checks to predicates: The FC metafunc-tion, also in figure 4, takes a flat contract and produces thesource code of a function, which when applied to a valueproduces true or false indicating whether the value passes thecontract. The additional complexity over the similar rules ofsections 2 and 3 handles the addition of flat contracts con-taining recursive contracts, disjunctive and conjunctive con-tracts, and pair contracts. In particular, to check disjunctivecontracts, we must test if the left disjunct passes the contract,and branch on the result, whereas our earlier reduction rulesfor flat contracts simply fail for contracts that don’t pass.

As an example, the expression monf,gh (flat(nat?), V ) re-duces to if (nat? V ) V blamefh, but using this reduction tocheck the left disjunct of mon(flat(nat?) & flat(bool?), tt)would cause a blame error, which is obviously not the in-tended result. Instead, the rules for FC generate the checkif ((nat? tt) & (bool? tt)) tt blame, which then succeeds.

Higher-order contracts: The next set of reduction rules,presented in figure 5, defines the behavior of higher-ordercontract checks; we assume here that the contract is not flat.

In the first rule, we again use the !-expansion techniquepioneered by Findler and Felleisen [17] to decompose ahigher-order contract into subcomponents. This rule only ap-plies if the contracted value V is indeed a function, as indi-cated by proc? (In SCPCF, this side-condition is unneces-sary thanks to the type system). Otherwise, the second ruleblames the positive party of a function contract when thesupplied value is not a function.

The remaining rules handle higher-order contracts thatare not immediately function contracts, such as pairs of func-tion contracts. The first two are for pair contracts. If the valueis determined to be a pair by cons?, then the components are

Function contract reduction mon(C, V ) !"# E!

monf,gh (C !#!X.D, V ) !"#(!X.monf,gh (D, (V mong,fh (C,X))))

if "(proc?, V ) ) tt

monf,gh (C !#!X.D, V ) !"# blamefh if "(proc?, V ) ) !

Other higher-order contract reductions

mon('C,D(, V ) !"#(cons mon(C, car V !)mon(D, cdr V !))

if "(cons?, V ) ) tt and V ! = V · flat(cons?)monf,gh ('C,D(, V ) !"# blamefh if "(cons?, V ) ) !

mon(µX.C, V ) !"# mon([µX.C/X]C, V )

mon(C %D,V ) !"# mon(D,mon(C, V ))

mon(C &D,V ) !"# if (FC(C) V ) (V · C)mon(D,V )if $ V : C ?

mon(C &D,V ) !"# V if $ V : C !

mon(C &D,V ) !"# mon(D,V ) if $ V : C "

Figure 5. Higher-order contract reduction

extracted using car and cdr and checked against the rele-vant portions of the contract. Otherwise, then the programreduces to blame, analogous to function contracts.

The last set of rules decompose combinations of higher-order contracts. Recursive contracts are unrolled. (Produc-tivity ensures that contracts do not unroll forever.) Conjunc-tions are split into their components, with the left checkedbefore the right. For higher-order disjunctions, we rely onthe invariant that only the right disjunct is higher-order anduse FC for the check of the left. When possible, we omit thischeck by using the proof system (see the final two rules).

4.2.5 Applying abstract valuesAgain, application of abstract values poses a challenge, justas it did in section 3. In contrast, the system must nowexplore more possible behaviors of abstract operators andit can no longer be guided by the type. Fortunately, abstractvalues provide the tools to express the needed computation.

Applying abstract values E !"# E! where !V = •/C!V V ! !"# •/{[!V /X]D | (C !#!X.D) * C}

if "(proc?, !V ) ) tt!V V ! !"# havoc V ! if "(proc?, !V ) ) tt

havoc = µy.(!x.AMB({y (x •), y (car x), y (cdr x)}))

AMB({E}) = EAMB({E,E1, . . . }) = if • E AMB({E1, . . . })

Flat contract reduction mon(C, V ) !"# E!

monf,gh (C, V ) !"# V · C if C is flat and $ V : C !

monf,gh (C, V ) !"# blamefh if C is flat and $ V : C "

monf,gh (C, V ) !"# if (FC(C) V ) (V · C) blamefhif C is flat and $ V : C ?

Flat contract checking FC(C) = E

FC(µX.C) = µX.FC(C)FC(X) = X

FC(flat(E)) = EFC(C1 % C2) = !y.if (FC(C1) y) (FC(C2) y) !FC(C1 & C2) = !y.if (FC(C1) y) tt (FC(C2) y)FC('C1,C2() =!y.(and (cons? y) (FC(C1) (car y)) (FC(C2) (cdr y)))

Figure 4. Flat contracts

the key property is that $ V · C : C ! holds, just as in sec-tion 3.4, and further details are discussed in section 4.3.

Compiling flat checks to predicates: The FC metafunc-tion, also in figure 4, takes a flat contract and produces thesource code of a function, which when applied to a valueproduces true or false indicating whether the value passes thecontract. The additional complexity over the similar rules ofsections 2 and 3 handles the addition of flat contracts con-taining recursive contracts, disjunctive and conjunctive con-tracts, and pair contracts. In particular, to check disjunctivecontracts, we must test if the left disjunct passes the contract,and branch on the result, whereas our earlier reduction rulesfor flat contracts simply fail for contracts that don’t pass.

As an example, the expression monf,gh (flat(nat?), V ) re-duces to if (nat? V ) V blamefh, but using this reduction tocheck the left disjunct of mon(flat(nat?) & flat(bool?), tt)would cause a blame error, which is obviously not the in-tended result. Instead, the rules for FC generate the checkif ((nat? tt) & (bool? tt)) tt blame, which then succeeds.

Higher-order contracts: The next set of reduction rules,presented in figure 5, defines the behavior of higher-ordercontract checks; we assume here that the contract is not flat.

In the first rule, we again use the !-expansion techniquepioneered by Findler and Felleisen [17] to decompose ahigher-order contract into subcomponents. This rule only ap-plies if the contracted value V is indeed a function, as indi-cated by proc? (In SCPCF, this side-condition is unneces-sary thanks to the type system). Otherwise, the second ruleblames the positive party of a function contract when thesupplied value is not a function.

The remaining rules handle higher-order contracts thatare not immediately function contracts, such as pairs of func-tion contracts. The first two are for pair contracts. If the valueis determined to be a pair by cons?, then the components are

Function contract reduction mon(C, V ) !"# E!

monf,gh (C !#!X.D, V ) !"#(!X.monf,gh (D, (V mong,fh (C,X))))

if "(proc?, V ) ) tt

monf,gh (C !#!X.D, V ) !"# blamefh if "(proc?, V ) ) !

Other higher-order contract reductions

mon('C,D(, V ) !"#(cons mon(C, car V !)mon(D, cdr V !))

if "(cons?, V ) ) tt and V ! = V · flat(cons?)monf,gh ('C,D(, V ) !"# blamefh if "(cons?, V ) ) !

mon(µX.C, V ) !"# mon([µX.C/X]C, V )

mon(C %D,V ) !"# mon(D,mon(C, V ))

mon(C &D,V ) !"# if (FC(C) V ) (V · C)mon(D,V )if $ V : C ?

mon(C &D,V ) !"# V if $ V : C !

mon(C &D,V ) !"# mon(D,V ) if $ V : C "

Figure 5. Higher-order contract reduction

extracted using car and cdr and checked against the rele-vant portions of the contract. Otherwise, then the programreduces to blame, analogous to function contracts.

The last set of rules decompose combinations of higher-order contracts. Recursive contracts are unrolled. (Produc-tivity ensures that contracts do not unroll forever.) Conjunc-tions are split into their components, with the left checkedbefore the right. For higher-order disjunctions, we rely onthe invariant that only the right disjunct is higher-order anduse FC for the check of the left. When possible, we omit thischeck by using the proof system (see the final two rules).

4.2.5 Applying abstract valuesAgain, application of abstract values poses a challenge, justas it did in section 3. In contrast, the system must nowexplore more possible behaviors of abstract operators andit can no longer be guided by the type. Fortunately, abstractvalues provide the tools to express the needed computation.

Applying abstract values E !"# E! where !V = •/C!V V ! !"# •/{[!V /X]D | (C !#!X.D) * C}

if "(proc?, !V ) ) tt!V V ! !"# havoc V ! if "(proc?, !V ) ) tt

havoc = µy.(!x.AMB({y (x •), y (car x), y (cdr x)}))

AMB({E}) = EAMB({E,E1, . . . }) = if • E AMB({E1, . . . })

The behavior of abstract values, which are created byreferences to opaque modules, is handled in much the sameway as in SCPCF. When an abstract function is applied, thereare again two possible scenarios: (1) the abstract functionreturns an abstract value or (2) the argument escapes intoan unknown context that causes the value to be blamed. Weagain make use of a havoc function for discovering if thepossibility of blame exists. In contrast to the typed setting ofSCPCF, we need only one such value. The demonic contextis a universal context that will produce blame if it there existsa context that produces blame originating from the value. Ifthe universal demonic context cannot produce blame, onlythe range value is produced.

The havoc function is implemented as a recursive func-tion that makes a non-deterministic choice as to how to treatits argument—it either applies the argument to the least-specific value, •, or selects one component of it, and thenrecurs on the result of its choice. This subjects the inputvalue to all possible behavior that a context might have. Notethat the demonic context might itself be blamed; we implic-itly label the expressions in the demonic context with a dis-tinguished label and disregard these spurious errors in theproof of soundness. We use the AMB metafunction to imple-ment the non-determinism of havoc; AMB uses an if test ofan opaque value, which reduces to both branches.

4.3 Proof systemCompared to the very simple proof system of section 3.4, thesystem for proving or refuting whether a given value satisfiesa contract in Core Racket is more sophisticated, although thegeneral principles remain the same.

In particular, we rely on three different kinds of judg-ments that relate values and contracts: proves, refutes, andneither. The first, ! V : C ! includes the original judgmentthat a value proves a contract if it remembers that contract.Additionally, we add judgements for reasoning about typepredicates in the language. For example if a value is knownto satisfy a particular base predicate, written ! V : o?!,then the value satisfies the contract flat(o?). This relies onthe relation between values and predicates used above in thedefinition of !, which is defined in a straightforward way.

The refutes relation is more interesting and relies on addi-tional semantic knowledge, such as the disjointness of datatypes. For instance, a value that remembers it is a proce-dure, refutes all pair contracts and the pair? predicate con-tract. Other refutes judgments are straightforward based onstructural decomposition of contracts and values.

The complete definition of these relations is given in theauxiliary materials (§A.3). Our implementation, described insection 6, incorporates a richer set of rules for improvedreasoning. The implementation is naive but effective forbasic semantic reasoning, however it essentially does nosophisticated reasoning about base type domains such asnumbers, strings, or lists. The tool could immediately benefit

from leveraging an external solver to decide properties ofconcrete values.

4.4 Improving precision via non-determinismSince our reduction rules, and in particular the ! relation,make use of the remembered contracts on values, makingthese contracts as specific as possible improves precision ofthe results.

Improving precision via non-determinism !V "#$ !V !

•/C ·% {C1 & C2} "#$ •/C % {Ci} i ' {1, 2}•/C ·% {µX.C} "#$ •/C % {[µX.C/X]C}

The two rules above increase the specificity of abstractvalues. The first rule splits abstract values known to sat-isfy a disjunctive contract. For example, •/{flat(nat?) &flat(bool?)} "#$ •/flat(nat?) and •/flat(bool?). This con-verts the imprecision of the value into non-determinism inthe reduction relation, and makes subsequent uses of ! moreprecise on the two resulting values. Similarly, we unfoldrecursive contracts in abstract values; this exposes furtherdisjunctions to split, as with a contract for lists.

As an example of the effectiveness of this simple ap-proach, consider the list length function:

(module length(provide [len (list/c -> nat?)])(define (len l)

(if (empty? l) 0 (+ 1 (len (cdr l))))))

When applied to the symbolic value

• · µx.(flat(empty?) & (flat(nat?),x))

which is the definition of list/c, we immediately unroll andsplit the abstract value, meaning that we evaluate the body oflen in exactly the two cases it is designed to handle, with aprecise result for each. Without this splitting, the test wouldreturn both tt and !, and the semantics would attempt totake the cdr of the empty list, even though the function willnever fail on concrete inputs. This provides some of thebenefits of occurrence typing [41] simply by exploiting thenon-determinism inherent in the reduction semantics.

4.5 Evaluation and SoundnessWe now define evaluation of entire modular programs, andprove soundness for our abstract reduction semantics. Onecomplication remains. In any program with opaque mod-ules, any module might be referenced, and then treated ar-bitrarily, by one of the opaque modules. While this does notaffect the value that the main expression might reduce to, itdoes create the possibility of blame that has not been pre-viously predicted. We therefore place each concrete mod-ule into the previously-defined demonic context and non-deterministically choose one of these expressions to runprior to running the main module of the program.

Page 75: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

We now establish the correspondence between the previ-ous reduction semantics and the machine model when no ap-proximation occurs. Let !"#CESK denote the machine tran-sition relation under the exact interpretations of widen andalloc. Let U be the straightforward recursive “unload” func-tion that maps a closure and store to the closed term it repre-sents.

Lemma 7 (Correspondence). If P !"## Q, then there exists! such that $P,!,!% !"##CESK ! and U(!) = Q.

We now relate any approximating variant of the machineto its exact counterpart. Let !"# !CESK

denote the machinetransition under any sound interpretation of widen. We de-fine an abstraction map as a structural abstraction of thestate-space of the exact machine to its approximate coun-terpart. The key case is on stores:

"(#) = $a.!

!(a)=a

{"(#(a))}

The & relation is lifted to machine states as the point-wise,element-wise, component-wise, and member-wise lifting.

Theorem 3 (Soundness). If ! !"#CESK ! ! and "(!) & ! !,then there exists ! ! such that ! !"# !CESK

! ! and "(! !) & ! !.

We have now established any instantiation of the machineis a sound approximation to the exact machine, which in turncorrespond to the original reduction semantics. Furthermore,we can prove decidability of the semantics for finite instan-tiations of widen and alloc:

Theorem 4 (Decidability). If widen and alloc have finiterange for a program P , then $P,!,!% !"## !CESK

! isdecidable for any ! .

The proofs of these theorems closely follow those givenby Van Horn and Might [42].

6. ImplementationTo validate our approach, we have implemented a prototypeinteractive program verification environment, as seen in fig-ure 6. We can take the example from section 2, define the rel-evant modules, and explore the behavior of different choicesfor the main expression.

Programs are written with the #lang var <options>header, where <options> range over a visualization mode:trace, step, or eval; a model mode: term or machine;and an approximation mode: approx or exact. Followingthe header, programs are written in a subset of Racket, con-sisting of a series of module definitions and a top-level ex-pression.

The visualization mode controls how the state space is ex-plored. The choices are simply running the program to com-pletion with a read-eval-print loop, visualizing a directedgraph of the state space labeled by transitions, or with an in-teractive step-by-step exploration. The model mode selects

Figure 6. Interactive program verification environment

whether to use the term or the machine as the underlyingmodel of computation.

Finally, the approximation mode selects what, if any, ap-proximation should be used. The exact mode uses no ap-proximation; allocation always returns fresh addresses andno widening is used for base values. The approx mode usesa default mode of approximation that has proved useful inverifying programs (discussed below).

6.1 Implementation extensionsOur prototype includes significant extensions to the systemas described above.

First, we make numerous extensions in order to verifyexisting Racket programs. For example, modules are ex-tended to include multiple definitions and functions mayaccept zero or more arguments. The latter complicates thereduction relation as new possibilities arise for errors dueto arity mismatches. Second, we add additional base val-ues and operations to the model to support more realis-tic programs. Third, we make the implementation of con-tract checking and reduction more sophisticated, improvingrunning time and simplifying visualization. Fourth, we im-plement several techniques to reduce the size of the statespace explored in practice, including abstract garbage col-lection [32]. Abstract GC enables naive allocation strate-gies to perform with high precision. Additionally, we widencontracted recursive functions to their contracts on recur-sive calls; this implements a form of induction that is highlyeffective at increasing convergence. Fifth, we add simplerrules to model non-recursive functions and non-dependentcontracts. This brings the model closer to programmers ex-pectation of the semantics of the language, and simplifiesvisualizations. Sixth, we include several more contract com-binators, such as and/c for contract conjunction; atom/cfor expressing equality with atomic values; one-of/c for

Interactive verification environment

Page 76: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software
Page 77: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software
Page 78: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software
Page 79: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Contracts

Behavioral contracts

Specify pre- & post-conditionsas predicates

@SafeSocket(url)Socket openURL(@OnWhiteList(wl) URL url)

class OnWhiteList extends Contract<List<URL>> { bool checkContract(List<URL> wl, URL u) {...}}

Page 80: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Analysis

SemanticsSpecification

Compile-time specification

checking

Specification

Page 81: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

★ Fast design & development times★ Fast analysis times★ Modular★ Handles libraries★ Verifies rich properties

Analysis

SemanticsCompile-time specification

checking

Page 82: Scalable Abstractions for Trustworthy Software · 2012. 10. 17. · David Van Horn Matthew Might Scalable Abstractions for Trustworthy Software

Thank you

★ Fast design & development times★ Fast analysis times★ Modular★ Handles libraries★ Verifies rich properties

Analysis

SemanticsCompile-time specification

checking


Recommended