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
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)
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
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)
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))
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))
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))
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))
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)
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)
def astFuncIsr(): aray = c_ast.ArrayRef(c_ast.ID('isr'), c_ast.ID('rand')) funcisr = c_ast.FuncCall(aray, None) return funcisr
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
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