예제 #1
0
def test_const_ptr_func_arg():
    src = """
    const int *bar;
    void foo(const int *bar, int * const baz);
    """

    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    src_str = GnuCGenerator().visit(ast)

    assert src_str.count("*") == 3
    print(src_str)
예제 #2
0
def test_const_ptr_func_arg():
    src = """
    const int *bar;
    void foo(const int *bar, int * const baz);
    """

    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    src_str = GnuCGenerator().visit(ast)

    assert src_str.count("*") == 3
    print(src_str)
예제 #3
0
def test_funky_header_code_5():
    src = """ void  do_foo(void) __asm(__STRING(do_foo));"""

    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #4
0
def test_array_ptr_decl_attribute():
    src = """
    int* __attribute__((weak)) array[256];
    """
    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #5
0
def test_func_ret_ptr_decl_attribute():
    src = """
    extern void* memcpy(const void* src, const void *dst, int len) __attribute__((unused));
    """
    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #6
0
def static_slicing_from_ast(ast: c_ast):
    """
	Executes static slicing on the given AST.
	:param ast: A PyCParser AST.
	:return: A PyCParser AST on which static slicing has been applied.
	:rtype: c_ast
	"""
    ast_file = tempfile.NamedTemporaryFile(delete=False, suffix=".c")
    ast_file.write(bytes(GnuCGenerator().visit(ast), "utf-8"))
    sliced_file = static_slicing_from_file(ast_file.name)
    with open(sliced_file, "r") as slice:
        return GnuCParser().parse(slice.read())
예제 #7
0
def test_array_attributes():
    src = """
        int x[10] __attribute__((unused));
        int y[20] __attribute((aligned(10)));
        """

    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #8
0
def test_empty_struct_declaration():
    src = """
        typedef struct Foo {
        } Foo_t;
    """

    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #9
0
def test_asm_volatile_3():
    src = """
    void read_tsc(void) {
        long fpenv;
        asm("mtfsf 255,%0" :: "f" (fpenv));
    }    """
    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #10
0
def test_asm_volatile_1():
    src = """
    void read_tsc(void) {
        long val;
        asm("rdtsc" : "=A" (val));
    }    """
    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #11
0
def test_func_decl_attribute():
    src = """
    extern void int happy(void) __attribute__((unused));
    int main()
    {
    }
    """

    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #12
0
def test_lvalue_gnu_statement_expression():
    src = """
      int func(int a) {
        int ret=(int)({; ; *(int*)&a;});
        return ret;
     }
    """

    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #13
0
def test_funky_header_code():
    src = """
        extern __inline int __attribute__ ((__nothrow__)) __signbitf (float __x)
         {
           int __m;
           __asm ("pmovmskb %1, %0" : "=r" (__m) : "x" (__x));
           return __m & 0x8;
         }
        """

    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #14
0
def test_empty_gnu_statement_expression():
    # Incase, ASSERTS turn out to be empty statements
    src = """
      int func(int a) {
              ({
                    ; ;
                         });
                }
    """

    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(src)
    ast.show()

    from pycparserext.ext_c_generator import GnuCGenerator
    print(GnuCGenerator().visit(ast))
예제 #15
0
def insert_k_into_induction_file(file_induction: str, k: int):
    """
	Inserts the current unwind number into the file such that the property is only checked once the iteration number
	has reached k.
	:param file_induction: The file the verifier run on in the previous iteration.
	:param k: The new k.
	:return: A filename whose content is the C-code for the updated iteration number k.
	"""
    if k > 1:
        # Parses the file (again) and identifies the main function (again). Not super elegant, could surely be improved.
        with open(file_induction) as file:
            ast = GnuCParser().parse(file.read())
        main_function = CAnalyzer(ast).identify_function(MAIN_FUNCTION_NAME)
        CTransformer(ast).replace_initial_value(
            "const unsigned int k = " + str(k - 1) + ";", main_function, k)
        output_file = tempfile.NamedTemporaryFile(delete=False, suffix=".c")
        output_file.write(bytes(GnuCGenerator().visit(ast), "utf-8"))
        return output_file.name
    else:
        return file_induction
예제 #16
0
def static_slicing_from_file(input_file: str,
                             output: str = None,
                             slice_funcs: list = None):
    """
	Executes static slicing from a given file name. Writes to the output file if given, otherwise creates a	temporary
	file and writes the results to it.
	:param input_file: The location of the input file.
	:param output: An optional file location.
	:param slice_funcs: The functions to slice for their reachability. If None, the default is __VERIFIER_error.
	:return: The file name of the output file.
	:rtype: str
	"""
    # Need a temporary file because Frama-C does not allow to only print out the C code.
    slice_file = tempfile.NamedTemporaryFile(delete=False, suffix=".c")
    if not slice_funcs or len(slice_funcs) == 0:
        slice_funcs = ["__VERIFIER_error"]
    with open(input_file, "r") as input:
        # Only keep assume statements if there are any, otherwise Frama-C complains.
        if "__VERIFIER_assume" in input.read().replace(
                "extern int __VERIFIER_assume(int);", ""):
            slice_funcs.append("__VERIFIER_assume")
    # /dev/null supresses output of Frama-C.
    with open(os.devnull, "w") as devnull:
        subprocess.call([
            "frama-c", "-slice-calls", ",".join(slice_funcs), input_file,
            "-then-on", "Slicing export", "-print", "-ocode", slice_file.name
        ],
                        stdout=devnull)
    slice = slice_file.read().decode("utf-8")
    # Removes comments of the form /**/ as GnuCParser does not seem to like them.
    slice = re.sub("/\*.*?\*/", "", slice)
    # Parses the slice and original to allow for the process of moving switch-local variables out of switch blocks.
    slice_ast = GnuCParser().parse(slice)
    # By moving switch-local variables outside of the switch-statement, we prevent a bug in CBMC v5.11 and earlier.
    move_switch_local_variables(slice_ast)
    # Output printing.
    if not output:
        output_file = tempfile.NamedTemporaryFile(delete=False, suffix=".c")
        output = open(output_file.name, "w")
    output.write(GnuCGenerator().visit(slice_ast))
    return output.name
예제 #17
0
def variable_analysis_from_file(input_file: str,
                                output: str = None,
                                ignore_functions=None):
    """
	Executes the variable analysis from a given file name. Writes to the output file if given, otherwise creates a
	temporary file and writes the results to it.
	:param input_file: The location of the input file.
	:param output: An optional file location.
	:param ignore_functions: A set of functions whose contents are ignored when determining the usage of variables. If
		None, all functions are taken into account.
	:return: The file name of the output file.
	:rtype: str
	"""
    with open(input_file) as input:
        ast = GnuCParser().parse(input.read())
        changed_ast = variable_analysis_from_ast(ast, ignore_functions)
        if not output:
            output_file = tempfile.NamedTemporaryFile(delete=False,
                                                      suffix=".c")
            output = open(output_file.name, "w")
        output.write(GnuCGenerator().visit(changed_ast))
        return output.name
예제 #18
0
def variable_analysis_from_ast(ast: c_ast, ignore_functions=None):
    """
	Executes the variable analysis on the given AST.
	:param ast: A PyCParser AST.
	:param ignore_functions: A set of functions whose contents are ignored when determining the usage of variables. If
		None, all functions are taken into account.
	:return: A PyCParser AST on which the analysis has been applied.
	:rtype: c_ast
	"""
    # Writes AST content to file, in order to run ctags on it.
    ast_file = tempfile.NamedTemporaryFile(delete=False, suffix=".c")
    ast_file.write(bytes(GnuCGenerator().visit(ast), "utf-8"))
    # Runs ctags to extract global variables from the given AST.
    vars = os.popen(
        "ctags -x --c-kinds=v --file-scope=no " + ast_file.name +
        " | grep -v volatile | awk '{print $1;}'").read().splitlines()

    # For each global variable, finds every function that accesses it.
    var_to_funcs = {}
    for var in vars:
        var_to_funcs[var] = get_usages_for_variable(ast, var)
    var_and_funcs_to_be_moved = determine_variables_to_be_moved(
        var_to_funcs, ignore_functions)
    vars_to_be_removed = determine_variables_to_be_removed(
        var_to_funcs, ignore_functions)

    if len(vars_to_be_removed) > 0:
        ast = remove_variables(ast, vars_to_be_removed)
        print("Removed " + str(len(vars_to_be_removed)) +
              " global variables (" +
              "{:.1%}".format((len(vars_to_be_removed) / len(vars))) +
              ") and their retrospectively added statements.")
    if len(var_and_funcs_to_be_moved) > 0:
        ast = move_variables_to_func(ast, var_and_funcs_to_be_moved)
        print("Moved " + str(len(var_and_funcs_to_be_moved)) +
              " global variables (" +
              "{:.1%}".format((len(var_and_funcs_to_be_moved) / len(vars))) +
              ") to their local function scope.")
    return ast
예제 #19
0
def _round_trip_matches(src):
    from pycparserext.ext_c_parser import GnuCParser
    from pycparserext.ext_c_generator import GnuCGenerator

    p = GnuCParser()

    first_ast = p.parse(src)

    gen = GnuCGenerator().visit(first_ast)

    second_ast = p.parse(gen)

    if not _compare_asts(first_ast, second_ast):
        print('First AST:')
        first_ast.show()

        print('Generated code:')
        print(gen)

        print('Second AST:')
        second_ast.show()

        return False
    return True
예제 #20
0
def generate_cdef():
    """Generate the cdef output file"""
    include_v4l2_path = '/usr/include/linux'
    #include_v4l2_path='.'
    #out_file = path.join(HERE, 'v4l2', 'videodev2.cdef.h')
    #out_packed_file = path.join(HERE, 'v4l2', 'videodev2.cdef_packed.h')
    #header = path.join(include_v4l2_path, 'videodev2.h')
    #header_parsed = path.join(HERE, 'v4l2', 'videodev2.h')
    #enum_file = path.join(HERE, 'v4l2', 'v4l2_enums.py')
    out_file = os.path.join(HERE, BUILDDIR, 'videodev2.cdef.h')
    out_packed_file = os.path.join(HERE, BUILDDIR, 'videodev2.cdef_packed.h')
    header = os.path.join(include_v4l2_path, 'videodev2.h')
    header_parsed = os.path.join(HERE, BUILDDIR, 'videodev2.h')
    enum_file = os.path.join(HERE, 'v4l2enums.py')

    out = open(header_parsed, 'w+')
    cpp_process = subprocess.Popen(
        [
            'cpp',
            '-P',
            #'-nostdinc',
            '-I',
            'fake-include',
            header
        ],
        stdout=out)
    cpp_process.wait()
    out.close()

    headerin = open(header_parsed, 'r')
    headersrc = headerin.read()
    from pycparserext.ext_c_parser import GnuCParser
    p = GnuCParser()
    ast = p.parse(headersrc, filename=header_parsed)
    # ast.show()
    headerin.close()
    out = open(out_file, 'w+')
    out_packed = open(out_packed_file, 'w+')
    enums = open(enum_file, 'w+')
    enums.write('import enum\nimport v4l2\n')
    from pycparserext.ext_c_generator import GnuCGenerator
    g = GnuCGenerator()
    i = 0
    for nname, astnode in ast.children():
        outthis = out
        if type(astnode) == pycparser.c_ast.Decl:
            #print('node', i)
            #print(g.visit(astnode)+'\n')
            for spec in astnode.funcspec:
                if type(spec) == pycparserext.ext_c_parser.AttributeSpecifier:
                    for att in spec.exprlist.exprs:
                        if att.name == 'packed':
                            outthis = out_packed
            if type(astnode.type) == pycparser.c_ast.Enum:
                enumnode = astnode.type
                enums.write('class ' + enumnode.name + '(enum.IntEnum):\n')
                for el in enumnode.values.enumerators:
                    enums.write('    ' + el.name + ' = v4l2.' + el.name + '\n')
                enums.write('\n')
            if type(astnode.type) != pycparserext.ext_c_parser.FuncDeclExt:
                #print(i, type(astnode.type))
                outthis.write(g.generic_visit(astnode) + ';\n')
            else:
                # for parsing ioctl(...) decalaration
                outthis.write(g.visit(astnode) + ';\n')
        else:
            outthis.write(g.visit(astnode) + ';\n')
        #print('node', i)
        #print(g.generic_visit(astnode)+'\n')
        i += 1
    out.flush()
    out.close()
    out_packed.flush()
    out_packed.close()
    enums.flush()
    enums.close()

    print('generate_cdef: generated\n      ', out_file, ',\n      ',
          out_packed_file, '\n  and', enum_file, 'from', header)
    return out_file, out_packed_file
예제 #21
0
def write_file(out_dir, header_include, node, errno, retval):
    header = """
#define _GNU_SOURCE
#include <dlfcn.h>
#include <stdio.h>
#include <errno.h>
#include <stddef.h>
#include <stdlib.h>
#include <%s>
"""

    code_template = """
static %s %s(*%s) (%s) = NULL;
%s {
  char* var = getenv("PROB");
  float p = atof(var);
  int flip = rand_bool((double) p);
  %s = dlsym(RTLD_NEXT, "%s");
  if(flip || (%s == NULL)) {
    %s
    return %s;
  } else {
    %s
  }
}
"""

    gen = GnuCGenerator()

    new_fn = node.name
    real_fn = "real_" + new_fn

    arglist = gen.visit(node.type.args)

    is_ptr_result = isinstance(node.type.type, c_ast.PtrDecl)
    is_void_result = gen.visit(node.type.type) == "void" and not is_ptr_result

    # eliminate __extension__ and stuff like it from the function signature
    func_sig = "%s %s %s%s(%s)" % (' '.join(
        node.storage), gen.visit(
            node.type.type), '*' if is_ptr_result else '', new_fn, arglist)

    new_file = out_dir + '%s_wrapper.c' % new_fn
    with open(new_file, 'w') as f:
        f.write(header % header_include)
        f.write(code_template % (
            gen.visit(node.type.type),  # int
            '*' if isinstance(node.type.type, c_ast.PtrDecl) else '',
            real_fn,  # real_open
            gen.visit(node.type.args),  # (args with types)
            func_sig,
            real_fn,  # real_open
            new_fn,
            real_fn,  # real_open
            ("errno = %s;" % errno) if errno is not None else "",
            retval,
            "%s%s(%s);" % (  # return
                "return " if not is_void_result else "",
                real_fn,  # real_open
                ', '.join([
                    a.name if a.name is not None else ''
                    for a in node.type.args.params
                    if not isinstance(a, c_ast.EllipsisParam)
                ]),
            )))
    print 'wrote %s' % new_file
예제 #22
0
 def __str__(self):
     message = "Input program contains multiple (" + str(len(self.loops)) + ") main loops in function " \
         + self.main_function_name + ", namely:\n"
     for i, loop in enumerate(self.loops):
         message += str(i) + ")\n" + GnuCGenerator().visit(loop) + "\n"
     return message
예제 #23
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)
예제 #24
0
def programPrint(statement):
    generator = GnuCGenerator()
    return str(generator.visit(statement))
예제 #25
0
파일: __init__.py 프로젝트: inducer/cnd
 def __init__(self):
     GnuCGeneratorBase.__init__(self)
     CndGeneratorMixin.__init__(self)
예제 #26
0
def prepare_induction_step(input_file: str,
                           original_input_file: str = None,
                           readd_property_from_original: bool = False):
    """
	Prepares the input C file for the execution of the induction step. It parses the code, havocs the main loop
	variables and adds the property assumption to the beginning of the loop body. When finished, the C code is written
	to a temporary working file which is then returned.
	:param input_file: The input C file location to prepare.
	:param original_input_file: The input C file location of the original input code.
	:param readd_property_from_original: Whether the original input file should be read and the property readded from
		this file to the input file.
	:return: The location of the prepared C file for the induction step.
	:rtype: str
	"""
    parser = GnuCParser()
    with open(input_file) as file:
        ast = parser.parse(file.read())
    analyzer = CAnalyzer(ast)
    transformer = CTransformer(ast)
    # De-anonymizes aggregates as a first step, as this is a requirement for later analysis.
    # transformer.deanonymize_aggregates()
    # Identifies main components of the code.
    try:
        main_function = analyzer.identify_function(MAIN_FUNCTION_NAME)
        main_loop = analyzer.identify_main_loop()
        declarations = analyzer.identify_declarations_of_modified_variables(
            main_loop.stmt, main_function)
        if readd_property_from_original and original_input_file and input_file != original_input_file:
            with open(original_input_file) as original_file:
                # In case we sliced the input, we want to re-add the original property first, as Frama-C scrambles the
                # if statement in such a way that it becomes unrecognizable for our property identification process.
                transformer.add_property(
                    CAnalyzer(parser.parse(
                        original_file.read())).identify_property(), main_loop)
        property = analyzer.identify_property()
    except (NoMainLoopException, MultipleMainLoopsException,
            UnidentifiableVariableTypeException) as err:
        print(err)
        sys.exit(1)
    # Creates new code and functions to be added.
    try:
        svcomp_havoc_functions, havoc_block = transformer.create_havoc_block(
            declarations)
    except NonSvCompTypeException as err:
        print(err)
        sys.exit(1)
    for svcomp_havoc_function in svcomp_havoc_functions:
        transformer.insert(transformer.create_svcomp_function_declaration(
            svcomp_havoc_function),
                           before=ast.ext[0])
    conjunct_property = transformer.join_expression_list("&&", property)
    negated_property = transformer.add_to_expression(conjunct_property, "!")
    assume_property = transformer.create_function_call(
        VERIFIER_ASSUME_FUNCTION_NAME, negated_property)
    # Adds some code to emulate incremental BMC: Only check property if we are in the k-th main loop iteration.
    if not VERIFIER_IS_INCREMENTAL:
        k_initialization = transformer.from_code("const unsigned int k = 1;",
                                                 parser).block_items[0]
        i_initialization = transformer.from_code("unsigned int i = 0;",
                                                 parser).block_items[0]
        i_increment = transformer.from_code("i++;", parser).block_items[0]
        k_property = transformer.add_to_expression(
            property.exprs[0], "&&",
            c_ast.ExprList(transformer.from_code("(i == k)").block_items))
        transformer.replace_property(k_property)
        transformer.insert(k_initialization, before=main_loop)
        transformer.insert(i_initialization, before=main_loop)
        transformer.insert(i_increment, before=main_loop.stmt.block_items[0])
    # Inserts new code pieces.
    transformer.insert(havoc_block, before=main_loop)
    transformer.insert(assume_property, before=main_loop.stmt.block_items[0])
    # Writes the transformed code to a temporary file.
    output_file = tempfile.NamedTemporaryFile(delete=False, suffix=".c")
    output_file.write(bytes(GnuCGenerator().visit(ast), "utf-8"))
    return output_file.name
예제 #27
0
 def __init__(self):
     GnuCGeneratorBase.__init__(self)
     CndGeneratorMixin.__init__(self)