def _translate_waitlevel_method( self, expr: sil.PermExpression, node: ast.Compare, ctx: Context) -> sil.BoolExpression: """Translate ``WaitLevel() < Level()`` in method contract.""" position = self.to_position(node, ctx) info = self.no_info(ctx) obligation_info = ctx.actual_function.obligation_info guard = obligation_info.get_wait_level_guard(node.left) exhale = self._create_level_below_inex( guard, expr, obligation_info.residue_level, ctx) translated_exhale = exhale.translate(self, ctx, position, info) if ctx.ignore_waitlevel_constraints: return sil.TrueLit() if ctx.obligation_context.is_translating_posts: obligation_info.add_postcondition(translated_exhale) caller_inhale = sil.InhaleExhale( sil.PermVar(obligation_info.current_wait_level) < expr, sil.TrueLit()) return caller_inhale else: obligation_info.add_precondition(translated_exhale) body_inhale = sil.InhaleExhale( sil.PermVar(obligation_info.residue_level) < expr, sil.TrueLit()) return body_inhale
def construct_obligation_bound(self) -> sil.Statement: """Construct statement for bounding obligation.""" if self._credit_only: return sil.Exhale(sil.TrueLit()) return sil.If( self._unbounded_positive, [sil.Exhale(self._unbounded_acc), sil.Inhale(self._bounded_acc)], [])
def _create_level_below_inex(self, guard: sil.BoolExpression, expr: sil.PermExpression, level: PythonVar, ctx: Context) -> sil.BoolExpression: return sil.InhaleExhale( sil.TrueLit(), sil.Implies(guard, self.create_level_below(expr, sil.PermVar(level), ctx)))
def initialize_current_wait_level(self, current_wait_level: sil.PermExpression, residue_level_var: sil.PermExpression, ctx: Context) -> sil.BoolExpression: return sil.InhaleExhale( self._create_level_below_equal(current_wait_level, residue_level_var, ctx), sil.TrueLit())
def _set_loop_check_before(self) -> None: """Set the variable indicating that we are before loop.""" if obligation_config.disable_all: return assign = sil.Assign(self._loop_obligation_info.loop_check_before_var, sil.TrueLit()) info = self._to_info('We are before loop.') self._append_statement(assign, info=info)
def _construct_inhale(self, fresh: bool) -> sil.Acc: """Construct obligation inhale.""" if self._skip_inhale: return sil.TrueLit() if self._credit_only: return self._credit_acc if fresh: return self._unbounded_acc else: return self._bounded_acc
def _add_leak_check(self) -> None: """Add leak checks to invariant.""" reference_name = self._ctx.actual_function.get_fresh_name('_r') leak_check = self._obligation_manager.create_leak_check(reference_name) loop_check_before = sil.BoolVar( self._loop_obligation_info.loop_check_before_var) termination_flag = sil.BoolVar( self._loop_obligation_info.termination_flag_var) if not obligation_config.disable_loop_context_leak_check: must_terminate = self._obligation_manager.must_terminate_obligation predicate = must_terminate.create_predicate_access( self._obligation_info.current_thread_var) termination_leak_check = sil.CurrentPerm(predicate) == sil.NoPerm() loop_cond = self._loop_obligation_info.construct_loop_condition() before_loop_leak_check = sil.InhaleExhale( sil.TrueLit(), sil.Implies( loop_check_before, sil.BigOr([ termination_flag, sil.Not(loop_cond), sil.BigAnd([termination_leak_check, leak_check]) ]))) info = self._to_info('Leak check for context.') position = self._to_position( conversion_rules=rules.OBLIGATION_LOOP_CONTEXT_LEAK_CHECK_FAIL) self._obligation_loop.append_invariants([ before_loop_leak_check.translate(self._translator, self._ctx, position, info) ]) if not obligation_config.disable_loop_body_leak_check: body_leak_check = sil.InhaleExhale( sil.TrueLit(), sil.Implies(sil.Not(loop_check_before), leak_check)) info = self._to_info('Leak check for loop body.') position = self._to_position( conversion_rules=rules.OBLIGATION_LOOP_BODY_LEAK_CHECK_FAIL) self._obligation_loop.append_invariants([ body_leak_check.translate(self._translator, self._ctx, position, info) ])
def check(self, reference: sil.RefExpression, value: sil.IntExpression) -> sil.BoolExpression: """Generate a check if current value is smaller than in map.""" if (obligation_config.disable_measures or obligation_config.disable_measure_check): return sil.TrueLit() args = [ sil.CallArg('map', self._measure_var_type, sil.AnyVar(self._map_var)), sil.CallArg('key', sil.REF, reference), sil.CallArg('value', sil.INT, value), ] return sil.BoolCall('Measure$check', args)
def construct_use_method_bounded( self, measure_check: sil.BoolExpression, is_postconditon: bool) -> sil.BoolExpression: """Construct inhale exhale pair for use in method contract. Used for bounded obligations. """ if self._skip_exhale: exhale = sil.TrueLit() elif self._credit_only: exhale = self._credit_acc else: exhale = self._construct_bounded_exhale( measure_check if not is_postconditon else None) return sil.InhaleExhale(self._construct_inhale(False), exhale)
def construct_use_loop( self, measure_check: Optional[sil.BoolExpression], loop_check_before_var: sil.BoolVar) -> sil.BoolExpression: """Construct inhale exhale pair for use in loop invariant. ``measure_check is None`` indicates that obligation is fresh. """ if self._skip_exhale: exhale = sil.TrueLit() elif self._credit_only: exhale = self._credit_acc elif measure_check is None: exhale = self._construct_unbounded_exhale() else: exhale = sil.BoolCondExp( loop_check_before_var, self._construct_bounded_exhale(None), self._construct_bounded_exhale(measure_check)) inhale = self._construct_inhale(measure_check is None) return sil.InhaleExhale(inhale, exhale)
def _add_body_leak_check(self) -> None: """Add a leak check. Check that method body does not leak obligations. """ if obligation_config.disable_method_body_leak_check: return reference_name = self._python_method.get_fresh_name('_r') check = sil.InhaleExhale( sil.TrueLit(), self._obligation_manager.create_leak_check(reference_name)) node = self._python_method.node assert node position = self._translator.to_position( node, self._ctx, rules=rules.OBLIGATION_BODY_LEAK_CHECK_FAIL) info = self._translator.to_info(["Body leak check."], self._ctx) postcondition = check.translate(self._translator, self._ctx, position, info) self._obligation_method.append_postconditions([postcondition])
def _translate_waitlevel_loop( self, expr: sil.PermExpression, node: ast.Compare, ctx: Context) -> sil.BoolExpression: """Translate ``WaitLevel() < Level()`` in loop invariant.""" position = self.to_position(node, ctx) info = self.no_info(ctx) obligation_info = ctx.obligation_context.current_loop_info guard = obligation_info.get_wait_level_guard(node.left) context_info = ctx.obligation_context.get_surrounding_loop_info() if context_info: context_residue_level = context_info.residue_level else: method_info = ctx.current_function.obligation_info context_residue_level = method_info.residue_level body_inhale = sil.Inhale( sil.Implies( guard, sil.PermVar(obligation_info.residue_level) < expr)) obligation_info.prepend_body( body_inhale.translate(self, ctx, position, info)) body_exhale = sil.Implies( sil.Not(sil.BoolVar(obligation_info.loop_check_before_var)), self._create_level_below_inex( guard, expr, obligation_info.residue_level, ctx)) obligation_info.add_invariant( body_exhale.translate(self, ctx, position, info)) context_inhale = sil.Inhale( sil.Implies( guard, sil.PermVar(context_residue_level) < expr)) obligation_info.append_after_loop( context_inhale.translate(self, ctx, position, info)) context_exhale = sil.Implies( sil.BoolVar(obligation_info.loop_check_before_var), self._create_level_below_inex( guard, expr, context_residue_level, ctx)) obligation_info.add_invariant( context_exhale.translate(self, ctx, position, info)) return sil.TrueLit()
def _add_caller_leak_check(self) -> None: """Add a leak check. Check that if callee is not terminating, caller has no obligations. """ if obligation_config.disable_call_context_leak_check: return # MustTerminate leak check. must_terminate = self._obligation_manager.must_terminate_obligation cthread = self._obligation_info.current_thread_var predicate = must_terminate.create_predicate_access(cthread) termination_leak_check = sil.CurrentPerm(predicate) == sil.NoPerm() # Other obligations leak check. reference_name = self._python_method.get_fresh_name('_r') leak_check = self._obligation_manager.create_leak_check(reference_name) if self._python_method.interface: if must_terminate.is_interface_method_terminating( self._python_method.interface_dict): exhale = self._obligation_info.caller_measure_map.check( sil.RefVar(self._obligation_info.current_thread_var), sil.RawIntExpression(1)) else: exhale = sil.BigAnd([termination_leak_check, leak_check]) else: # Termination condition. tcond = self._obligation_info.create_termination_check(False) # Combination. exhale = sil.BigOr( [tcond, sil.BigAnd([termination_leak_check, leak_check])]) check = sil.InhaleExhale(sil.TrueLit(), exhale) # Translate to Silver. node = self.get_function_node() position = self._translator.to_position( node, self._ctx, rules=rules.OBLIGATION_CALL_LEAK_CHECK_FAIL) info = self._translator.to_info(["Caller side leak check"], self._ctx) precondition = check.translate(self._translator, self._ctx, position, info) self._obligation_method.append_preconditions([precondition])