Local Ltac t := solve [right; intros []; intros; breakhyps].Ltac t' i cnti :=
      right; intros [i']; intros [cnti']; intros ?; breakhyps;
      try (assert (i' = i) by congruence; subst i');
      try (assert (cnti' = cnti) by apply proof_irr; subst cnti');
      breakhyps.

(* Specifications: *)
Lemma safety_bupd : forall state n Gamma, (exists state', state_step state state' /\ (state_invariant Jspec' Gamma n state' \/ state_invariant Jspec' Gamma (S n) state')) -> exists state', state_step(ge := globalenv prog) state state' /\ (state_bupd (state_invariant Jspec' Gamma n) state' \/ state_bupd (state_invariant Jspec' Gamma (S n)) state').
Theorem safety_induction Gamma n state : state_invariant Jspec' Gamma (S n) state -> exists state', state_step(ge := globalenv prog) state state' /\ (state_bupd (state_invariant Jspec' Gamma n) state' \/ state_bupd (state_invariant Jspec' Gamma (S n)) state').
Lemma tp_bupd_mono : forall (P Q : jstate (globalenv prog) -> Prop) tp, (forall phi tp' phi', tp_update tp phi tp' phi' -> P tp' -> Q tp') -> tp_bupd P tp -> tp_bupd Q tp.
Lemma inv_step Gamma n state : inv Gamma (S n) state -> exists state', state_step state state' /\ state_bupd (inv Gamma n) state'.
Lemma num_tp_update : forall tp tp' phi phi', tp_update(ge := globalenv prog) tp phi tp' phi' -> num_threads tp' = num_threads tp.
Lemma no_Krun_stable_update tp tp' phi phi' : no_Krun tp -> tp_update tp phi tp' phi' -> no_Krun(ge := globalenv prog) tp'.
Lemma invariant_safe Gamma n state : inv Gamma n state -> jmsafe (globalenv prog) n state.