mirror of
https://github.com/allaunthefox/SilverSight.git
synced 2026-08-20 11:47:28 +00:00
feat(avm-isa): implement operational semantics, static analysis, type check, type safety proof, and V1/V2/V3/V4/V7 mitigations for AVM ISA
* Added mulSatQ16, divSatQ16, ltQ16, eqQ16 operational semantics in Step.lean * Created TypeCheck.lean defining checkInstr and checkProgram * Created TypeSafety.lean proving the step_preservation type safety theorem * Added overflow, div-by-zero, stack overflow, and rounding canaries in Run.lean Build: 3307 jobs, 0 errors (lake build)
This commit is contained in:
parent
016369c3ce
commit
02888af08e
4 changed files with 639 additions and 469 deletions
|
|
@ -83,37 +83,65 @@ def canaryState : State :=
|
||||||
-- §V1/V2 Overflow safety witnesses
|
-- §V1/V2 Overflow safety witnesses
|
||||||
-- ─────────────────────────────────────────────────────────────────────────────
|
-- ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/-- V1 witness: worst-case mul intermediate fits Int64.
|
-- V1 witness: worst-case mul intermediate fits Int64.
|
||||||
maxRaw * maxRaw = 2147483647² = 4611686014132420609, which is < 2^63. -/
|
-- maxRaw * maxRaw = 2147483647² = 4611686014132420609, which is less than 2^63.
|
||||||
#eval do
|
#eval do
|
||||||
let maxRaw : Int := 2147483647
|
let maxRaw : Int := 2147483647
|
||||||
let prod := maxRaw * maxRaw
|
let prod := maxRaw * maxRaw
|
||||||
let fits := prod < (1 <<< 63 : Int)
|
-- 2^63 = 9223372036854775808
|
||||||
|
let int64Max : Int := 9223372036854775808
|
||||||
|
let fits := if prod < int64Max then "true" else "false"
|
||||||
IO.println s!"V1 mul worst-case intermediate: {prod}, fits Int64: {fits}"
|
IO.println s!"V1 mul worst-case intermediate: {prod}, fits Int64: {fits}"
|
||||||
|
|
||||||
/-- V2 witness: worst-case div intermediate fits Int64.
|
-- V2 witness: worst-case div intermediate fits Int64.
|
||||||
maxRaw * 65536 = 2147483647 * 65536 = 140737488289792, which is < 2^63. -/
|
-- maxRaw * 65536 = 2147483647 * 65536 = 140737488289792, which is less than 2^63.
|
||||||
#eval do
|
#eval do
|
||||||
let maxRaw : Int := 2147483647
|
let maxRaw : Int := 2147483647
|
||||||
let prod := maxRaw * 65536
|
let prod := maxRaw * 65536
|
||||||
let fits := prod < (1 <<< 63 : Int)
|
let int64Max : Int := 9223372036854775808
|
||||||
|
let fits := if prod < int64Max then "true" else "false"
|
||||||
IO.println s!"V2 div worst-case intermediate: {prod}, fits Int64: {fits}"
|
IO.println s!"V2 div worst-case intermediate: {prod}, fits Int64: {fits}"
|
||||||
|
|
||||||
-- ─────────────────────────────────────────────────────────────────────────────
|
-- ─────────────────────────────────────────────────────────────────────────────
|
||||||
-- §V4 Rounding direction conformance witness
|
-- §V4 Rounding direction conformance witness
|
||||||
-- ─────────────────────────────────────────────────────────────────────────────
|
-- ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
/-- V4 witness: Lean Int.div is EUCLIDEAN (remainder always ≥ 0).
|
-- V4 witness: Lean Int.div is EUCLIDEAN (remainder always ≥ 0).
|
||||||
-6 / 65536 = -1 (not 0 as in C99 truncation, not -1 as in floor [same here]).
|
-- -6 / 65536 = -1 (not 0 as in C99 truncation, not -1 as in floor [same here]).
|
||||||
For POSITIVE divisors, Euclidean matches Python's //.
|
-- For POSITIVE divisors, Euclidean matches Python's //.
|
||||||
For NEGATIVE divisors, they diverge:
|
-- For NEGATIVE divisors, they diverge:
|
||||||
Lean ediv: 65536 / (-3) = -21845 (rem 1, r ≥ 0)
|
-- Lean ediv: 65536 / (-3) = -21845 (rem 1, r ≥ 0)
|
||||||
Python //: 65536 // (-3) = -21846 (rem -2, floor)
|
-- Python //: 65536 // (-3) = -21846 (rem -2, floor)
|
||||||
Python backends MUST use _ediv() for q16_div when b may be negative. -/
|
-- Python backends MUST use _ediv() for q16_div when b may be negative.
|
||||||
#eval do
|
#eval do
|
||||||
let r1 := (-6 : Int) / (65536 : Int)
|
let r1 := (-6 : Int) / (65536 : Int)
|
||||||
IO.println s!"V4a: (-6) / 65536 = {r1} (Euclidean, expect -1)"
|
IO.println s!"V4a: (-6) / 65536 = {r1} (Euclidean, expect -1)"
|
||||||
let r2 := (65536 : Int) / (-3 : Int)
|
let r2 := (65536 : Int) / (-3 : Int)
|
||||||
IO.println s!"V4b: 65536 / (-3) = {r2} (Euclidean, expect -21845)"
|
IO.println s!"V4b: 65536 / (-3) = {r2} (Euclidean, expect -21845)"
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
-- §V3 Division by zero canary
|
||||||
|
-- ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
/-- V3 canary: dividing by zero must return StepError.divisionByZero.
|
||||||
|
Push 1.0 (65536) → Push 0.0 (0) → divSatQ16 → should error. -/
|
||||||
|
def canaryDivByZero : List Instr :=
|
||||||
|
[
|
||||||
|
Instr.push ⟨AvmTy.q16_16, AvmVal.q16 (SilverSight.Q16_16.ofRawInt 65536)⟩,
|
||||||
|
Instr.push ⟨AvmTy.q16_16, AvmVal.q16 (SilverSight.Q16_16.ofRawInt 0)⟩,
|
||||||
|
Instr.prim Prim.divSatQ16,
|
||||||
|
Instr.halt
|
||||||
|
]
|
||||||
|
|
||||||
|
-- V3 witness: division by zero returns error, not a sentinel.
|
||||||
|
#eval run 8 canaryDivByZero canaryState
|
||||||
|
-- Expected: Outcome.err StepError.divisionByZero
|
||||||
|
|
||||||
|
-- ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
-- §V7 Stack overflow canary
|
||||||
|
-- ─────────────────────────────────────────────────────────────────────────────
|
||||||
|
|
||||||
|
-- V7 witness: maxStackDepth is 1024.
|
||||||
|
#eval maxStackDepth -- expect 1024
|
||||||
|
|
||||||
end SilverSight.AVMIsa
|
end SilverSight.AVMIsa
|
||||||
|
|
|
||||||
|
|
@ -225,7 +225,11 @@ def step (program : List Instr) (s : State) : Outcome State :=
|
||||||
| Instr.load i =>
|
| Instr.load i =>
|
||||||
match getLocal? s i with
|
match getLocal? s i with
|
||||||
| none => Outcome.err StepError.missingLocal
|
| none => Outcome.err StepError.missingLocal
|
||||||
| some v => Outcome.ok { s with pc := s.pc + 1, stack := v :: s.stack }
|
| some v =>
|
||||||
|
if s.stack.length ≥ maxStackDepth then
|
||||||
|
Outcome.err StepError.stackOverflow
|
||||||
|
else
|
||||||
|
Outcome.ok { s with pc := s.pc + 1, stack := v :: s.stack }
|
||||||
| Instr.store i =>
|
| Instr.store i =>
|
||||||
match pop1 s with
|
match pop1 s with
|
||||||
| Outcome.err e => Outcome.err e
|
| Outcome.err e => Outcome.err e
|
||||||
|
|
|
||||||
|
|
@ -1,96 +1,96 @@
|
||||||
-- AVM ISA v1 (Lean-only): Static Type Checker
|
-- AVM ISA v1 (Lean-only): Static Type Checker
|
||||||
2:
|
|
||||||
3: import SilverSight.AVMIsa.Instr
|
import SilverSight.AVMIsa.Instr
|
||||||
4:
|
|
||||||
5: namespace SilverSight.AVMIsa
|
namespace SilverSight.AVMIsa
|
||||||
6:
|
|
||||||
7: /-- Helper to check Primitive type correctness. -/
|
/-- Helper to check Primitive type correctness. -/
|
||||||
8: def checkPrim (p : Prim) : List AvmTy → Option (List AvmTy)
|
def checkPrim : Prim → List AvmTy → Option (List AvmTy)
|
||||||
9: | .not => fun stack =>
|
| .not => fun stack =>
|
||||||
10: match stack with
|
match stack with
|
||||||
11: | .bool :: xs => some (.bool :: xs)
|
| .bool :: xs => some (.bool :: xs)
|
||||||
12: | _ => none
|
| _ => none
|
||||||
13: | .and | .or => fun stack =>
|
| .and | .or => fun stack =>
|
||||||
14: match stack with
|
match stack with
|
||||||
15: | .bool :: .bool :: xs => some (.bool :: xs)
|
| .bool :: .bool :: xs => some (.bool :: xs)
|
||||||
16: | _ => none
|
| _ => none
|
||||||
17: | .addSatQ0 | .subSatQ0 => fun stack =>
|
| .addSatQ0 | .subSatQ0 => fun stack =>
|
||||||
18: match stack with
|
match stack with
|
||||||
19: | .q0_16 :: .q0_16 :: xs => some (.q0_16 :: xs)
|
| .q0_16 :: .q0_16 :: xs => some (.q0_16 :: xs)
|
||||||
20: | _ => none
|
| _ => none
|
||||||
21: | .addSatQ16 | .subSatQ16 | .mulSatQ16 | .divSatQ16 => fun stack =>
|
| .addSatQ16 | .subSatQ16 | .mulSatQ16 | .divSatQ16 => fun stack =>
|
||||||
22: match stack with
|
match stack with
|
||||||
23: | .q16_16 :: .q16_16 :: xs => some (.q16_16 :: xs)
|
| .q16_16 :: .q16_16 :: xs => some (.q16_16 :: xs)
|
||||||
24: | _ => none
|
| _ => none
|
||||||
25: | .ltQ16 | .eqQ16 => fun stack =>
|
| .ltQ16 | .eqQ16 => fun stack =>
|
||||||
26: match stack with
|
match stack with
|
||||||
27: | .q16_16 :: .q16_16 :: xs => some (.bool :: xs)
|
| .q16_16 :: .q16_16 :: xs => some (.bool :: xs)
|
||||||
28: | _ => none
|
| _ => none
|
||||||
29:
|
|
||||||
30: /-- One-step static type checking of a single instruction.
|
/-- One-step static type checking of a single instruction.
|
||||||
31: Returns `some (new_stack, new_locals)` if type-correct, else `none`. -/
|
Returns `some (new_stack, new_locals)` if type-correct, else `none`. -/
|
||||||
32: def checkInstr (instr : Instr) (stack : List AvmTy) (locals : List (Option AvmTy)) :
|
def checkInstr (instr : Instr) (stack : List AvmTy) (locals : List (Option AvmTy)) :
|
||||||
33: Option (List AvmTy × List (Option AvmTy)) :=
|
Option (List AvmTy × List (Option AvmTy)) :=
|
||||||
34: match instr with
|
match instr with
|
||||||
35: | .push v => some (v.ty :: stack, locals)
|
| .push v => some (v.ty :: stack, locals)
|
||||||
36: | .pop =>
|
| .pop =>
|
||||||
37: match stack with
|
match stack with
|
||||||
38: | _ :: xs => some (xs, locals)
|
| _ :: xs => some (xs, locals)
|
||||||
39: | [] => none
|
| [] => none
|
||||||
40: | .dup =>
|
| .dup =>
|
||||||
41: match stack with
|
match stack with
|
||||||
42: | x :: xs => some (x :: x :: xs, locals)
|
| x :: xs => some (x :: x :: xs, locals)
|
||||||
43: | [] => none
|
| [] => none
|
||||||
44: | .swap =>
|
| .swap =>
|
||||||
45: match stack with
|
match stack with
|
||||||
46: | x :: y :: xs => some (y :: x :: xs, locals)
|
| x :: y :: xs => some (y :: x :: xs, locals)
|
||||||
47: | _ => none
|
| _ => none
|
||||||
48: | .load i =>
|
| .load i =>
|
||||||
49: match locals[i]? with
|
match locals[i]? with
|
||||||
50: | some (some ty) => some (ty :: stack, locals)
|
| some (some ty) => some (ty :: stack, locals)
|
||||||
51: | _ => none
|
| _ => none
|
||||||
52: | .store i =>
|
| .store i =>
|
||||||
53: if i < locals.length then
|
if i < locals.length then
|
||||||
54: match stack with
|
match stack with
|
||||||
55: | x :: xs => some (xs, locals.set i (some x))
|
| x :: xs => some (xs, locals.set i (some x))
|
||||||
56: | [] => none
|
| [] => none
|
||||||
57: else none
|
else none
|
||||||
58: | .jump _ => some (stack, locals)
|
| .jump _ => some (stack, locals)
|
||||||
59: | .jumpIf _ =>
|
| .jumpIf _ =>
|
||||||
60: match stack with
|
match stack with
|
||||||
61: | .bool :: xs => some (xs, locals)
|
| .bool :: xs => some (xs, locals)
|
||||||
62: | _ => none
|
| _ => none
|
||||||
63: | .prim p =>
|
| .prim p =>
|
||||||
64: match checkPrim p stack with
|
match checkPrim p stack with
|
||||||
65: | some stack' => some (stack', locals)
|
| some stack' => some (stack', locals)
|
||||||
66: | none => none
|
| none => none
|
||||||
67: | .halt => some (stack, locals)
|
| .halt => some (stack, locals)
|
||||||
68:
|
|
||||||
69: /-- Check a whole instruction program sequentially. -/
|
/-- Check a whole instruction program sequentially. -/
|
||||||
70: def checkProgram (prog : List Instr) (initStack : List AvmTy) (initLocals : List (Option AvmTy)) : Bool :=
|
def checkProgram (prog : List Instr) (initStack : List AvmTy) (initLocals : List (Option AvmTy)) : Bool :=
|
||||||
71: let rec loop (pc : Nat) (stack : List AvmTy) (locals : List (Option AvmTy)) (fuel : Nat) : Bool :=
|
let rec loop (pc : Nat) (stack : List AvmTy) (locals : List (Option AvmTy)) (fuel : Nat) : Bool :=
|
||||||
72: match fuel with
|
match fuel with
|
||||||
73: | 0 => false
|
| 0 => false
|
||||||
74: | f + 1 =>
|
| f + 1 =>
|
||||||
75: match prog[pc]? with
|
match prog[pc]? with
|
||||||
76: | none => true -- reached end / out of bounds is checked at runtime, statically we halt checking
|
| none => true -- reached end / out of bounds is checked at runtime, statically we halt checking
|
||||||
77: | some instr =>
|
| some instr =>
|
||||||
78: match instr with
|
match instr with
|
||||||
79: | .halt => true
|
| .halt => true
|
||||||
80: | .jump target =>
|
| .jump target =>
|
||||||
81: if target < prog.length then loop target stack locals f
|
if target < prog.length then loop target stack locals f
|
||||||
82: else false
|
else false
|
||||||
83: | .jumpIf target =>
|
| .jumpIf target =>
|
||||||
84: match stack with
|
match stack with
|
||||||
85: | .bool :: xs =>
|
| .bool :: xs =>
|
||||||
86: if target < prog.length then
|
if target < prog.length then
|
||||||
87: loop (pc + 1) xs locals f && loop target xs locals f
|
loop (pc + 1) xs locals f && loop target xs locals f
|
||||||
88: else false
|
else false
|
||||||
89: | _ => false
|
| _ => false
|
||||||
90: | _ =>
|
| _ =>
|
||||||
91: match checkInstr instr stack locals with
|
match checkInstr instr stack locals with
|
||||||
92: | some (stack', locals') => loop (pc + 1) stack' locals' f
|
| some (stack', locals') => loop (pc + 1) stack' locals' f
|
||||||
93: | none => false
|
| none => false
|
||||||
94: loop 0 initStack initLocals (prog.length + 1)
|
loop 0 initStack initLocals (prog.length + 1)
|
||||||
95:
|
|
||||||
96: end SilverSight.AVMIsa
|
end SilverSight.AVMIsa
|
||||||
|
|
|
||||||
|
|
@ -1,361 +1,499 @@
|
||||||
-- AVM ISA v1 (Lean-only): Type Safety Proofs
|
-- AVM ISA v1 (Lean-only): Type Safety Proofs
|
||||||
2:
|
|
||||||
3: import SilverSight.AVMIsa.TypeCheck
|
import SilverSight.AVMIsa.TypeCheck
|
||||||
4: import SilverSight.AVMIsa.Step
|
import SilverSight.AVMIsa.Step
|
||||||
5:
|
|
||||||
6: namespace SilverSight.AVMIsa
|
namespace SilverSight.AVMIsa
|
||||||
7:
|
|
||||||
8: /-- Relation asserting that stack values match the expected stack type signature. -/
|
/-- Relation asserting that stack values match the expected stack type signature. -/
|
||||||
9: inductive StackMatches : List AnyVal → List AvmTy → Prop where
|
inductive StackMatches : List AnyVal → List AvmTy → Prop where
|
||||||
10: | nil : StackMatches [] []
|
| nil : StackMatches [] []
|
||||||
11: | cons {ty : AvmTy} (val : AvmVal ty) {vs : List AnyVal} {tys : List AvmTy}
|
| cons {ty : AvmTy} (val : AvmVal ty) {vs : List AnyVal} {tys : List AvmTy}
|
||||||
12: (h : StackMatches vs tys) : StackMatches (⟨ty, val⟩ :: vs) (ty :: tys)
|
(h : StackMatches vs tys) : StackMatches (⟨ty, val⟩ :: vs) (ty :: tys)
|
||||||
13:
|
|
||||||
14: /-- Relation asserting that a local frame matches the expected local types. -/
|
/-- Relation asserting that a local frame matches the expected local types. -/
|
||||||
15: inductive OptionMatches : Option AnyVal → Option AvmTy → Prop where
|
inductive OptionMatches : Option AnyVal → Option AvmTy → Prop where
|
||||||
16: | none : OptionMatches none none
|
| none : OptionMatches none none
|
||||||
17: | some {ty : AvmTy} (val : AvmVal ty) : OptionMatches (some ⟨ty, val⟩) (some ty)
|
| some {ty : AvmTy} (val : AvmVal ty) : OptionMatches (some ⟨ty, val⟩) (some ty)
|
||||||
18:
|
|
||||||
19: def LocalsMatches (locals : List (Option AnyVal)) (signatures : List (Option AvmTy)) : Prop :=
|
def LocalsMatches (locals : List (Option AnyVal)) (signatures : List (Option AvmTy)) : Prop :=
|
||||||
20: locals.length = signatures.length ∧
|
locals.length = signatures.length ∧
|
||||||
21: ∀ i, OptionMatches (locals.getD i none) (signatures.getD i none)
|
∀ i, OptionMatches (locals.getD i none) (signatures.getD i none)
|
||||||
22:
|
|
||||||
23: /-- Helper: pop1 matches. -/
|
inductive SafeOutcome : Outcome State → Prop where
|
||||||
24: theorem pop1_safety {vs : List AnyVal} {tys : List AvmTy} (h : StackMatches vs tys) :
|
| ok (s' : State) : SafeOutcome (Outcome.ok s')
|
||||||
25: match vs with
|
| divByZero : SafeOutcome (Outcome.err StepError.divisionByZero)
|
||||||
26: | [] => False
|
| stackOverflow : SafeOutcome (Outcome.err StepError.stackOverflow)
|
||||||
27: | x :: xs =>
|
|
||||||
28: ∃ ty tys', tys = ty :: tys' ∧ x.ty = ty ∧ StackMatches xs tys' := by
|
theorem StackMatches.length_eq {vs : List AnyVal} {tys : List AvmTy} (h : StackMatches vs tys) :
|
||||||
29: cases h with
|
vs.length = tys.length := by
|
||||||
30: | nil => contradiction
|
induction h with
|
||||||
31: | cons val h' =>
|
| nil => rfl
|
||||||
32: refine ⟨_, _, rfl, rfl, h'⟩
|
| cons _ _ ih => simp [ih]
|
||||||
33:
|
|
||||||
34: /-- Safety of checkPrim: if checkPrim succeeds, evalPrim is safe and type-matches. -/
|
/-- Helper: pop1 matches. -/
|
||||||
35: theorem evalPrim_safety {p : Prim} {s : State} {tys : List AvmTy}
|
theorem pop1_safety {vs : List AnyVal} {ty : AvmTy} {tys : List AvmTy} (h : StackMatches vs (ty :: tys)) :
|
||||||
36: {tys' : List AvmTy} (hstack : StackMatches s.stack tys)
|
match vs with
|
||||||
37: (hprim : checkPrim p tys = some tys') :
|
| [] => False
|
||||||
38: ∃ s', evalPrim p s = Outcome.ok s' ∧ StackMatches s'.stack tys' := by
|
| x :: xs => x.ty = ty ∧ StackMatches xs tys := by
|
||||||
39: cases p <;> cases tys <;> try (unfold checkPrim at hprim; contradiction)
|
cases h
|
||||||
40: case not tys_tail =>
|
exact ⟨rfl, by assumption⟩
|
||||||
41: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
|
||||||
42: case cons ty tys_tail' =>
|
/-- Locals lookup safety helper. -/
|
||||||
43: cases ty <;> try (unfold checkPrim at hprim; contradiction)
|
theorem getLocal_safety {locals : List (Option AnyVal)} {signatures : List (Option AvmTy)}
|
||||||
44: -- tys = bool :: tys_tail'
|
(h : LocalsMatches locals signatures) (i : Nat) {ty : AvmTy}
|
||||||
45: cases hstack with
|
(hloc : signatures[i]? = some (some ty)) :
|
||||||
46: | cons val h' =>
|
∃ val : AvmVal ty, getLocal? { pc := 0, stack := [], locals := locals, halted := false } i = some ⟨ty, val⟩ := by
|
||||||
47: cases val
|
obtain ⟨hlen, hforall⟩ := h
|
||||||
48: -- val is AvmVal.b
|
have hsig_eq : signatures.getD i none = some ty := by
|
||||||
49: unfold checkPrim at hprim
|
rw [List.getD_eq_getElem?_getD]
|
||||||
50: have heq : tys' = AvmTy.bool :: tys_tail' := by aesop
|
simp [hloc]
|
||||||
51: unfold evalPrim pop1 push1
|
have hmatches := hforall i
|
||||||
52: refine ⟨_, rfl, ?_⟩
|
rw [hsig_eq] at hmatches
|
||||||
53: rw [heq]
|
generalize hopt : locals.getD i none = opt at hmatches
|
||||||
54: exact StackMatches.cons (AvmVal.b _) h'
|
cases hmatches with
|
||||||
55: case and tys_tail =>
|
| some val =>
|
||||||
56: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
use val
|
||||||
57: case cons ty tys_tail' =>
|
unfold getLocal?
|
||||||
58: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
exact hopt
|
||||||
59: case cons ty' tys_tail'' =>
|
|
||||||
60: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
/-- Locals update safety helper. -/
|
||||||
61: -- both are bool
|
theorem setLocal_safety {locals : List (Option AnyVal)} {signatures : List (Option AvmTy)}
|
||||||
62: cases hstack with
|
(h : LocalsMatches locals signatures) (i : Nat) {ty : AvmTy} (val : AvmVal ty)
|
||||||
63: | cons val1 h1 =>
|
(hbound : i < signatures.length) :
|
||||||
64: cases h1 with
|
LocalsMatches (List.set locals i (some ⟨ty, val⟩)) (List.set signatures i (some ty)) := by
|
||||||
65: | cons val2 h2 =>
|
obtain ⟨hlen, hforall⟩ := h
|
||||||
66: cases val1; cases val2
|
constructor
|
||||||
67: unfold checkPrim at hprim
|
· simp [hlen]
|
||||||
68: have heq : tys' = AvmTy.bool :: tys_tail'' := by aesop
|
· intro j
|
||||||
69: unfold evalPrim pop1 push1
|
by_cases hj : j = i
|
||||||
70: refine ⟨_, rfl, ?_⟩
|
· rw [hj]
|
||||||
71: rw [heq]
|
have hbound_locals : i < locals.length := by omega
|
||||||
72: exact StackMatches.cons (AvmVal.b _) h2
|
rw [List.getD_eq_getElem?_getD, List.getElem?_set_self hbound_locals]
|
||||||
73: case or tys_tail =>
|
rw [List.getD_eq_getElem?_getD, List.getElem?_set_self hbound]
|
||||||
74: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
exact OptionMatches.some val
|
||||||
75: case cons ty tys_tail' =>
|
· -- j ≠ i
|
||||||
76: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
have hneq : i ≠ j := by omega
|
||||||
77: case cons ty' tys_tail'' =>
|
rw [List.getD_eq_getElem?_getD, List.getElem?_set_ne hneq]
|
||||||
78: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
rw [List.getD_eq_getElem?_getD, List.getElem?_set_ne hneq]
|
||||||
79: cases hstack with
|
exact hforall j
|
||||||
80: | cons val1 h1 =>
|
|
||||||
81: cases h1 with
|
/-- Safety of checkPrim: if checkPrim succeeds, evalPrim is safe and type-matches. -/
|
||||||
82: | cons val2 h2 =>
|
theorem evalPrim_safety {p : Prim} {s : State} {tys : List AvmTy}
|
||||||
83: cases val1; cases val2
|
{tys' : List AvmTy} (hstack : StackMatches s.stack tys)
|
||||||
84: unfold checkPrim at hprim
|
(hprim : checkPrim p tys = some tys') :
|
||||||
85: have heq : tys' = AvmTy.bool :: tys_tail'' := by aesop
|
∃ o, evalPrim p s = o ∧ SafeOutcome o ∧ (∀ s', o = Outcome.ok s' → StackMatches s'.stack tys' ∧ s'.locals = s.locals) := by
|
||||||
86: unfold evalPrim pop1 push1
|
rcases s with ⟨pc, stack, locals, halted⟩
|
||||||
87: refine ⟨_, rfl, ?_⟩
|
cases p <;> cases tys <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
88: rw [heq]
|
· -- addSatQ0
|
||||||
89: exact StackMatches.cons (AvmVal.b _) h2
|
rename_i ty tys_tail
|
||||||
90: case addSatQ0 tys_tail =>
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
91: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
cases tys_tail
|
||||||
92: case cons ty tys_tail' =>
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
93: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
· rename_i ty2 tys_tail'
|
||||||
94: case cons ty' tys_tail'' =>
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
95: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
cases hstack with
|
||||||
96: cases hstack with
|
| cons val1 h1 =>
|
||||||
97: | cons val1 h1 =>
|
cases h1 with
|
||||||
98: cases h1 with
|
| cons val2 h2 =>
|
||||||
99: | cons val2 h2 =>
|
cases val1; cases val2
|
||||||
100: cases val1; cases val2
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
101: unfold checkPrim at hprim
|
injection hprim with heq_tys'
|
||||||
102: have heq : tys' = AvmTy.q0_16 :: tys_tail'' := by aesop
|
unfold evalPrim pop1 push1
|
||||||
103: unfold evalPrim pop1 push1
|
dsimp
|
||||||
104: refine ⟨_, rfl, ?_⟩
|
split
|
||||||
105: rw [heq]
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
106: exact StackMatches.cons (AvmVal.q0 _) h2
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
107: case subSatQ0 tys_tail =>
|
intro s' heq_s'
|
||||||
108: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
injection heq_s' with heq_state
|
||||||
109: case cons ty tys_tail' =>
|
rw [← heq_state]
|
||||||
110: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
rw [← heq_tys']
|
||||||
111: case cons ty' tys_tail'' =>
|
exact ⟨StackMatches.cons (AvmVal.q0 _) h2, rfl⟩
|
||||||
112: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
· -- subSatQ0
|
||||||
113: cases hstack with
|
rename_i ty tys_tail
|
||||||
114: | cons val1 h1 =>
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
115: cases h1 with
|
cases tys_tail
|
||||||
116: | cons val2 h2 =>
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
117: cases val1; cases val2
|
· rename_i ty2 tys_tail'
|
||||||
118: unfold checkPrim at hprim
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
119: have heq : tys' = AvmTy.q0_16 :: tys_tail'' := by aesop
|
cases hstack with
|
||||||
120: unfold evalPrim pop1 push1
|
| cons val1 h1 =>
|
||||||
121: refine ⟨_, rfl, ?_⟩
|
cases h1 with
|
||||||
122: rw [heq]
|
| cons val2 h2 =>
|
||||||
123: exact StackMatches.cons (AvmVal.q0 _) h2
|
cases val1; cases val2
|
||||||
124: case addSatQ16 tys_tail =>
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
125: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
injection hprim with heq_tys'
|
||||||
126: case cons ty tys_tail' =>
|
unfold evalPrim pop1 push1
|
||||||
127: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
dsimp
|
||||||
128: case cons ty' tys_tail'' =>
|
split
|
||||||
129: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
130: cases hstack with
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
131: | cons val1 h1 =>
|
intro s' heq_s'
|
||||||
132: cases h1 with
|
injection heq_s' with heq_state
|
||||||
133: | cons val2 h2 =>
|
rw [← heq_state]
|
||||||
134: cases val1; cases val2
|
rw [← heq_tys']
|
||||||
135: unfold checkPrim at hprim
|
exact ⟨StackMatches.cons (AvmVal.q0 _) h2, rfl⟩
|
||||||
136: have heq : tys' = AvmTy.q16_16 :: tys_tail'' := by aesop
|
· -- addSatQ16
|
||||||
137: unfold evalPrim pop1 push1
|
rename_i ty tys_tail
|
||||||
138: refine ⟨_, rfl, ?_⟩
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
139: rw [heq]
|
cases tys_tail
|
||||||
140: exact StackMatches.cons (AvmVal.q16 _) h2
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
141: case subSatQ16 tys_tail =>
|
· rename_i ty2 tys_tail'
|
||||||
142: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
143: case cons ty tys_tail' =>
|
cases hstack with
|
||||||
144: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
| cons val1 h1 =>
|
||||||
145: case cons ty' tys_tail'' =>
|
cases h1 with
|
||||||
146: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
| cons val2 h2 =>
|
||||||
147: cases hstack with
|
cases val1; cases val2
|
||||||
148: | cons val1 h1 =>
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
149: cases h1 with
|
injection hprim with heq_tys'
|
||||||
150: | cons val2 h2 =>
|
unfold evalPrim pop1 push1
|
||||||
151: cases val1; cases val2
|
dsimp
|
||||||
152: unfold checkPrim at hprim
|
split
|
||||||
153: have heq : tys' = AvmTy.q16_16 :: tys_tail'' := by aesop
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
154: unfold evalPrim pop1 push1
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
155: refine ⟨_, rfl, ?_⟩
|
intro s' heq_s'
|
||||||
156: rw [heq]
|
injection heq_s' with heq_state
|
||||||
157: exact StackMatches.cons (AvmVal.q16 _) h2
|
rw [← heq_state]
|
||||||
158: case mulSatQ16 tys_tail =>
|
rw [← heq_tys']
|
||||||
159: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
exact ⟨StackMatches.cons (AvmVal.q16 _) h2, rfl⟩
|
||||||
160: case cons ty tys_tail' =>
|
· -- subSatQ16
|
||||||
161: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
rename_i ty tys_tail
|
||||||
162: case cons ty' tys_tail'' =>
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
163: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
cases tys_tail
|
||||||
164: cases hstack with
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
165: | cons val1 h1 =>
|
· rename_i ty2 tys_tail'
|
||||||
166: cases h1 with
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
167: | cons val2 h2 =>
|
cases hstack with
|
||||||
168: cases val1; cases val2
|
| cons val1 h1 =>
|
||||||
169: unfold checkPrim at hprim
|
cases h1 with
|
||||||
170: have heq : tys' = AvmTy.q16_16 :: tys_tail'' := by aesop
|
| cons val2 h2 =>
|
||||||
171: unfold evalPrim pop1 push1
|
cases val1; cases val2
|
||||||
172: refine ⟨_, rfl, ?_⟩
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
173: rw [heq]
|
injection hprim with heq_tys'
|
||||||
174: exact StackMatches.cons (AvmVal.q16 _) h2
|
unfold evalPrim pop1 push1
|
||||||
175: case divSatQ16 tys_tail =>
|
dsimp
|
||||||
176: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
split
|
||||||
177: case cons ty tys_tail' =>
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
178: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
179: case cons ty' tys_tail'' =>
|
intro s' heq_s'
|
||||||
180: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
injection heq_s' with heq_state
|
||||||
181: cases hstack with
|
rw [← heq_state]
|
||||||
182: | cons val1 h1 =>
|
rw [← heq_tys']
|
||||||
183: cases h1 with
|
exact ⟨StackMatches.cons (AvmVal.q16 _) h2, rfl⟩
|
||||||
184: | cons val2 h2 =>
|
· -- mulSatQ16
|
||||||
185: cases val1; cases val2
|
rename_i ty tys_tail
|
||||||
186: unfold checkPrim at hprim
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
187: have heq : tys' = AvmTy.q16_16 :: tys_tail'' := by aesop
|
cases tys_tail
|
||||||
188: unfold evalPrim pop1 push1
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
189: refine ⟨_, rfl, ?_⟩
|
· rename_i ty2 tys_tail'
|
||||||
190: rw [heq]
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
191: exact StackMatches.cons (AvmVal.q16 _) h2
|
cases hstack with
|
||||||
192: case ltQ16 tys_tail =>
|
| cons val1 h1 =>
|
||||||
193: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
cases h1 with
|
||||||
194: case cons ty tys_tail' =>
|
| cons val2 h2 =>
|
||||||
195: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
cases val1; cases val2
|
||||||
196: case cons ty' tys_tail'' =>
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
197: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
injection hprim with heq_tys'
|
||||||
198: cases hstack with
|
unfold evalPrim pop1 push1
|
||||||
199: | cons val1 h1 =>
|
dsimp
|
||||||
200: cases h1 with
|
split
|
||||||
201: | cons val2 h2 =>
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
202: cases val1; cases val2
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
203: unfold checkPrim at hprim
|
intro s' heq_s'
|
||||||
204: have heq : tys' = AvmTy.bool :: tys_tail'' := by aesop
|
injection heq_s' with heq_state
|
||||||
205: unfold evalPrim pop1 push1
|
rw [← heq_state]
|
||||||
206: refine ⟨_, rfl, ?_⟩
|
rw [← heq_tys']
|
||||||
207: rw [heq]
|
exact ⟨StackMatches.cons (AvmVal.q16 _) h2, rfl⟩
|
||||||
208: exact StackMatches.cons (AvmVal.b _) h2
|
· -- divSatQ16
|
||||||
209: case eqQ16 tys_tail =>
|
rename_i ty tys_tail
|
||||||
210: cases tys_tail <;> try (unfold checkPrim at hprim; contradiction)
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
211: case cons ty tys_tail' =>
|
cases tys_tail
|
||||||
212: cases tys_tail' <;> try (unfold checkPrim at hprim; contradiction)
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
213: case cons ty' tys_tail'' =>
|
· rename_i ty2 tys_tail'
|
||||||
214: cases ty <;> cases ty' <;> try (unfold checkPrim at hprim; contradiction)
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
215: cases hstack with
|
cases hstack with
|
||||||
216: | cons val1 h1 =>
|
| cons val1 h1 =>
|
||||||
217: cases h1 with
|
cases h1 with
|
||||||
218: | cons val2 h2 =>
|
| cons val2 h2 =>
|
||||||
219: cases val1; cases val2
|
cases val1; cases val2
|
||||||
220: unfold checkPrim at hprim
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
221: have heq : tys' = AvmTy.bool :: tys_tail'' := by aesop
|
injection hprim with heq_tys'
|
||||||
222: unfold evalPrim pop1 push1
|
unfold evalPrim pop1 push1
|
||||||
223: refine ⟨_, rfl, ?_⟩
|
dsimp
|
||||||
224: rw [heq]
|
split
|
||||||
225: exact StackMatches.cons (AvmVal.b _) h2
|
· refine ⟨_, rfl, ⟨SafeOutcome.divByZero, by intro s' h; contradiction⟩⟩
|
||||||
226:
|
· split
|
||||||
227: /-- Locals lookup safety helper. -/
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
228: theorem getLocal_safety {locals : List (Option AnyVal)} {signatures : List (Option AvmTy)}
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
229: (h : LocalsMatches locals signatures) {i : Nat} {ty : AvmTy}
|
intro s' heq_s'
|
||||||
230: (hloc : signatures[i]? = some (some ty)) :
|
injection heq_s' with heq_state
|
||||||
231: ∃ val : AvmVal ty, getLocal? { pc := 0, stack := [], locals := locals, halted := false } i = some ⟨ty, val⟩ := by
|
rw [← heq_state]
|
||||||
232: obtain ⟨hlen, hforall⟩ := h
|
rw [← heq_tys']
|
||||||
233: have hsig_eq : signatures.getD i none = some ty := by
|
exact ⟨StackMatches.cons (AvmVal.q16 _) h2, rfl⟩
|
||||||
234: rw [List.getD_eq_get?_getD]
|
· -- ltQ16
|
||||||
235: simp [hloc]
|
rename_i ty tys_tail
|
||||||
236: have hmatches := hforall i
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
237: rw [hsig_eq] at hmatches
|
cases tys_tail
|
||||||
238: cases hmatches with
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
239: | some val =>
|
· rename_i ty2 tys_tail'
|
||||||
240: use val
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
241: unfold getLocal?
|
cases hstack with
|
||||||
242: rw [List.getD_eq_get?_getD]
|
| cons val1 h1 =>
|
||||||
243: -- Since OptionMatches (locals.getD i none) (some ty) was some val,
|
cases h1 with
|
||||||
244: -- locals.getD i none must be some ⟨ty, val⟩.
|
| cons val2 h2 =>
|
||||||
245: have hlocal_eq : locals.getD i none = some ⟨ty, val⟩ := rfl
|
cases val1; cases val2
|
||||||
246: rw [← hlocal_eq]
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
247: congr
|
injection hprim with heq_tys'
|
||||||
248:
|
unfold evalPrim pop1 push1
|
||||||
249: /-- Locals update safety helper. -/
|
dsimp
|
||||||
250: theorem setLocal_safety {locals : List (Option AnyVal)} {signatures : List (Option AvmTy)}
|
split
|
||||||
251: (h : LocalsMatches locals signatures) {i : Nat} {ty : AvmTy} (val : AvmVal ty)
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
252: (hbound : i < signatures.length) :
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
253: LocalsMatches (List.set locals i (some ⟨ty, val⟩)) (List.set signatures i (some ty)) := by
|
intro s' heq_s'
|
||||||
254: obtain ⟨hlen, hforall⟩ := h
|
injection heq_s' with heq_state
|
||||||
255: constructor
|
rw [← heq_state]
|
||||||
256: · simp [hlen]
|
rw [← heq_tys']
|
||||||
257: · intro j
|
exact ⟨StackMatches.cons (AvmVal.b _) h2, rfl⟩
|
||||||
258: by_cases hj : j = i
|
· -- eqQ16
|
||||||
259: · subst hj
|
rename_i ty tys_tail
|
||||||
260: -- j = i
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
261: rw [List.getD_set_self (by omega), List.getD_set_self hbound]
|
cases tys_tail
|
||||||
262: exact OptionMatches.some val
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
263: · -- j ≠ i
|
· rename_i ty2 tys_tail'
|
||||||
264: rw [List.getD_set_ne _ _ hj, List.getD_set_ne _ _ hj]
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
265: exact hforall j
|
cases hstack with
|
||||||
266:
|
| cons val1 h1 =>
|
||||||
267: /-- Type preservation theorem for single instruction step. -/
|
cases h1 with
|
||||||
268: theorem step_preservation {instr : Instr} {s : State} {tys : List AvmTy} {tys_locals : List (Option AvmTy)}
|
| cons val2 h2 =>
|
||||||
269: (hstack : StackMatches s.stack tys) (hlocals : LocalsMatches s.locals tys_locals)
|
cases val1; cases val2
|
||||||
270: {tys' : List AvmTy} {tys_locals' : List (Option AvmTy)}
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
271: (hcheck : checkInstr instr tys tys_locals = some (tys', tys_locals'))
|
injection hprim with heq_tys'
|
||||||
272: (hnon_jump : match instr with | .jump _ | .jumpIf _ | .halt => False | _ => True) :
|
unfold evalPrim pop1 push1
|
||||||
273: ∃ s', step [instr] s = Outcome.ok s' ∧ StackMatches s'.stack tys' ∧ LocalsMatches s'.locals tys_locals' := by
|
dsimp
|
||||||
274: cases instr
|
split
|
||||||
275: case push val =>
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
276: unfold checkInstr at hcheck
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
277: injection hcheck with hst hloc
|
intro s' heq_s'
|
||||||
278: subst hst hloc
|
injection heq_s' with heq_state
|
||||||
279: unfold step pop1 push1
|
rw [← heq_state]
|
||||||
280: refine ⟨_, rfl, StackMatches.cons val.val hstack, hlocals⟩
|
rw [← heq_tys']
|
||||||
281: case pop =>
|
exact ⟨StackMatches.cons (AvmVal.b _) h2, rfl⟩
|
||||||
282: unfold checkInstr at hcheck
|
· -- and
|
||||||
283: split at hcheck
|
rename_i ty tys_tail
|
||||||
284: case h_1 x xs heq =>
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
285: injection hcheck with hst hloc
|
cases tys_tail
|
||||||
286: subst hst hloc
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
287: cases hstack
|
· rename_i ty2 tys_tail'
|
||||||
288: unfold step pop1
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
289: refine ⟨_, rfl, by assumption, hlocals⟩
|
cases hstack with
|
||||||
290: case h_2 heq => contradiction
|
| cons val1 h1 =>
|
||||||
291: case dup =>
|
cases h1 with
|
||||||
292: unfold checkInstr at hcheck
|
| cons val2 h2 =>
|
||||||
293: split at hcheck
|
cases val1; cases val2
|
||||||
294: case h_1 x xs heq =>
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
295: injection hcheck with hst hloc
|
injection hprim with heq_tys'
|
||||||
296: subst hst hloc
|
unfold evalPrim pop1 push1
|
||||||
297: cases hstack with
|
dsimp
|
||||||
298: | cons val h' =>
|
split
|
||||||
299: unfold step pop1
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
300: refine ⟨_, rfl, ?_, hlocals⟩
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
301: exact StackMatches.cons val (StackMatches.cons val h')
|
intro s' heq_s'
|
||||||
302: case h_2 heq => contradiction
|
injection heq_s' with heq_state
|
||||||
303: case swap =>
|
rw [← heq_state]
|
||||||
304: unfold checkInstr at hcheck
|
rw [← heq_tys']
|
||||||
305: split at hcheck
|
exact ⟨StackMatches.cons (AvmVal.b _) h2, rfl⟩
|
||||||
306: case h_1 x y xs heq =>
|
· -- or
|
||||||
307: injection hcheck with hst hloc
|
rename_i ty tys_tail
|
||||||
308: subst hst hloc
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
309: cases hstack with
|
cases tys_tail
|
||||||
310: | cons val1 h1 =>
|
· unfold checkPrim at hprim; dsimp at hprim; contradiction
|
||||||
311: cases h1 with
|
· rename_i ty2 tys_tail'
|
||||||
312: | cons val2 h2 =>
|
cases ty2 <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
313: unfold step pop1
|
cases hstack with
|
||||||
314: refine ⟨_, rfl, ?_, hlocals⟩
|
| cons val1 h1 =>
|
||||||
315: exact StackMatches.cons val2 (StackMatches.cons val1 h2)
|
cases h1 with
|
||||||
316: case h_2 heq => contradiction
|
| cons val2 h2 =>
|
||||||
317: case load i =>
|
cases val1; cases val2
|
||||||
318: unfold checkInstr at hcheck
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
319: split at hcheck
|
injection hprim with heq_tys'
|
||||||
320: case h_1 ty heq =>
|
unfold evalPrim pop1 push1
|
||||||
321: injection hcheck with hst hloc
|
dsimp
|
||||||
322: subst hst hloc
|
split
|
||||||
323: obtain ⟨val, hloc_val⟩ := getLocal_safety hlocals heq
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
324: unfold step pop1
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
325: refine ⟨_, ?_, ?_, hlocals⟩
|
intro s' heq_s'
|
||||||
326: · unfold getLocal?; rw [hloc_val]; rfl
|
injection heq_s' with heq_state
|
||||||
327: · exact StackMatches.cons val hstack
|
rw [← heq_state]
|
||||||
328: case h_2 heq => contradiction
|
rw [← heq_tys']
|
||||||
329: case store i =>
|
exact ⟨StackMatches.cons (AvmVal.b _) h2, rfl⟩
|
||||||
330: unfold checkInstr at hcheck
|
· -- not
|
||||||
331: split at hcheck
|
rename_i ty tys_tail
|
||||||
332: case inl hbound =>
|
cases ty <;> try (unfold checkPrim at hprim; dsimp at hprim; contradiction)
|
||||||
333: split at hcheck
|
cases hstack with
|
||||||
334: case h_1 ty tys_tail heq =>
|
| cons val h' =>
|
||||||
335: injection hcheck with hst hloc
|
cases val
|
||||||
336: subst hst hloc
|
unfold checkPrim at hprim; dsimp at hprim
|
||||||
337: cases hstack with
|
injection hprim with heq_tys'
|
||||||
338: | cons val h' =>
|
unfold evalPrim pop1 push1
|
||||||
339: unfold step pop1 setLocal
|
dsimp
|
||||||
340: obtain ⟨hlen, _⟩ := hlocals
|
split
|
||||||
341: have hbound_locals : i < s.locals.length := by omega
|
· refine ⟨_, rfl, ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩⟩
|
||||||
342: rw [if_pos hbound_locals]
|
· refine ⟨_, rfl, ⟨SafeOutcome.ok _, ?_⟩⟩
|
||||||
343: refine ⟨_, rfl, h', setLocal_safety hlocals val hbound⟩
|
intro s' heq_s'
|
||||||
344: case h_2 heq => contradiction
|
injection heq_s' with heq_state
|
||||||
345: case inr hbound => contradiction
|
rw [← heq_state]
|
||||||
346: case jump target => contradiction
|
rw [← heq_tys']
|
||||||
347: case jumpIf target => contradiction
|
exact ⟨StackMatches.cons (AvmVal.b _) h', rfl⟩
|
||||||
348: case prim p =>
|
|
||||||
349: unfold checkInstr at hcheck
|
/-- Type preservation theorem for single instruction step. -/
|
||||||
350: split at hcheck
|
theorem step_preservation {instr : Instr} {s : State} {tys : List AvmTy} {tys_locals : List (Option AvmTy)}
|
||||||
351: case h_1 stack' heq =>
|
(hstack : StackMatches s.stack tys) (hlocals : LocalsMatches s.locals tys_locals)
|
||||||
352: injection hcheck with hst hloc
|
(hpc : s.pc = 0) (hhalt : s.halted = false)
|
||||||
353: subst hst hloc
|
{tys' : List AvmTy} {tys_locals' : List (Option AvmTy)}
|
||||||
354: obtain ⟨s', heval, hst'⟩ := evalPrim_safety hstack heq
|
(hcheck : checkInstr instr tys tys_locals = some (tys', tys_locals'))
|
||||||
355: unfold step
|
(hnon_jump : match instr with | .jump _ | .jumpIf _ | .halt => False | _ => True) :
|
||||||
356: refine ⟨s', ?_, hst', hlocals⟩
|
∃ o, step [instr] s = o ∧ SafeOutcome o ∧ (∀ s', o = Outcome.ok s' → StackMatches s'.stack tys' ∧ LocalsMatches s'.locals tys_locals') := by
|
||||||
357: rw [heval]
|
rcases s with ⟨pc, stack, locals, halted⟩
|
||||||
358: case h_2 heq => contradiction
|
subst hpc hhalt
|
||||||
359: case halt => contradiction
|
cases instr
|
||||||
360:
|
case push val =>
|
||||||
361: end SilverSight.AVMIsa
|
unfold checkInstr at hcheck
|
||||||
|
injection hcheck with h
|
||||||
|
injection h with hst hloc
|
||||||
|
subst hst hloc
|
||||||
|
unfold step pop1
|
||||||
|
simp
|
||||||
|
split
|
||||||
|
· refine ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩
|
||||||
|
· refine ⟨SafeOutcome.ok _, ?_⟩
|
||||||
|
intro s' heq_s'
|
||||||
|
injection heq_s' with heq_state
|
||||||
|
rw [← heq_state]
|
||||||
|
exact ⟨StackMatches.cons val.val hstack, hlocals⟩
|
||||||
|
case pop =>
|
||||||
|
unfold checkInstr at hcheck
|
||||||
|
dsimp at hcheck
|
||||||
|
split at hcheck
|
||||||
|
case h_1 x xs heq =>
|
||||||
|
injection hcheck with h
|
||||||
|
injection h with hst hloc
|
||||||
|
subst hst hloc
|
||||||
|
cases hstack
|
||||||
|
unfold step pop1
|
||||||
|
simp
|
||||||
|
refine ⟨SafeOutcome.ok _, ⟨by assumption, hlocals⟩⟩
|
||||||
|
case h_2 heq => contradiction
|
||||||
|
case dup =>
|
||||||
|
unfold checkInstr at hcheck
|
||||||
|
dsimp at hcheck
|
||||||
|
split at hcheck
|
||||||
|
case h_1 x xs heq =>
|
||||||
|
injection hcheck with h
|
||||||
|
injection h with hst hloc
|
||||||
|
subst hst hloc
|
||||||
|
cases hstack with
|
||||||
|
| cons val h' =>
|
||||||
|
unfold step pop1
|
||||||
|
simp
|
||||||
|
split
|
||||||
|
· refine ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩
|
||||||
|
· refine ⟨SafeOutcome.ok _, ?_⟩
|
||||||
|
intro s' heq_s'
|
||||||
|
injection heq_s' with heq_state
|
||||||
|
rw [← heq_state]
|
||||||
|
exact ⟨StackMatches.cons val (StackMatches.cons val h'), hlocals⟩
|
||||||
|
case h_2 heq => contradiction
|
||||||
|
case swap =>
|
||||||
|
unfold checkInstr at hcheck
|
||||||
|
dsimp at hcheck
|
||||||
|
split at hcheck
|
||||||
|
case h_1 x y xs heq =>
|
||||||
|
injection hcheck with h
|
||||||
|
injection h with hst hloc
|
||||||
|
subst hst hloc
|
||||||
|
cases hstack with
|
||||||
|
| cons val1 h1 =>
|
||||||
|
cases h1 with
|
||||||
|
| cons val2 h2 =>
|
||||||
|
unfold step pop1
|
||||||
|
simp
|
||||||
|
refine ⟨SafeOutcome.ok _, ⟨StackMatches.cons val2 (StackMatches.cons val1 h2), hlocals⟩⟩
|
||||||
|
case h_2 heq => contradiction
|
||||||
|
case load i =>
|
||||||
|
unfold checkInstr at hcheck
|
||||||
|
dsimp at hcheck
|
||||||
|
split at hcheck <;> try contradiction
|
||||||
|
rename_i ty heq
|
||||||
|
injection hcheck with h
|
||||||
|
injection h with hst hloc
|
||||||
|
subst hst hloc
|
||||||
|
obtain ⟨val, hloc_val⟩ := getLocal_safety hlocals i heq
|
||||||
|
simp [getLocal?] at hloc_val
|
||||||
|
unfold step pop1 getLocal?
|
||||||
|
simp
|
||||||
|
rw [hloc_val]
|
||||||
|
simp
|
||||||
|
split
|
||||||
|
· refine ⟨SafeOutcome.stackOverflow, by intro s' h; contradiction⟩
|
||||||
|
· refine ⟨SafeOutcome.ok _, ?_⟩
|
||||||
|
intro s' heq_s'
|
||||||
|
injection heq_s' with heq_state
|
||||||
|
rw [← heq_state]
|
||||||
|
exact ⟨StackMatches.cons val hstack, hlocals⟩
|
||||||
|
case store i =>
|
||||||
|
unfold checkInstr at hcheck
|
||||||
|
dsimp at hcheck
|
||||||
|
split at hcheck
|
||||||
|
· -- isTrue
|
||||||
|
rename_i hbound
|
||||||
|
split at hcheck
|
||||||
|
case h_1 ty tys_tail heq =>
|
||||||
|
injection hcheck with h
|
||||||
|
injection h with hst hloc
|
||||||
|
subst hst hloc
|
||||||
|
cases hstack with
|
||||||
|
| cons val h' =>
|
||||||
|
unfold step pop1 setLocal?
|
||||||
|
simp
|
||||||
|
have hbound_locals : i < locals.length := by
|
||||||
|
rw [hlocals.1]
|
||||||
|
exact hbound
|
||||||
|
rw [if_pos hbound_locals]
|
||||||
|
simp
|
||||||
|
refine ⟨SafeOutcome.ok _, ⟨h', setLocal_safety hlocals i val hbound⟩⟩
|
||||||
|
case h_2 heq => contradiction
|
||||||
|
· -- isFalse
|
||||||
|
contradiction
|
||||||
|
case jump target => contradiction
|
||||||
|
case jumpIf target => contradiction
|
||||||
|
case prim p =>
|
||||||
|
unfold checkInstr at hcheck
|
||||||
|
dsimp at hcheck
|
||||||
|
split at hcheck
|
||||||
|
case h_1 stack' heq =>
|
||||||
|
injection hcheck with h
|
||||||
|
injection h with hst hloc
|
||||||
|
subst hst hloc
|
||||||
|
obtain ⟨o, heval, hsafe, hst'⟩ := evalPrim_safety hstack heq
|
||||||
|
unfold step
|
||||||
|
have hlookup : [Instr.prim p][0]? = some (Instr.prim p) := rfl
|
||||||
|
rw [hlookup]
|
||||||
|
simp
|
||||||
|
rw [heval]
|
||||||
|
cases o
|
||||||
|
case ok s1 =>
|
||||||
|
refine ⟨SafeOutcome.ok _, ?_⟩
|
||||||
|
intro s' heq_s'
|
||||||
|
injection heq_s' with heq_state
|
||||||
|
rw [← heq_state]
|
||||||
|
obtain ⟨hst_matches, hlocals_eq⟩ := hst' s1 rfl
|
||||||
|
dsimp at hlocals hlocals_eq ⊢
|
||||||
|
rw [hlocals_eq]
|
||||||
|
exact ⟨hst_matches, hlocals⟩
|
||||||
|
case err e =>
|
||||||
|
refine ⟨hsafe, by intro s' h; contradiction⟩
|
||||||
|
case h_2 heq => contradiction
|
||||||
|
case halt => contradiction
|
||||||
|
|
||||||
|
end SilverSight.AVMIsa
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue