Example #1
0
    def generalize(self) -> Dict[str, Any]:
        """
        Generalize arguments seen. For each function argument,
        produce an abstract failure-inducing input that characterizes
        the set of inputs for which the function fails.
        """
        if self.generalized_args:
            return self.generalized_args

        self.generalized_args = copy.deepcopy(self.args())
        self.generalized_trees = {}
        self.generalizers = {}

        for arg in self.args():

            def test(value: Any) -> Any:
                return self.call({arg: value})

            value = self.args()[arg]
            if isinstance(value, str):
                tree = list(self.parser.parse(value))[0]
                gen = self.generalizer_class(self.grammar, tree, test,
                                             **self.kwargs)
                generalized_tree = gen.generalize()

                self.generalizers[arg] = gen
                self.generalized_trees[arg] = generalized_tree
                self.generalized_args[arg] = all_terminals(generalized_tree)

        return self.generalized_args
Example #2
0
    def reduce_subtree(self, tree, subtree, depth=-1):
        if os.path.exists("./tmp"):
            subprocess.call(["rm", "-r", "tmp"])
        subprocess.call(["mkdir", "tmp"])
        self.devnull = open(os.devnull, 'w')

        symbol, children = subtree
        if len(children) == 0:
            return False

        if self.log_reduce == True:
            print("Reducing", all_terminals(subtree), "with depth", depth)

        reduced = False
        while True:
            reduced_child = False
            for i, child in enumerate(children):
                (child_symbol, _) = child
                for reduction in self.symbol_reductions(
                        child, child_symbol, depth):
                    if self.number_of_nodes(reduction) >= self.number_of_nodes(
                            child):
                        continue

                    if self.log_reduce == True:
                        print("Replacing", all_terminals(children[i]), "by",
                              all_terminals(reduction))
                    children[i] = reduction

                    if self.log_test == True:
                        print("Test" + str(self.tests) + " " +
                              all_terminals(tree))

                    output = open("./tmp/output" + str(self.tests), "wb")
                    output.write(all_terminals(tree).encode())
                    output.close()

                    if self.execution(all_terminals(tree)) == False:
                        if self.log_reduce == True:
                            print("New tree:", all_terminals(tree))
                        reduced = reduced_child = True
                        break
                    else:
                        children[i] = child

            if not reduced_child:
                if self.log_reduce == True:
                    print("Tried all alternatives for", all_terminals(subtree))
                break

        for c in children:
            if self.reduce_subtree(tree, c, depth):
                reduced = True

        return reduced
    def choose_node_expansion(self, node, possible_children):
        (symbol, children) = node
        new_coverages = self.new_coverages(node, possible_children)

        if new_coverages is None:
            # In a loop, look for empty
            if ((hasattr(self, 'derivation_tree') and
                 len(all_terminals(self.derivation_tree)) > len(self.grammar))
                    or (len(self.covered_expansions) >= len(self.grammar))
                ) and "<empty>" in str(possible_children):
                return self.get_empty(possible_children)
            else:
                # All expansions covered - use superclass method
                return self.choose_covered_node_expansion(
                    node, possible_children)

        if node == self.last_symbol:
            if self.last_symbol_count < 3:
                self.last_symbol_count += 1
            elif "<empty>" in str(possible_children):
                return self.get_empty(possible_children)
        else:
            self.last_symbol = node
            self.last_symbol_count = 0

        max_new_coverage = max(len(cov) for cov in new_coverages)

        children_with_max_new_coverage = [
            c for (i, c) in enumerate(possible_children)
            if len(new_coverages[i]) == max_new_coverage
        ]
        index_map = [
            i for (i, c) in enumerate(possible_children)
            if len(new_coverages[i]) == max_new_coverage
        ]

        # Select a random expansion
        new_children_index = self.choose_uncovered_node_expansion(
            node, children_with_max_new_coverage)
        new_children = children_with_max_new_coverage[new_children_index]

        # Save the expansion as covered
        key = expansion_key(symbol, new_children)

        if self.log:
            print("Now covered:", key)
        self.covered_expansions.add(key)

        return index_map[new_children_index]
Example #4
0
    def fuzz_args(self) -> Dict[str, Any]:
        """
        Return arguments randomly instantiated
        from the abstract failure-inducing pattern.
        """
        if not self.generalized_trees:
            self.generalize()

        args = copy.deepcopy(self.generalized_args)
        for arg in args:
            if arg not in self.generalized_trees:
                continue

            tree = self.generalized_trees[arg]
            gen = self.generalizers[arg]
            instantiated_tree = gen.fuzz_tree(tree)
            args[arg] = all_terminals(instantiated_tree)

        return args
def expansion_key(symbol, expansion):
    """Convert (symbol, children) into a key. `children` can be an expansion string or a derivation tree."""
    if isinstance(expansion, tuple):
        expansion = expansion[0]
    if not isinstance(expansion, str):
        children = expansion
        expansion = all_terminals((symbol, children))

    terminals = list(
        filter(lambda x: "<" not in x,
               filter(lambda x: x != "", re.split(RE_NONTERMINAL, expansion))))

    if len(terminals) > 1:
        raise Exception("Found terminal " + str(terminals) + " in " +
                        expansion + " from symbol " + symbol)
    elif len(terminals) > 0:
        exp = terminals[0]
    else:
        exp = ''

    return exp
Example #6
0
 def reduce(self, inp):
     tree = self.parse(inp)
     self.reduce_tree(tree)
     return all_terminals(tree)
Example #7
0
 def parse(self, inp):
     tree, *_ = self.parser.parse(inp)
     if self.log_reduce == True:
         print(all_terminals(tree))
     return tree
Example #8
0
        symbol, children = tree

        if not path or children is None:
            return symbol, None  # Nonterminal without children

        head = path[0]
        new_children = (children[:head] +
                        [self.generalize_path(path[1:], children[head])] +
                        children[head + 1:])
        return symbol, new_children


if __name__ == '__main__':
    all_terminals(
        cast(TreeGeneralizer,
             bad_input_tree_generalizer()).generalize_path([0, 0, 0]))


class TreeGeneralizer(TreeGeneralizer):
    def generalize(self) -> DerivationTree:
        """Returns a copy of the tree in which all generalizable subtrees
        are generalized (= replaced by nonterminals without children)"""
        tree = self.tree
        assert tree is not None

        for path in self.generalizable_paths():
            tree = self.generalize_path(path, tree)

        return tree