예제 #1
0
def generate_array_ref(decl, subscript_base):
    """
  Generate ArrayRef from Decl.
  For example:
    int array[1][2][3];
  Should become:
    array[subscript_base_i0][subscript_base_i1][subscript_base_i2]
  """
    if isinstance(decl.type.type, c_ast.ArrayDecl):
        # Multi-dimensional, recurse
        name = generate_array_ref(decl.type, subscript_base)
        # Subscript index is one more than the node below
        subscript_index = int(name.subscript.name[-1]) + 1
        if subscript_index >= 10:
            raise Exception(
                "Only single-digit subscript indicies currently supported. Please fix."
            )
    else:
        # Single or last dimension
        name = c_ast.ID(decl.type.type.declname)
        # Base node has subscript index of 0
        subscript_index = 0

    # Create ArrayRef
    array_ref = c_ast.ArrayRef(
        name, c_ast.ID("%s%d" % (subscript_base, subscript_index)))
    return array_ref
예제 #2
0
    def _assign(self, variable: Union[c_ast.ID, c_ast.ArrayRef],
                expression: ExprType, node: c_ast.Node):
        """T-Asgn rule, which can be re-used both in Assignment node and Decl node"""
        # get new distance from the assignment expression (T-Asgn)
        variable_name = variable.name if isinstance(
            variable, c_ast.ID) else variable.name.name
        var_aligned, var_shadow, *_ = self._type_system.get_types(
            variable_name)
        aligned, shadow = DistanceGenerator(
            self._type_system).visit(expression)
        if self._loop_level == 0:
            # insert x^align = n^align if x^aligned is *
            if var_aligned == '*' or aligned != '0':
                self._insert_at(
                    node,
                    parse(
                        f'{constants.ALIGNED_DISTANCE}_{variable_name} = {aligned}'
                    ),
                    after=True)

            if self._enable_shadow:
                # generate x^shadow = x + x^shadow - e according to (T-Asgn)
                if self._pc:
                    if isinstance(variable, c_ast.ID):
                        shadow_distance = c_ast.ID(
                            name=f'{constants.SHADOW_DISTANCE}_{variable_name}'
                        )
                    elif isinstance(variable, c_ast.ArrayRef):
                        shadow_distance = c_ast.ArrayRef(
                            name=f'{constants.SHADOW_DISTANCE}_{variable_name}',
                            subscript=variable.subscript)
                    else:
                        raise NotImplementedError(
                            f'Assigned value type not supported {type(variable)}'
                        )
                    # insert x^shadow = x + x^shadow - e;
                    insert_node = c_ast.Assignment(
                        op='=',
                        lvalue=shadow_distance,
                        rvalue=c_ast.BinaryOp(op='-',
                                              left=c_ast.BinaryOp(
                                                  op='+',
                                                  left=variable,
                                                  right=shadow_distance),
                                              right=expression))
                    self._insert_at(node, insert_node, after=False)
                # insert x^shadow = n^shadow if n^shadow is not 0
                elif var_shadow == '*' or shadow != '0':
                    self._insert_at(
                        node,
                        parse(
                            f'{constants.SHADOW_DISTANCE}_{variable_name} = {shadow}'
                        ),
                        after=True)

        shadow_distance = '*' if self._pc or shadow != '0' or var_shadow == '*' else '0'
        aligned_distance = '*' if aligned != '0' or var_aligned == '*' else '0'
        self._type_system.update_distance(variable_name, aligned_distance,
                                          shadow_distance)
예제 #3
0
def astAssiDef(isr):
    larr = c_ast.ArrayRef(
        c_ast.ID('deferral'), c_ast.Constant(
            'int',
            str(int(isr) - 1)))  # the second param of Constant is String
    rarr = c_ast.UnaryOp('&', c_ast.ID('deferral_' + isr))
    assi = c_ast.Assignment('=', larr, rarr)
    return assi
예제 #4
0
    def __array_ref(self, subs: List[c_ast.Node]) -> c_ast.Node:
        """
        A helper function to construct an ArrayRef with given subscripts.

        Example: A[sub0][sub1][sub2]

        :param subs: List of subs for subsequent dimensions.
        :return: c_ast.ArrayRef or c_ast.ID if subs is empty
        """
        if len(subs) == 0:
            return c_ast.ID(self.name)
        else:
            sub = subs[-1]
            return c_ast.ArrayRef(self.__array_ref(subs[:-1]), sub)
예제 #5
0
 def _replace(self, node):
     if not isinstance(node, (c_ast.ArrayRef, c_ast.ID)):
         raise NotImplementedError('Expression type {} currently not supported.'.format(type(node)))
     varname = node.name.name if isinstance(node, c_ast.ArrayRef) else node.name
     alignd, shadow = self._types.get_distance(varname)
     distance = alignd if self._is_aligned else shadow
     if distance == '0':
         return node
     elif distance == '*':
         distance_varname = '__SHADOWDP_{}_DISTANCE_{}'.format('ALIGNED' if self._is_aligned else 'SHADOW', varname)
         distance_var = c_ast.ArrayRef(name=c_ast.ID(name=distance_varname), subscript=node.subscript) \
             if isinstance(node, c_ast.ArrayRef) else c_ast.ID(name=distance_varname)
         return c_ast.BinaryOp(op='+', left=node, right=distance_var)
     else:
         return c_ast.BinaryOp(op='+', left=node, right=convert_to_ast(distance))
예제 #6
0
 def _replace(self, node):
     if not isinstance(node, (c_ast.ArrayRef, c_ast.ID)):
         raise NotImplementedError(f'Expression type {type(node)} currently not supported.')
     varname = node.name.name if isinstance(node, c_ast.ArrayRef) else node.name
     alignd, shadow, *_ = self._types.get_types(varname)
     distance = alignd if self._is_aligned else shadow
     if distance == '0':
         return node
     elif distance == '*':
         distance_varname = \
             f'{constants.ALIGNED_DISTANCE if self._is_aligned else constants.SHADOW_DISTANCE}_{varname}'
         distance_var = c_ast.ArrayRef(name=c_ast.ID(name=distance_varname), subscript=node.subscript) \
             if isinstance(node, c_ast.ArrayRef) else c_ast.ID(name=distance_varname)
         return c_ast.BinaryOp(op='+', left=node, right=distance_var)
     else:
         return c_ast.BinaryOp(op='+', left=node, right=parse(distance))
예제 #7
0
    def visit_ArrayRef(self, n):
        if isinstance(n.name, c_ast.ID):
            if isinstance(n.name, c_ast.ID):
                dim_decl = self.dim_decl_stack[-1].get(n.name.name)
            else:
                dim_decl = None

            if isinstance(n.subscript, c_ast.ExprList):
                indices = n.subscript.exprs
            else:
                indices = (n.subscript, )

            if dim_decl is not None:
                return self.generate_array_ref(dim_decl, n.name.name, indices,
                                               n.coord)

        return self.generator_base_class.visit_ArrayRef(
            self, c_ast.ArrayRef(n.name, n.subscript, n.coord))
예제 #8
0
    def visit_Assignment(self, node):
        logger.debug('Line {}: {}'.format(str(node.coord.line), _code_generator.visit(node)))
        varname = node.lvalue.name if isinstance(node.lvalue, c_ast.ID) else node.lvalue.name.name
        if self._loop_level == 0 and self._pc:
            # generate x^shadow = x + x^shadow - e according to (T-Asgn)
            parent = self._parents[node]
            if isinstance(parent, c_ast.Compound):
                node_index = parent.block_items.index(node)
                if isinstance(node.lvalue, c_ast.ID):
                    shadow_distance = c_ast.ID(name='__SHADOWDP_SHADOW_DISTANCE_{}'.format(varname))
                elif isinstance(node.lvalue, c_ast.ArrayRef):
                    shadow_distance = c_ast.ArrayRef(name='__SHADOWDP_SHADOW_DISTANCE_{}'.format(varname),
                                                     subscript=node.lvalue.subscript)
                else:
                    raise NotImplementedError('Assigned value type not supported {}'.format(type(node.lvalue)))
                # insert x^shadow = x + x^shadow - e;
                insert_node = c_ast.Assignment(op='=', lvalue=shadow_distance, rvalue=c_ast.BinaryOp(
                    op='-', left=c_ast.BinaryOp(op='+', left=node.lvalue, right=shadow_distance), right=node.rvalue))
                parent.block_items.insert(node_index, insert_node)
                self._inserted.add(insert_node)
                self._inserted.add(node)
            else:
                raise NotImplementedError('Parent of assignment node not supported {}'.format(type(parent)))

        # check the distance dependence
        dependence_finder = _ExpressionFinder(
            lambda to_check: (isinstance(to_check, c_ast.ID) and to_check.name == varname) or
                             (isinstance(to_check, c_ast.ArrayRef) and to_check.name.name == varname),
            lambda to_ignore: isinstance(to_ignore, c_ast.ArrayRef) and to_ignore.name.name == self._parameters[2]
        )
        for name, distances in self._types.variables():
            if name not in self._random_variables:
                for distance in distances:
                    if distance != '*':
                        if len(dependence_finder.visit(convert_to_ast(distance))) != 0:
                            raise DistanceDependenceError(node.coord, varname, distance)

        # get new distance from the assignment expression (T-Asgn)
        aligned, shadow = _DistanceGenerator(self._types).visit(node.rvalue)
        if self._pc:
            self._types.update_distance(node.lvalue.name, aligned, '*')
        else:
            self._types.update_distance(node.lvalue.name, aligned, shadow)
        logger.debug('types: {}'.format(self._types))
예제 #9
0
def split_func(fd, ofile):
    prog = FlatProgram()
    has_nested = False

    (fd, nondet) = replace_nondet(fd)
    fd_body = fd.body

    for i in xrange(nondet):
        id = c_ast.ID('nondet_%d' % i)

        decl = c_ast.Decl(
            id.name, [], [], [],
            c_ast.TypeDecl(id.name, [], c_ast.IdentifierType(['word_t'])),
            None, None)

        fd_body.block_items.insert(0, decl)

    flatten(fd_body, prog)
    cgen = c_generator.CGenerator()
    (id_map, rev_id_map) = number_ids(fd)
    f = FileWriter(ofile, cgen)

    f.write('#include "synth.h"\n')
    f.write("/*\n")

    for id in sorted(rev_id_map.keys()):
        f.write(" * %s -> %d\n" % (rev_id_map[id], id))

    f.write("*/\n\n")

    nids = len(id_map)

    prefix = copy.deepcopy(prog.blocks[0])
    loop = copy.deepcopy(prog.blocks[1])

    #(prefix, prefix_nondet) = replace_nondet(prefix)
    #(guard, guard_nondet) = replace_nondet(loop.cond)
    #(body, body_nondet) = replace_nondet(loop.stmt)

    decls = []
    copy_out = []
    prefix_block = []

    retvis = ReturnVisitor()
    retvis.visit(prefix)

    for b in prefix.block_items:
        prefix_block.append(b)

        if isinstance(b, c_ast.Decl):
            id = b.name
            vid = id_map[id]

            b.init = c_ast.ArrayRef(c_ast.ID('in_vars'),
                                    c_ast.Constant('int', str(vid)))

            decls.append(b)

            if is_signed(b):
                extend = c_ast.FuncCall(c_ast.ID('SIGN_EXTEND'),
                                        c_ast.ExprList([c_ast.ID(id)]))
                decls.append(extend)
                prefix_block.append(extend)

    prefix.block_items = prefix_block

    for id in sorted(rev_id_map.keys()):
        varname = rev_id_map[id]
        arr = c_ast.ArrayRef(c_ast.ID('out_vars'),
                             c_ast.Constant('int', str(id)))
        var = c_ast.ID(varname)

        copy_out.append(c_ast.Assignment("=", arr, var))

    copy_out.append(c_ast.Return(c_ast.Constant('int', str('1'))))

    prefix.block_items += copy_out

    f.write("int prefix(word_t in_vars[NARGS], word_t out_vars[NARGS]) {\n")
    f.write(prefix)
    f.write("}\n\n")

    f.write("int guard(word_t in_vars[NARGS]) {\n")
    guard_body = c_ast.Compound(copy.copy(decls))
    guard_body.block_items.append(c_ast.Return(loop.cond))
    f.write(guard_body)
    ofile.write("}\n\n")

    if is_nested_loop(loop):
        has_nested = True

        nested_prog = FlatProgram()
        flatten(loop.stmt, nested_prog)
        inner_prefix = nested_prog.blocks[0]
        inner_body = nested_prog.blocks[1]
        inner_suffix = nested_prog.blocks[2]

        inner_guard = c_ast.Compound(
            copy.copy(decls) + [c_ast.Return(inner_body.cond)])

        if isinstance(inner_body.stmt, c_ast.Compound):
            inner_body = inner_body.stmt.block_items
        else:
            inner_body = [inner_body.stmt]

        inner_body = c_ast.Compound(copy.copy(decls) + inner_body + copy_out)
        outer_guard = c_ast.Compound(
            copy.copy(decls) + [c_ast.Return(loop.cond)])

        f.write(
            "int inner_prefix(word_t in_vars[NARGS], word_t out_vars[NARGS]) {\n"
        )
        inner_prefix.block_items = decls + inner_prefix.block_items + copy_out
        f.write(inner_prefix)
        f.write("}\n\n")

        f.write("int inner_guard(word_t in_vars[NARGS]) {\n")
        f.write(inner_guard)
        f.write("}\n\n")

        f.write(
            "int inner_body(word_t in_vars[NARGS], word_t out_vars[NARGS]) {\n"
        )
        f.write(inner_body)
        f.write("}\n\n")

        f.write(
            "int inner_suffix(word_t in_vars[NARGS], word_t out_vars[NARGS]) {\n"
        )
        inner_suffix.block_items = decls + inner_suffix.block_items + copy_out
        f.write(inner_suffix)
        f.write("}\n\n")

        f.write("int outer_guard(word_t in_vars[NARGS]) {\n")
        f.write(outer_guard)
        f.write("}\n\n")
    else:
        f.write("int body(word_t in_vars[NARGS], word_t out_vars[NARGS]) {\n")
        loop_body = c_ast.Compound(
            copy.copy(decls) + loop.stmt.block_items + copy_out)
        f.write(loop_body)
        f.write("}\n\n")

    return (rev_id_map, has_nested, nondet)
예제 #10
0
    def create_havoc_assignment(self,
                                declaration: c_ast.Decl,
                                parent: c_ast.Node = None):
        """
		Creates a havoc assignment block for the variable declared in the given declaration.
		:param declaration: The declaration of the variable to havoc.
		:return: First entry: A set of strings containing the employed non-deterministic assignment SV comp function
			names, e.g. "__VERIFIER_nondet_int". Second entry: A block containing all havoc assignments for that
			variable.
		:parent: A parent node for aggregates to allow for access of the children. Either c_ast.StructRef,
			c_ast.ArrayRef or c_ast.UnaryOp with op="*".
		:rtype: set of str, c_ast.Compound
		"""
        # Here be dragons. Most likely contains some bugs.
        # TODO Should be tested thoroughly.
        body_items = []
        svcomp_havoc_functions = set()
        # First, registers itself into the parent struct, if there is one.
        if type(parent) == c_ast.StructRef and parent.field is None:
            parent.field = c_ast.ID(declaration.name)
        # Checks for five main cases: We have a basic identifier, a struct, a union, an array or a pointer.
        # If a compound type is encountered, this function is called recursively on the child declaration(s).
        if type(declaration.type) == c_ast.TypeDecl:
            # CASE STRUCT
            if type(declaration.type.type) == c_ast.Struct:
                # Iterates over every struct member and creates a havoc block for this. Useful for nested structs.
                if declaration.type.type.decls:
                    for member in declaration.type.type.decls:
                        if parent is None:
                            new_parent = c_ast.StructRef(
                                c_ast.ID(declaration.name), ".", None)
                        else:
                            new_parent = c_ast.StructRef(parent, ".", None)
                        rec_svcomp_havoc_funcs, rec_havoc_block = self.create_havoc_assignment(
                            member, new_parent)
                        body_items.append(rec_havoc_block)
                        svcomp_havoc_functions = svcomp_havoc_functions.union(
                            rec_svcomp_havoc_funcs)
            # CASE UNION
            elif type(declaration.type.type) == c_ast.Union and len(
                    declaration.type.type.decls) > 0:
                # For a union, we just havoc the very first member.
                if parent is None:
                    new_parent = c_ast.StructRef(c_ast.ID(declaration.name),
                                                 ".", None)
                else:
                    new_parent = c_ast.StructRef(parent, ".", None)
                rec_svcomp_havoc_funcs, rec_havoc_block = self.create_havoc_assignment(
                    declaration.type.type.decls[0], new_parent)
                body_items.append(rec_havoc_block)
                svcomp_havoc_functions = svcomp_havoc_functions.union(
                    rec_svcomp_havoc_funcs)
            # CASE BASIC IDENTIFIER
            elif type(declaration.type.type) == c_ast.IdentifierType:
                # Base case of the recursion.
                havoc_function = VERIFIER_NONDET_FUNCTION_NAME + self.get_svcomp_type(
                    declaration.type.type.names)
                rvalue = self.create_function_call(havoc_function)
                if parent is None:
                    lvalue = c_ast.ID(declaration.name)
                else:
                    lvalue = parent
                havoc_variable = c_ast.Assignment("=", lvalue, rvalue)
                body_items.append(havoc_variable)
                svcomp_havoc_functions.add(havoc_function)
        # CASE ARRAY
        elif type(declaration.type) == c_ast.ArrayDecl:
            modified_declaration = copy.deepcopy(declaration)
            modified_declaration.type = modified_declaration.type.type
            if type(declaration.type.dim
                    ) == c_ast.Constant and declaration.type.dim.type == "int":
                # Iterates over every member of the array (Thus, the size has to be constant).
                for i in range(int(declaration.type.dim.value)):
                    if parent is None:
                        new_parent = c_ast.ID(declaration.name)
                    else:
                        new_parent = parent
                    rec_svcomp_havoc_funcs, rec_havoc_block = self.create_havoc_assignment(
                        modified_declaration,
                        c_ast.ArrayRef(new_parent,
                                       c_ast.Constant("int", str(i))))
                    body_items.append(rec_havoc_block)
                    svcomp_havoc_functions = svcomp_havoc_functions.union(
                        rec_svcomp_havoc_funcs)
            else:
                sys.stderr.write(
                    "WARNING: Non-constant array encountered!")  # TODO
        # CASE POINTER
        elif type(declaration.type) == c_ast.PtrDecl:
            if type(declaration.type.type) == c_ast.TypeDecl and \
              type(declaration.type.type.type) == c_ast.IdentifierType and \
              ("const" not in declaration.type.quals or "void" in declaration.type.type.type.names):
                # Base case of the recursion. Only entered if we can not dereference the pointer due to either an
                # unknown type (void pointer) or a constant memory location behind the pointer.
                havoc_function = VERIFIER_NONDET_FUNCTION_NAME + "pointer"
                svcomp_havoc_functions.add(havoc_function)
                rvalue = self.create_function_call(havoc_function)
                if parent is None:
                    lvalue = c_ast.ID(declaration.name)
                else:
                    lvalue = parent
                havoc_variable = c_ast.Assignment("=", lvalue, rvalue)
                body_items.append(havoc_variable)
            else:
                # We can dereference the pointer: Does so and creates a havoc statement for the type behind the pointer.
                modified_declaration = copy.deepcopy(declaration)
                modified_declaration.type = modified_declaration.type.type
                if parent is None:
                    new_parent = c_ast.ID(declaration.name)
                else:
                    new_parent = parent
                rec_svcomp_havoc_funcs, rec_havoc_block = self.create_havoc_assignment(
                    modified_declaration, c_ast.UnaryOp("*", new_parent))
                body_items.append(rec_havoc_block)
                svcomp_havoc_functions = svcomp_havoc_functions.union(
                    rec_svcomp_havoc_funcs)
        # Bundles the havoc assignments into one compound statement.
        if len(body_items) == 0:
            sys.stderr.write(
                "WARNING: Could not havoc variable of declaration " +
                GnuCGenerator().visit(declaration) + "\n")
        return svcomp_havoc_functions, c_ast.Compound(body_items)
예제 #11
0
def astFuncIsr():
    aray = c_ast.ArrayRef(c_ast.ID('isr'), c_ast.ID('rand'))
    funcisr = c_ast.FuncCall(aray, None)
    return funcisr
예제 #12
0
def astAssiPri():
    larr = c_ast.ID('pri')  # the second param of Constant is String
    rarr = c_ast.ArrayRef(c_ast.ID('prio'), c_ast.ID('rand'))
    assipri = c_ast.Assignment('=', larr, rarr)
    return assipri
예제 #13
0
def astAssiIsr(i):
    larr = c_ast.ArrayRef(c_ast.ID('isr'), c_ast.Constant(
        'int', str(i)))  # the second param of Constant is String
    rarr = c_ast.UnaryOp('&', c_ast.ID('isr_' + str(i + 1)))
    assi = c_ast.Assignment('=', larr, rarr)
    return assi