Esempio n. 1
0
    def get_use_loop(self, ctx: Context) -> List[Tuple[sil.Expression, Rules]]:
        """Default implementation for obligation use in loop invariant."""
        obligation_info = ctx.obligation_context.current_loop_info

        terms = []

        # Positive measure.
        if not self.is_fresh():
            loop_condition = obligation_info.construct_loop_condition()
            positive_measure = sil.Implies(loop_condition,
                                           self.get_measure() > 0)
            if not positive_measure.is_always_true():
                terms.append((positive_measure,
                              rules.OBLIGATION_LOOP_MEASURE_NON_POSITIVE))

        # Actual inhale / exhale.
        inexhale = self._get_inexhale(ctx)
        if self.is_fresh():
            measure_check = None
        else:
            measure_check = obligation_info.loop_measure_map.check(
                self.get_target(), self.get_measure())
        inhale_exhale = inexhale.construct_use_loop(
            measure_check, sil.BoolVar(obligation_info.loop_check_before_var))
        terms.append((inhale_exhale, None))

        return terms
Esempio n. 2
0
 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)))
Esempio n. 3
0
    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)
            ])
Esempio n. 4
0
    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()
Esempio n. 5
0
    def _reset_must_terminate(self, amount_var: PythonVar) -> None:
        """Reset ``MustTerminate`` permission to its original level.

        .. note::

            Implication is needed because in Silicon if callee took all
            permission, the ``exhale acc(..., none)`` would fail, even
            though this exhale does nothing.
        """
        if obligation_config.disable_termination_check:
            return
        predicate = self._get_must_terminate_predicate()
        original_amount = sil.PermVar(amount_var)
        perm = sil.CurrentPerm(predicate) - original_amount
        exhale = sil.Exhale(sil.Implies(
            sil.CurrentPerm(predicate) > sil.NoPerm(),
            sil.Acc(predicate, perm)))
        info = self._to_info('Reset MustTerminate amount to original level.')
        self._append_statement(exhale, info=info)
Esempio n. 6
0
 def _check_loop_preserves_termination(self) -> None:
     """Check that loop keeps the promise to terminate."""
     if obligation_config.disable_termination_check:
         return
     check = sil.Implies(
         sil.BoolVar(self._loop_obligation_info.termination_flag_var),
         sil.BigOr([
             sil.Not(self._loop_obligation_info.construct_loop_condition()),
             self._loop_obligation_info.create_termination_check(False)
         ]))
     assertion = sil.Assert(check)
     position = self._to_position(
         conversion_rules=rules.OBLIGATION_LOOP_TERMINATION_PROMISE_FAIL)
     comment = 'Check if loop continues to terminate.'
     if isinstance(self._viper, ViperASTExtended):
         info = self._viper.SIFInfo([comment], continue_unaware=True)
     else:
         info = self._to_info(comment)
     statement = assertion.translate(self._translator, self._ctx, position,
                                     info)
     self._obligation_loop.append_body(statement)