Ejemplo n.º 1
0
 def _test_ast_equivalent(self, a: ASTNode, b: ASTNode) -> None:
     assert a.attr_names == b.attr_names
     for name in a.attr_names:
         assert getattr(a, name) == getattr(b, name)
     for (name_a, child_a), (name_b,
                             child_b) in zip(a.children(), b.children()):
         assert name_a == name_b
         self._test_ast_equivalent(child_a, child_b)
Ejemplo n.º 2
0
def AddExplicitCasts(node: c_ast.Node, _parent: c_ast.Node, meta_info, skip_constants):
    def constant_check(node: c_ast.Node):
        return not skip_constants or not isinstance(node, c_ast.Constant)

    for c in node:
        AddExplicitCasts(c, node, meta_info, skip_constants)

    if isinstance(node, c_ast.BinaryOp):
        tl = meta_info.type_links[node.left]
        tr = meta_info.type_links[node.right]
        if not isinstance(tl, c_ast.IdentifierType) or not isinstance(tr, c_ast.IdentifierType):
            return

        cmp = common.TypeCompare(tl, tr)
        if cmp == "<" and constant_check(node.left):
            node.left = MakeCast(tr, node.left)
            meta_info.type_links[node.left] = tr
        elif cmp == ">" and constant_check(node.right):
            node.right = MakeCast(tl, node.right)
            meta_info.type_links[node.right] = tl

    elif (isinstance(node, c_ast.Decl) and
          node.init is not None and
          not isinstance(node.init, c_ast.InitList)):
        left = node.type.type
        right = meta_info.type_links[node.init]
        if not isinstance(left, c_ast.IdentifierType) or not isinstance(right, c_ast.IdentifierType):
            return
        if constant_check(node.init):
            node.init = MakeCast(left, node.init)
            meta_info.type_links[node.init] = left

    elif isinstance(node, c_ast.Assignment):
        left = meta_info.type_links[node.lvalue]
        right = meta_info.type_links[node.rvalue]
        if not isinstance(left, c_ast.IdentifierType) or not isinstance(right, c_ast.IdentifierType):
            return
        if left is not right and constant_check(node.rvalue):
            node.rvalue = MakeCast(left, node.rvalue)
            meta_info.type_links[node.rvalue] = left

    #     if not p: return
    #     right = CanonicalScalarType(ttab[node.rvalue])
    #     if right != p:
    #         node.rvalue = MakeCast(p, node.rvalue)
    #
    # elif isinstance(node, c_ast.FuncCall):
    #     pass
    elif isinstance(node, c_ast.Return):
        if node.expr and constant_check(node.expr):
            src = meta_info.type_links[node.expr]
            dst = meta_info.type_links[node]
            if not isinstance(src, c_ast.IdentifierType) or not isinstance(dst, c_ast.IdentifierType):
                return
            if src is not dst:
                node.expr = MakeCast(dst, node.expr)
                meta_info.type_links[node.expr] = dst
Ejemplo n.º 3
0
    def resolve_typedefs(self, declaration: c_ast.Node, typedefs: set):
        """
		Resolves any typedefs present in the given declaration for the given typedef list. Works in-place on the AST and
		applies itself recursively until no more typedefs are found.
		:param declaration: The declaration in which to resolve typedefs in. Type is one of c_ast.TypeDecl,
			c_ast.PtrDecl or c_ast.ArrayDecl.
		:param typedefs: A set of typedefs to check against.
		:return: A set of the typedefs that was applied, hence a subset of the given typedefs set.
		:rtype: set
		"""
        # Three cases to be distinguished: Type, array or pointer declaration. For arrays, pointers, the type
        # resolving is just applied recursively. For a type declaration, all typedefs are first resolved, and in case we
        # have a aggregate type (struct or union), the resolving is again applied recursively to their members.
        # Keeps track of non-resolved typedefs for recursive application of this function. We do not want already
        # resolved typedefs to be re-applied again.
        applied_typedefs = set()
        if type(declaration) == c_ast.TypeDecl:
            for typedef in typedefs:
                if type(typedef) is c_ast.Typedef:
                    if type(declaration.type) == c_ast.Struct or type(
                            declaration.type) == c_ast.Union:
                        if typedef.name == declaration.type.name:
                            declaration.type = copy.deepcopy(typedef.type.type)
                            declaration.quals = copy.deepcopy(typedef.quals)
                            applied_typedefs.add(typedef)
                    elif type(declaration.type) == c_ast.IdentifierType:
                        if typedef.name in declaration.type.names:
                            applied_typedefs = applied_typedefs.union(
                                self.resolve_typedefs(typedef.type, typedefs))
                            declaration.type = copy.deepcopy(typedef.type.type)
                            declaration.quals = copy.deepcopy(typedef.quals)
                            applied_typedefs.add(typedef)
                elif type(typedef) is c_ast.Struct and type(
                        declaration.type) == c_ast.Struct:
                    if typedef.name == declaration.type.name:
                        declaration.type = copy.deepcopy(typedef)
                        applied_typedefs.add(typedef)
        elif type(declaration) == c_ast.ArrayDecl or type(
                declaration) == c_ast.PtrDecl:
            applied_typedefs = applied_typedefs.union(
                self.resolve_typedefs(declaration.type, typedefs))
        if type(declaration.type) == c_ast.Struct or type(
                declaration.type) == c_ast.Union:
            if declaration.type.decls:
                for member in declaration.type.decls:
                    applied_typedefs = applied_typedefs.union(
                        self.resolve_typedefs(member.type, typedefs))
        return applied_typedefs
Ejemplo n.º 4
0
    def traverse(node: ASTNode, depth: int = 0) -> JSONNode:
        klass = node.__class__

        result = {}

        # Node type
        result[NODE_TYPE_ATTR] = klass.__name__

        # Local node attributes
        for attr in klass.attr_names:
            result[attr] = getattr(node, attr)

        # Token position
        if tokens is not None:
            if node.coord is not None and node.coord.line > 0:  # some nodes have invalid coordinate (0, 1)
                coord: Coord = node.coord
                pos = find_token(coord.line, coord.column)
                result[TOKEN_POS_ATTR] = pos
            else:
                result[TOKEN_POS_ATTR] = None

        # node_name = (" " * (2 * depth) + klass.__name__).ljust(35)
        # if node.coord is not None:
        #     coord: Coord = node.coord
        #     pos = result['coord']
        #     print(node_name, coord.line, coord.column, pos, (tokens[pos] if pos else None), sep='\t')
        # else:
        #     print(node_name)

        # Children nodes
        children: Dict[str, Optional[MaybeList[JSONNode]]] = {}
        for child_name, child in node.children():
            child_dict = traverse(child, depth + 1)
            # Child strings are either simple (e.g. 'value') or arrays (e.g. 'block_items[1]')
            match = RE_CHILD_ARRAY.match(child_name)
            if match:
                array_name, array_index = match.groups()
                array_index = int(array_index)
                # arrays come in order, so we verify and append.
                array: List[JSONNode] = children.setdefault(array_name, [])  # type: ignore
                if array_index != len(array):
                    raise ValueError(f"Internal ast error. Array {array_name} out of order. "
                                     f"Expected index {len(array)}, got {array_index}")
                array.append(child_dict)
            else:
                children[child_name] = child_dict
        # Missing children are filled with `None` values in the dictionary.
        for child_attr in child_attrs_of(klass):
            if child_attr not in children:
                children[child_attr] = None
        result[CHILDREN_ATTR] = children

        return result
Ejemplo n.º 5
0
def replace_while_with_body(codeast: c_ast.Node):
    if type(codeast) == c_ast.Compound:
        new_block_items = copy.deepcopy(codeast.block_items)
        for i in range(0, len(codeast.block_items)):
            if type(codeast.block_items[i]) == c_ast.While:
                # insert list in position i
                while_content = copy.deepcopy(
                    codeast.block_items[i].stmt.block_items)
                del new_block_items[i]
                new_block_items[i:i] = while_content

        codeast.block_items = new_block_items
Ejemplo n.º 6
0
def ForwardGotosAndRemoveUnusedLabels(node: c_ast.Node, forwards: Mapping[str, str]):
    def IsGotoOrLabel(node, _):
        return isinstance(node, (c_ast.Goto, c_ast.Label))

    candidates = common.FindMatchingNodesPostOrder(node, node, IsGotoOrLabel)

    for node, parent in candidates:
        if isinstance(node, c_ast.Goto):
            while node.name in forwards:
                node.name = forwards[node.name]
        elif isinstance(node, c_ast.Label) and node.name in forwards:
            stmts = common.GetStatementList(parent)
            assert stmts, parent
            stmts.remove(node)
Ejemplo n.º 7
0
    def try_handle_block(block: ca.Node, where: Optional[Loc]) -> None:
        if not isinstance(block, ca.Compound) or not block.block_items:
            return
        pragma = block.block_items[0]
        if not isinstance(pragma, ca.Pragma) or pragma.string != wanted_pragma:
            return

        args: List[Statement] = block.block_items[1:]
        stmts = perm.eval_statement_ast(args, seed)

        if where:
            where[0][where[1]:where[1] + 1] = stmts
        else:
            block.block_items = stmts
        raise _Done
Ejemplo n.º 8
0
 def dfs(u: c_ast.Node):
     nonlocal node_parent
     for (v_name, v) in u.children():
         node_parent[v] = u
         dfs(v)
Ejemplo n.º 9
0
    "visit_dict",
    "JSONNode",
    "NODE_TYPE_ATTR",
    "CHILDREN_ATTR",
    "TOKEN_POS_ATTR",
]

T = TypeVar('T')
K = TypeVar('K')
MaybeList = Union[T, List[T]]
JSONNode = Dict[str, Any]

RE_CHILD_ARRAY = re.compile(r'(.*)\[(.*)\]')
RE_INTERNAL_ATTR = re.compile('__.*__')

AVAILABLE_NODES: Dict[str, Type[ASTNode]] = {klass.__name__: klass for klass in ASTNode.__subclasses__()}
NODE_TYPE_ATTR = "_t"
CHILDREN_ATTR = "_c"
TOKEN_POS_ATTR = "_p"


@functools.lru_cache()
def child_attrs_of(klass: Type[ASTNode]):
    r"""Given a Node class, get a set of child attrs.
    Memoized to avoid highly repetitive string manipulation
    """
    non_child_attrs = set(klass.attr_names)
    all_attrs = set([i for i in klass.__slots__ if not RE_INTERNAL_ATTR.match(i)])
    all_attrs -= {"coord"}
    return all_attrs - non_child_attrs
Ejemplo n.º 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)
Ejemplo n.º 11
0
def CanonicalizeBaseTypes(node: c_ast.Node):
    if isinstance(node, c_ast.IdentifierType):
        node.names = common.CanonicalizeIdentifierType(node.names)
    for c in node:
        CanonicalizeBaseTypes(c)
Ejemplo n.º 12
0
def RemoveVoidParam(node: c_ast.Node):
    if isinstance(node, c_ast.ParamList) and len(node.params) == 1:
        if IsVoidArg(node.params[0]):
            node.params = []
    for c in node:
        RemoveVoidParam(c)