예제 #1
0
    def create_verify_message_procedure(self, message: Message) -> UnitPart:
        specification = ProcedureSpecification(
            "Verify_Message", [InOutParameter(["Ctx"], "Context")])

        loop_invariant = And(
            Call("Has_Buffer", [Variable("Ctx")]),
            *common.context_invariant(message, loop_entry=True),
        )

        return UnitPart(
            [
                SubprogramDeclaration(
                    specification,
                    [
                        Precondition(
                            Call(
                                self.prefix * message.identifier *
                                "Has_Buffer",
                                [Variable("Ctx")],
                            )),
                        Postcondition(
                            And(
                                Call("Has_Buffer", [Variable("Ctx")]),
                                *common.context_invariant(message),
                            )),
                    ],
                )
            ],
            [
                SubprogramBody(
                    specification,
                    [],
                    [
                        ForIn(
                            "F",
                            Variable("Field"),
                            [
                                PragmaStatement("Loop_Invariant",
                                                [loop_invariant]),
                                CallStatement("Verify",
                                              [Variable("Ctx"),
                                               Variable("F")]),
                            ],
                        )
                    ],
                )
            ],
        )
예제 #2
0
def valid_path_to_next_field_condition(
    message: model.Message, field: model.Field, prefix: str
) -> Sequence[Expr]:
    return [
        If(
            [
                (
                    l.condition.substituted(substitution(message, public=True, prefix=prefix))
                    .simplified()
                    .ada_expr(),
                    And(
                        Equal(
                            Call(
                                "Predecessor",
                                [Variable("Ctx"), Variable(l.target.affixed_name)],
                            ),
                            Variable(field.affixed_name),
                        ),
                        Call(
                            "Valid_Next",
                            [Variable("Ctx"), Variable(l.target.affixed_name)],
                        )
                        if l.target != model.FINAL
                        else TRUE,
                    ),
                )
            ]
        )
        for l in message.outgoing(field)
        if l.target != model.FINAL
    ]
예제 #3
0
def public_context_predicate() -> Expr:
    return And(
        GreaterEqual(Call(const.TYPES_TO_INDEX, [Variable("First")]), Variable("Buffer_First")),
        LessEqual(Call(const.TYPES_TO_INDEX, [Variable("Last")]), Variable("Buffer_Last")),
        Less(Variable("Buffer_Last"), Last(const.TYPES_INDEX)),
        LessEqual(Variable("First"), Add(Variable("Last"), Number(1))),
        Less(Variable("Last"), Last(const.TYPES_BIT_INDEX)),
        Equal(Rem(Variable("First"), Size(const.TYPES_BYTE)), Number(1)),
        Equal(Rem(Variable("Last"), Size(const.TYPES_BYTE)), Number(0)),
    )
예제 #4
0
    def create_valid_function() -> UnitPart:
        specification = FunctionSpecification(
            "Valid", "Boolean",
            [Parameter(["Ctx"], "Context"),
             Parameter(["Fld"], "Field")])

        return UnitPart(
            [
                SubprogramDeclaration(
                    specification,
                    [
                        Postcondition(
                            If([(
                                Result("Valid"),
                                And(
                                    Call(
                                        "Structural_Valid",
                                        [Variable("Ctx"),
                                         Variable("Fld")],
                                    ),
                                    Call("Present",
                                         [Variable("Ctx"),
                                          Variable("Fld")]),
                                ),
                            )])),
                    ],
                )
            ],
            private=[
                ExpressionFunctionDeclaration(
                    specification,
                    AndThen(
                        Equal(
                            Selected(
                                Indexed(Variable("Ctx.Cursors"),
                                        Variable("Fld")), "State"),
                            Variable("S_Valid"),
                        ),
                        Less(
                            Selected(
                                Indexed(Variable("Ctx.Cursors"),
                                        Variable("Fld")), "First"),
                            Add(
                                Selected(
                                    Indexed(Variable("Ctx.Cursors"),
                                            Variable("Fld")), "Last"),
                                Number(1),
                            ),
                        ),
                    ),
                )
            ],
        )
예제 #5
0
 def _create_init_pred(self, slots: Sequence[NumberedSlotInfo]) -> UnitPart:
     return UnitPart([
         ExpressionFunctionDeclaration(
             FunctionSpecification("Initialized", "Boolean",
                                   [Parameter(["S"], "Slots")]),
             And(*[
                 NotEqual(
                     Variable("S" * self._slot_name(slot.slot_id)),
                     Variable("null"),
                 ) for slot in slots
             ]),
         )
     ])
예제 #6
0
 def cursors_invariant() -> Expr:
     return ForAllIn(
         "F",
         Variable("Field"),
         If(
             [
                 (
                     Call(
                         "Structural_Valid",
                         [Indexed(Variable("Cursors"), Variable("F"))],
                     ),
                     And(
                         GreaterEqual(
                             Selected(Indexed(Variable("Cursors"), Variable("F")), "First"),
                             Variable("First"),
                         ),
                         LessEqual(
                             Selected(Indexed(Variable("Cursors"), Variable("F")), "Last"),
                             Variable("Verified_Last"),
                         ),
                         LessEqual(
                             Selected(Indexed(Variable("Cursors"), Variable("F")), "First"),
                             Add(
                                 Selected(
                                     Indexed(Variable("Cursors"), Variable("F")),
                                     "Last",
                                 ),
                                 Number(1),
                             ),
                         ),
                         Call(
                             "Valid_Value",
                             [
                                 Variable("F"),
                                 Selected(
                                     Indexed(Variable("Cursors"), Variable("F")),
                                     "Value",
                                 ),
                             ],
                         ),
                     ),
                 )
             ]
         ),
     )
예제 #7
0
 def _create_global_allocated_pred(
         self, slots: Sequence[NumberedSlotInfo]) -> UnitPart:
     return UnitPart([
         ExpressionFunctionDeclaration(
             FunctionSpecification("Global_Allocated", "Boolean",
                                   [Parameter(["S"], "Slots")]),
             And(
                 *[
                     Equal(
                         Variable("S" * self._slot_name(slot.slot_id)),
                         Variable("null"),
                     ) for slot in slots if slot.global_
                 ],
                 *[
                     NotEqual(
                         Variable("S" * self._slot_name(slot.slot_id)),
                         Variable("null"),
                     ) for slot in slots if not slot.global_
                 ],
             ),
         )
     ])
예제 #8
0
    def create_verify_procedure(
        self,
        message: Message,
        scalar_fields: Mapping[Field, Scalar],
        composite_fields: Sequence[Field],
    ) -> UnitPart:
        specification = ProcedureSpecification(
            "Verify",
            [InOutParameter(["Ctx"], "Context"),
             Parameter(["Fld"], "Field")])

        valid_field_condition = AndThen(
            Call(
                "Valid_Value",
                [Variable("Fld"), Variable("Value")],
            ),
            Call(
                "Field_Condition",
                [
                    Variable("Ctx"),
                    Variable("Fld"),
                    *([Variable("Value")] if
                      common.has_value_dependent_condition(message) else []),
                    *([
                        Slice(
                            Variable("Ctx.Buffer.all"),
                            Call(
                                const.TYPES_TO_INDEX,
                                [
                                    Call("Field_First",
                                         [Variable("Ctx"),
                                          Variable("Fld")])
                                ],
                            ),
                            Call(
                                const.TYPES_TO_INDEX,
                                [
                                    Call("Field_Last",
                                         [Variable("Ctx"),
                                          Variable("Fld")])
                                ],
                            ),
                        )
                    ] if common.has_aggregate_dependent_condition(message) else
                      []),
                    *([Call("Field_Size",
                            [Variable("Ctx"), Variable("Fld")])]
                      if common.has_size_dependent_condition(message) else []),
                ],
            ),
        )

        last = Mul(
            Div(
                Add(
                    Call("Field_Last",
                         [Variable("Ctx"), Variable("Fld")]),
                    Size(const.TYPES_BYTE),
                    -Number(1),
                ),
                Size(const.TYPES_BYTE),
            ),
            Size(const.TYPES_BYTE),
        )
        set_cursors_statements = [
            *([
                PragmaStatement(
                    "Assert",
                    [
                        If([(
                            Or(*[
                                Equal(Variable("Fld"), Variable(
                                    f.affixed_name))
                                for f in message.direct_predecessors(FINAL)
                            ]),
                            Equal(
                                Mod(
                                    Call("Field_Last",
                                         [Variable("Ctx"),
                                          Variable("Fld")]),
                                    Size(const.TYPES_BYTE),
                                ),
                                Number(0),
                            ),
                        )])
                    ],
                )
            ] if len(message.fields) > 1 else []),
            # Improve provability of context predicate
            PragmaStatement(
                "Assert",
                [Equal(Mod(last, Size(const.TYPES_BYTE)), Number(0))]),
            Assignment(Variable("Ctx.Verified_Last"), last),
            PragmaStatement(
                "Assert",
                [
                    LessEqual(
                        Call("Field_Last", [Variable("Ctx"),
                                            Variable("Fld")]),
                        Variable("Ctx.Verified_Last"),
                    )
                ],
            ),
            IfStatement(
                [(
                    Call("Composite_Field", [Variable("Fld")]),
                    [set_context_cursor_composite_field("Fld")],
                )],
                [set_context_cursor_scalar()],
            ) if scalar_fields and composite_fields else
            set_context_cursor_scalar()
            if scalar_fields and not composite_fields else
            set_context_cursor_composite_field("Fld"),
            *([
                # https://github.com/Componolit/RecordFlux/issues/664
                # The provability of the context predicate is increased by splitting the
                # assignment into multiple statements.
                Assignment(
                    Indexed(
                        Variable("Ctx.Cursors"),
                        Call(
                            "Successor",
                            [Variable("Ctx"), Variable("Fld")],
                        ),
                    ),
                    NamedAggregate(
                        ("State", Variable("S_Invalid")),
                        ("Predecessor", Variable("Fld")),
                    ),
                )
            ] if len(message.fields) > 1 else []),
        ]

        return UnitPart(
            [
                SubprogramDeclaration(
                    specification,
                    [
                        Precondition(
                            Call(
                                self.prefix * message.identifier *
                                "Has_Buffer",
                                [Variable("Ctx")],
                            )),
                        Postcondition(
                            And(
                                Call("Has_Buffer", [Variable("Ctx")]),
                                *common.context_invariant(message),
                            )),
                    ],
                )
            ],
            [
                SubprogramBody(
                    specification,
                    [ObjectDeclaration(["Value"], const.TYPES_BASE_INT)],
                    [
                        IfStatement([(
                            AndThen(
                                Call(
                                    "Invalid",
                                    [
                                        Indexed(Variable("Ctx.Cursors"),
                                                Variable("Fld"))
                                    ],
                                ),
                                Call("Valid_Predecessor",
                                     [Variable("Ctx"),
                                      Variable("Fld")]),
                                Call("Path_Condition",
                                     [Variable("Ctx"),
                                      Variable("Fld")]),
                            ),
                            [
                                IfStatement(
                                    [(
                                        Call(
                                            "Sufficient_Buffer_Length",
                                            [Variable("Ctx"),
                                             Variable("Fld")],
                                        ),
                                        [
                                            Assignment(
                                                "Value",
                                                If(
                                                    [(
                                                        Call(
                                                            "Composite_Field",
                                                            [
                                                                Variable(
                                                                    "Fld"),
                                                            ],
                                                        ),
                                                        Number(0),
                                                    )],
                                                    Call(
                                                        "Get",
                                                        [
                                                            Variable("Ctx"),
                                                            Variable("Fld"),
                                                        ],
                                                    ),
                                                ) if scalar_fields
                                                and composite_fields else Call(
                                                    "Get",
                                                    [
                                                        Variable("Ctx"),
                                                        Variable("Fld"),
                                                    ],
                                                ) if scalar_fields else
                                                Number(0),
                                            ),
                                            IfStatement(
                                                [(
                                                    valid_field_condition,
                                                    set_cursors_statements,
                                                )],
                                                [
                                                    Assignment(
                                                        Indexed(
                                                            Variable(
                                                                "Ctx.Cursors"),
                                                            Variable("Fld"),
                                                        ),
                                                        NamedAggregate(
                                                            (
                                                                "State",
                                                                Variable(
                                                                    "S_Invalid"
                                                                ),
                                                            ),
                                                            (
                                                                "Predecessor",
                                                                Variable(
                                                                    FINAL.
                                                                    affixed_name,
                                                                ),
                                                            ),
                                                        ),
                                                    )
                                                ],
                                            ),
                                        ],
                                    )],
                                    [
                                        Assignment(
                                            Indexed(Variable("Ctx.Cursors"),
                                                    Variable("Fld")),
                                            NamedAggregate(
                                                ("State",
                                                 Variable("S_Incomplete")),
                                                (
                                                    "Predecessor",
                                                    Variable(
                                                        FINAL.affixed_name),
                                                ),
                                            ),
                                        )
                                    ],
                                )
                            ],
                        )], )
                    ],
                )
            ],
        )
예제 #9
0
    def create_generic_opaque_getter_procedures(
            self, message: Message,
            opaque_fields: Sequence[Field]) -> UnitPart:
        def specification(field: Field) -> ProcedureSpecification:
            return ProcedureSpecification(f"Generic_Get_{field.name}",
                                          [Parameter(["Ctx"], "Context")])

        return UnitPart(
            [
                SubprogramDeclaration(
                    specification(f),
                    [
                        Precondition(
                            And(
                                Call(
                                    self.prefix * message.identifier *
                                    "Has_Buffer",
                                    [Variable("Ctx")],
                                ),
                                Call(
                                    self.prefix * message.identifier *
                                    "Present",
                                    [
                                        Variable("Ctx"),
                                        Variable(
                                            self.prefix * message.identifier *
                                            f.affixed_name),
                                    ],
                                ),
                            ))
                    ],
                    [
                        FormalSubprogramDeclaration(
                            ProcedureSpecification(
                                f"Process_{f.name}",
                                [Parameter([f.name], const.TYPES_BYTES)]))
                    ],
                ) for f in opaque_fields
            ],
            [
                SubprogramBody(
                    specification(f),
                    [
                        ObjectDeclaration(
                            ["First"],
                            const.TYPES_INDEX,
                            Call(
                                const.TYPES_TO_INDEX,
                                [
                                    Selected(
                                        Indexed(
                                            Variable("Ctx.Cursors"),
                                            Variable(f.affixed_name),
                                        ),
                                        "First",
                                    )
                                ],
                            ),
                            constant=True,
                        ),
                        ObjectDeclaration(
                            ["Last"],
                            const.TYPES_INDEX,
                            Call(
                                const.TYPES_TO_INDEX,
                                [
                                    Selected(
                                        Indexed(
                                            Variable("Ctx.Cursors"),
                                            Variable(f.affixed_name),
                                        ),
                                        "Last",
                                    )
                                ],
                            ),
                            constant=True,
                        ),
                    ],
                    [
                        CallStatement(
                            f"Process_{f.name}",
                            [
                                Slice(Variable("Ctx.Buffer.all"),
                                      Variable("First"), Variable("Last"))
                            ],
                        )
                    ],
                ) for f in opaque_fields
            ],
        )
예제 #10
0
def context_predicate(
    message: model.Message, composite_fields: Sequence[model.Field], prefix: str
) -> Expr:
    def cursors_invariant() -> Expr:
        return ForAllIn(
            "F",
            Variable("Field"),
            If(
                [
                    (
                        Call(
                            "Structural_Valid",
                            [Indexed(Variable("Cursors"), Variable("F"))],
                        ),
                        And(
                            GreaterEqual(
                                Selected(Indexed(Variable("Cursors"), Variable("F")), "First"),
                                Variable("First"),
                            ),
                            LessEqual(
                                Selected(Indexed(Variable("Cursors"), Variable("F")), "Last"),
                                Variable("Verified_Last"),
                            ),
                            LessEqual(
                                Selected(Indexed(Variable("Cursors"), Variable("F")), "First"),
                                Add(
                                    Selected(
                                        Indexed(Variable("Cursors"), Variable("F")),
                                        "Last",
                                    ),
                                    Number(1),
                                ),
                            ),
                            Call(
                                "Valid_Value",
                                [
                                    Variable("F"),
                                    Selected(
                                        Indexed(Variable("Cursors"), Variable("F")),
                                        "Value",
                                    ),
                                ],
                            ),
                        ),
                    )
                ]
            ),
        )

    def valid_predecessors_invariant() -> Expr:
        return AndThen(
            *[
                If(
                    [
                        (
                            Call(
                                "Structural_Valid",
                                [
                                    Indexed(
                                        Variable("Cursors"),
                                        Variable(f.affixed_name),
                                    )
                                ],
                            ),
                            Or(
                                *[
                                    expr.AndThen(
                                        expr.Call(
                                            "Structural_Valid"
                                            if l.source in composite_fields
                                            else "Valid",
                                            [
                                                expr.Indexed(
                                                    expr.Variable("Cursors"),
                                                    expr.Variable(l.source.affixed_name),
                                                )
                                            ],
                                        ),
                                        expr.Equal(
                                            expr.Selected(
                                                expr.Indexed(
                                                    expr.Variable("Cursors"),
                                                    expr.Variable(f.affixed_name),
                                                ),
                                                "Predecessor",
                                            ),
                                            expr.Variable(l.source.affixed_name),
                                        ),
                                        l.condition.substituted(
                                            substitution(message, embedded=True, prefix=prefix)
                                        ),
                                    )
                                    .simplified()
                                    .ada_expr()
                                    for l in message.incoming(f)
                                ]
                            ),
                        )
                    ]
                )
                for f in message.fields
                if f not in message.direct_successors(model.INITIAL)
            ]
        )

    def invalid_successors_invariant() -> Expr:
        return AndThen(
            *[
                If(
                    [
                        (
                            AndThen(
                                *[
                                    Call(
                                        "Invalid",
                                        [
                                            Indexed(
                                                Variable("Cursors"),
                                                Variable(p.affixed_name),
                                            )
                                        ],
                                    )
                                    for p in message.direct_predecessors(f)
                                ]
                            ),
                            Call(
                                "Invalid",
                                [
                                    Indexed(
                                        Variable("Cursors"),
                                        Variable(f.affixed_name),
                                    )
                                ],
                            ),
                        )
                    ]
                )
                for f in message.fields
                if f not in message.direct_successors(model.INITIAL)
            ]
        )

    return AndThen(
        If(
            [
                (
                    NotEqual(Variable("Buffer"), Variable("null")),
                    And(
                        Equal(First("Buffer"), Variable("Buffer_First")),
                        Equal(Last("Buffer"), Variable("Buffer_Last")),
                    ),
                )
            ]
        ),
        public_context_predicate(),
        LessEqual(Sub(Variable("First"), Number(1)), Variable("Verified_Last")),
        LessEqual(Sub(Variable("First"), Number(1)), Variable("Written_Last")),
        LessEqual(Variable("Verified_Last"), Variable("Written_Last")),
        LessEqual(Variable("Written_Last"), Variable("Last")),
        Equal(Rem(Variable("First"), Size(const.TYPES_BYTE)), Number(1)),
        Equal(Rem(Variable("Last"), Size(const.TYPES_BYTE)), Number(0)),
        Equal(Rem(Variable("Verified_Last"), Size(const.TYPES_BYTE)), Number(0)),
        Equal(Rem(Variable("Written_Last"), Size(const.TYPES_BYTE)), Number(0)),
        cursors_invariant(),
        valid_predecessors_invariant(),
        invalid_successors_invariant(),
        message_structure_invariant(message, prefix, embedded=True),
    )