def make_klee_symbolic(variable_name, trackingName): arg1 = c_ast.UnaryOp(op='&', expr=c_ast.ID(variable_name)) arg2 = c_ast.UnaryOp(op='sizeof', expr = c_ast.Typename(name=None, quals =[], type= c_ast.TypeDecl(declname=None,quals=[], type=c_ast.IdentifierType(names=['int'])))) arg3 = c_ast.Constant(type='string', value='\"'+ trackingName +'\"') return c_ast.FuncCall(name=c_ast.ID(name = "klee_make_symbolic"), args=c_ast.ExprList(exprs=[arg1,arg2,arg3]))
def add_to_expression(self, expression: c_ast.Node, operator: str, addition: c_ast.ExprList = None): """ Adds the additional expression to the given expression, concatenated with the given operator. If the additional expression is None, the operator is assumed to be unary. :param expression: The expression to add to. :param operator: An operator on expression, e.g. "&&" or "!". :param addition: The expression to add. :return: The merged expression. :rtype: c_ast.ExprList """ expressions = [] if type(expression) is c_ast.ExprList: for expr in expression.exprs: if addition is None: expressions.append( c_ast.UnaryOp(operator, copy.deepcopy(expr))) else: expressions.append( c_ast.BinaryOp(operator, copy.deepcopy(expr), addition)) else: if addition is None: expressions.append( c_ast.UnaryOp(operator, copy.deepcopy(expression))) else: expressions.append( c_ast.BinaryOp(operator, copy.deepcopy(expression), addition)) return c_ast.ExprList(expressions)
def perm_refer_to_var(fn: ca.FuncDef, ast: ca.FileAST, indices: Indices, region: Region, random: Random) -> bool: """Add `if (variable) {}` or `if (struct.member) {}` in a random place. This will get optimized away but may affect regalloc.""" # Find expression to insert, searching within the randomization region. cands: List[Expression] = [ expr for expr in get_block_expressions(fn.body, region) if isinstance(expr, (ca.StructRef, ca.ID)) ] if not cands: return False expr = random.choice(cands) if ast_util.is_effectful(expr): return False type: SimpleType = decayed_expr_type(expr, build_typemap(ast)) if isinstance(type, ca.TypeDecl) and isinstance(type.type, (ca.Struct, ca.Union)): expr = ca.UnaryOp("&", expr) if random.choice([True, False]): expr = ca.UnaryOp("!", expr) # Insert it wherever -- possibly outside the randomization region, since regalloc # can act at a distance. (Except before a declaration.) ins_cands = get_insertion_points(fn, Region.unbounded()) ins_cands = [c for c in ins_cands if not isinstance(c[2], ca.Decl)] if not ins_cands: return False cond = copy.deepcopy(expr) stmt = ca.If(cond=cond, iftrue=ca.Compound(block_items=[]), iffalse=None) tob, toi, _ = random.choice(ins_cands) ast_util.insert_statement(tob, toi, stmt) return True
def rename_array_args(funcdef): """ Rename and copy arrays passed as arguments to funcdef. """ # For each argument for param in funcdef.decl.type.args.params: if isinstance(param.type, c_ast.ArrayDecl): # Rename and copy array arg_decl = copy.deepcopy(param) # Rename array v = inline.RenameVisitor() v.new_visit(get_decl_name(param), get_decl_name(param) + "_rename", funcdef.body) # Add copy and declarations funcdef.body.block_items = rename_array_decl( arg_decl) + funcdef.body.block_items elif isinstance(param.type, c_ast.TypeDecl): # Simple variable passing, don't need to handle pass elif isinstance(param.type, c_ast.PtrDecl): # Don't copy pointer arguments return """ Param of form: type *var is copied in the function body using: type var_rename _temp = *var; type *var_rename = &var_rename_temp; """ # General pointer arguments old_name = get_decl_name(param) new_name = old_name + "_rename" temp_name = new_name + "_temp" # Rename variable use in function body v = inline.RenameVisitor() v.new_visit(old_name, new_name, funcdef.body) # type var_rename_temp = *var; decl1 = c_ast.Decl( temp_name, None, None, None, c_ast.TypeDecl(temp_name, None, param.type.type.type), c_ast.UnaryOp('*', c_ast.ID(old_name)), None) # type *var_rename = &var_rename_temp; decl2 = c_ast.Decl( new_name, None, None, None, c_ast.PtrDecl([], c_ast.TypeDecl(new_name, None, param.type.type.type)), c_ast.UnaryOp('&', c_ast.ID(temp_name)), None) # Insert into function body funcdef.body.block_items.insert(0, decl2) funcdef.body.block_items.insert(0, decl1) else: print_node(param) param.show(nodenames=True, showcoord=True) raise Exception( "Unhandled argument type %s. Implement or verify that it can be ignored." % (type(param.type)))
def _generate_write(name, address=True): """ Helper function generate write functions """ if address: target = c_ast.UnaryOp('&', c_ast.ID(name)) else: target = c_ast.ID(name) return c_ast.FuncCall( c_ast.ID('_rpc_write'), c_ast.ExprList([target, c_ast.UnaryOp('sizeof', c_ast.ID(name))]))
def _generate_read(name, size=None, address=True): """ Helper function to generate read functions. size should be an AST fragment """ if size is None: size = c_ast.UnaryOp('sizeof', c_ast.ID(name)) if address: target = c_ast.UnaryOp('&', c_ast.ID(name)) else: target = c_ast.ID(name) return c_ast.FuncCall(c_ast.ID('_rpc_read'), c_ast.ExprList([target, size]))
def nested_for_loop(node, inner_loop_body, loop_iterator_base, rename_index=0): """ Recursively create nested for loops for copying a multi-dimensional array. """ if isinstance(node.type.type, c_ast.ArrayDecl): # Multi-dimensional array, recurse to generate inner loop for_loop_body = nested_for_loop(node.type, inner_loop_body, loop_iterator_base, rename_index + 1) else: # Single or last dimension of array for_loop_body = [inner_loop_body] # Declare iterator loop_iterator = c_ast.ID("%s_i%d" % (loop_iterator_base, rename_index)) loop_iterator_decl = c_ast.Decl( loop_iterator.name, [], [], [], c_ast.TypeDecl(loop_iterator.name, [], c_ast.IdentifierType(["int"])), None, None) # For loop array_size = node.type.dim for_loop = c_ast.For( c_ast.Assignment('=', loop_iterator, c_ast.Constant("int", "0")), c_ast.BinaryOp('<', loop_iterator, array_size), c_ast.UnaryOp('p++', loop_iterator), c_ast.Compound(for_loop_body)) return [loop_iterator_decl, for_loop]
def replacer(e: Expression) -> Optional[Expression]: if e in replace_cand_set: if should_make_ptr: return ca.UnaryOp("*", ca.ID(var)) else: return ca.ID(var) return None
def check_value(ast_tree, ext_index, bock_item_index, var_name, func_name): Cast = c_ast.Cast( c_ast.Typename( None, [], c_ast.PtrDecl([], c_ast.TypeDecl(None, [], c_ast.IdentifierType(['void'])))), c_ast.ID(var_name)) func_call = c_ast.FuncCall( c_ast.ID('check_value'), c_ast.ExprList([ c_ast.UnaryOp('&', c_ast.ID('global_log')), Cast, c_ast.Constant('string', '"' + var_name + '"'), c_ast.Constant('string', '"' + func_name + '"'), c_ast.Constant('int', str(len(var_name))), c_ast.Constant('int', str(len(func_name))) ])) new_node = c_ast.If( c_ast.BinaryOp('==', func_call, c_ast.Constant('int', '0')), c_ast.Compound([ c_ast.FuncCall( c_ast.ID('printf'), c_ast.ExprList([ c_ast.Constant('string', '"%s\\n"'), c_ast.Constant('string', '"Attack Detected"') ])), c_ast.FuncCall(c_ast.ID('exit'), c_ast.ExprList([c_ast.Constant('int', '1')])) ]), None) return merge_ast_tree(ast_tree, ext_index, bock_item_index, new_node, "insert_before")
def ConvertArrayIndexToPointerDereference(ast, meta_info): """ Eliminates multi-dimensional arrays Phase 1: a[1][2] = b; -> *(a + 1 * 10 + 2) = b; Phase 2: fun (int a[5][10]) -> fun (int a[][10]) Phase 3: int a[5][10]; -> int a[50]; """ def IsArrayRefChainHead(node, parent): if not isinstance(node, c_ast.ArrayRef): return False name_type = meta_info.type_links[node.name] # int **b = a; # printf("%d\n", b[1][1]); if not isinstance(name_type, c_ast.ArrayDecl): return True if not isinstance(parent, c_ast.ArrayRef): return True return False ref_chains = common.FindMatchingNodesPostOrder(ast, ast, IsArrayRefChainHead) for chain_head, parent in ref_chains: name, s = MakeCombinedSubscript(chain_head, meta_info) if s is None: addr = name else: addr = c_ast.BinaryOp("+", name, s) head_type = meta_info.type_links[chain_head] # TODO: low confidence - double check this meta_info.type_links[addr] = meta_info.type_links[name] if isinstance(head_type, c_ast.ArrayDecl): # the array ref sequence only partially indexes the array, so the result is just an address common.ReplaceNode(parent, chain_head, addr) else: deref = c_ast.UnaryOp("*", addr) meta_info.type_links[deref] = meta_info.type_links[chain_head] # expression has not changed common.ReplaceNode(parent, chain_head, deref) # Phase 2 def IsArrayDeclParam(node, parent): if not isinstance(parent, c_ast.ParamList): return False if isinstance(node, c_ast.EllipsisParam): return False return isinstance(node.type, c_ast.ArrayDecl) decl_params = common.FindMatchingNodesPreOrder( ast, ast, IsArrayDeclParam) for param, _ in decl_params: t = param.type t.dim = None # Phase 3 def IsArrayDeclChainHead(node, parent): if not isinstance(node, c_ast.ArrayDecl): return False return not isinstance(parent, c_ast.ArrayDecl) decl_chains = common.FindMatchingNodesPreOrder( ast, ast, IsArrayDeclChainHead) for chain_head, parent in decl_chains: CollapseArrayDeclChain(chain_head)
def ConvertArrayStructRef(ast: c_ast.FileAST): def IsArrowStructRef(node, _): return isinstance(node, c_ast.StructRef) and node.type == "->" candidates = common.FindMatchingNodesPostOrder(ast, ast, IsArrowStructRef) for struct_ref, parent in candidates: struct_ref.type = "." struct_ref.name = c_ast.UnaryOp("*", struct_ref.name)
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 replace_underlying_sizeof(self, ut): for node in self.get_nodes(self.ast): if type(node) == c_ast.Decl: try: if node.init.name.name == "fffc_get_sizeof_type": node.init = get_sizeof_pointer_to_type( ut, c_ast.UnaryOp("*", c_ast.ID("storage"))) except AttributeError: pass
def set_outdated(ast_tree, ext_index, bock_item_index, func_name): new_node = c_ast.FuncCall( c_ast.ID('set_outdated'), c_ast.ExprList([ c_ast.UnaryOp('&', c_ast.ID('global_log')), c_ast.Constant('string', '"' + func_name + '"'), c_ast.Constant('int', str(len(func_name))) ])) return merge_ast_tree(ast_tree, ext_index, bock_item_index, new_node, "insert_before")
def visit_FuncDef(self, node): # Skip if no loop counters exist if self.loop_counter_size == 0: return # Create loop_counter declaration/initialization constants = [c_ast.Constant("int", '0') for i in range(self.loop_counter_size)] init_list = c_ast.InitList(constants) identifier_type = c_ast.IdentifierType(["int"]) type_decl = c_ast.TypeDecl("loop_counter", [], identifier_type) dim = c_ast.Constant("int", str(self.loop_counter_size)) array_decl = c_ast.ArrayDecl(type_decl, dim, []) decl = c_ast.Decl("loop_counter", [], [], [], array_decl, init_list, None) node.body.block_items.insert(0, decl) # Label for return values to goto start_label = c_ast.Label("print_loop_counter", c_ast.EmptyStatement()) # Start and end labels used for inserting preprocessor commands for #if DEBUG_EN end_label = c_ast.Label("print_loop_counter_end", c_ast.EmptyStatement()) # Write to file if self.write_to_file: stmt = c_ast.ID("write_array(loop_counter, %d)\n" % (self.loop_counter_size)) compound = c_ast.Compound([start_label, stmt, end_label]) # Print to stdout else: # Add printf to the end of function # Start of printing stmt_start = c_ast.ID("printf(\"loop counter = (\")") # For loop # int i; identifier_type = c_ast.IdentifierType(["int"]) type_decl = c_ast.TypeDecl("i", [], identifier_type) for_decl = c_ast.Decl("i", [], [], [], type_decl, [], None) # i = 0 init = c_ast.Assignment("=", c_ast.ID("i"), c_ast.Constant("int", '0')) # i < self.loop_counter_size cond = c_ast.BinaryOp("<", c_ast.ID("i"), c_ast.Constant("int", str(self.loop_counter_size))) # i++ next_stmt = c_ast.UnaryOp("p++", c_ast.ID("i")) # printf in for stmt = c_ast.ID("printf(\"%d, \", loop_counter[i])") # Cosntruct for loop stmt_for = c_ast.For(init, cond, next_stmt, stmt) # End of printing stmt_end = c_ast.ID("printf(\")\\n\")") # Put it all together body = c_ast.Compound([stmt_start, for_decl, stmt_for, stmt_end]) # Surround with labels compound = c_ast.Compound([start_label, body, end_label]) node.body.block_items.append(compound)
def papi_instr() -> Tuple[List[c_ast.Node], List[c_ast.Node]]: """ :return: c_ast nodes representing the following code: exec(PAPI_start(set)); *begin = clock(); ... *end = clock(); exec(PAPI_stop(set, values)); """ papi_start = c_ast.FuncCall(c_ast.ID('PAPI_start'), c_ast.ParamList([c_ast.ID('set')])) papi_stop = c_ast.FuncCall(c_ast.ID('PAPI_stop'), c_ast.ParamList([c_ast.ID('set'), c_ast.ID('values')])) exec_start = c_ast.FuncCall(c_ast.ID('exec'), c_ast.ParamList([papi_start])) exec_stop = c_ast.FuncCall(c_ast.ID('exec'), c_ast.ParamList([papi_stop])) clock = c_ast.FuncCall(c_ast.ID('clock'), c_ast.ParamList([])) begin_clock = c_ast.Assignment('=', c_ast.UnaryOp('*', c_ast.ID('begin')), clock) end_clock = c_ast.Assignment('=', c_ast.UnaryOp('*', c_ast.ID('end')), clock) return [exec_start, begin_clock], [end_clock, exec_stop]
def assign_results(outargs, code): ptroutargs = [deepcopy(arg) for arg in outargs] rename = RenameVisitor("out") for arg in ptroutargs: rename.visit(arg) arg.type = c_ast.PtrDecl([], arg.type) arg.init = None for ptr, var in zip(ptroutargs, outargs): code.append( c_ast.Assignment('=', c_ast.UnaryOp('*', c_ast.ID(ptr.name)), c_ast.ID(var.name)))
def define_sizeof_type_from_ast(argument_ast): prefix = "fffc_get_sizeof_" desired_name = CGenerator().visit(argument_ast) suffix = encode_hash(desired_name) function_name = prefix + suffix storage_tdecl = c_ast.Decl("storage", [], [], [], c_ast.PtrDecl([], argument_ast), None, None) func_tdecl = c_ast.TypeDecl( function_name, [], c_ast.IdentifierType(["long", "long", "unsigned"])) funcdecl = c_ast.FuncDecl(c_ast.ParamList([storage_tdecl]), func_tdecl) funcdef = c_ast.FuncDef( c_ast.Decl(function_name, [], [], [], funcdecl, None, None), None, c_ast.Compound([ c_ast.Return( c_ast.UnaryOp("sizeof", c_ast.UnaryOp("*", c_ast.ID("storage")))) ]), ) comment = "/* " + desired_name + "*/\n" kr_funcdecl = c_ast.FuncDecl(c_ast.ParamList([]), func_tdecl) return comment, kr_funcdecl, funcdef
def ConvertConvertAddressTakenScalarsToArray(ast, meta_info: meta.MetaInfo): """ Rewrite address taken scalar vars as one element arrays After this transform we can keep all scalars in registers. """ def IsAddressTakenScalarOrGlobalScalar(node, parent): if isinstance(node, c_ast.Decl) and IsScalarType(node.type): # return isinstance(parent, c_ast.FileAST) return (isinstance(parent, c_ast.FileAST) or "static" in node.storage) if not isinstance(node, c_ast.UnaryOp): return False if node.op != "&": return False if not isinstance(node.expr, c_ast.ID): return False type = meta_info.type_links[node.expr] return IsScalarType(type) candidates = common.FindMatchingNodesPreOrder(ast, ast, IsAddressTakenScalarOrGlobalScalar) ids = set() for node, _ in candidates: if isinstance(node, c_ast.UnaryOp): ids.add(meta_info.sym_links[node.expr]) else: ids.add(node) one = c_ast.Constant("int", "1") meta_info.type_links[one] = meta.INT_IDENTIFIER_TYPE for node in ids: assert isinstance(node, c_ast.Decl) node.type = c_ast.ArrayDecl(node.type, one, []) if node.init: node.init = c_ast.InitList([node.init]) def IsAddressTakenScalarId(node, _): return isinstance(node, c_ast.ID) and meta_info.sym_links[node] in ids candidates = common.FindMatchingNodesPreOrder(ast, ast, IsAddressTakenScalarId) for node, parent in candidates: original_type = meta_info.type_links[node] meta_info.type_links[node] = meta.GetTypeForDecl(meta_info.sym_links[node].type) array_ref = c_ast.UnaryOp("*", node) meta_info.type_links[array_ref] = original_type common.ReplaceNode(parent, node, array_ref)
def instrument(self, ast, linenum): value = c_ast.Constant(value='0', type='int') typeid = c_ast.TypeDecl(declname='inst_block', quals=[], type=c_ast.IdentifierType(['int'])) blockdecl = c_ast.Decl(name='inst_block', quals=[], storage=[], funcspec=[], bitsize=None, init=value, type=typeid) ast.body.block_items.insert(0, blockdecl) blockplus = c_ast.UnaryOp(op="p++", expr=c_ast.ID("inst_block")) visitor = self.ReturnLineVisitorDecls(linenum) visitor.generic_visit(ast) for element in visitor.path: element.block_items.insert(0, blockplus)
def fndecl(name, inargs, outargs, code): ptroutargs = [deepcopy(arg) for arg in outargs] rename = RenameVisitor("out") for arg in ptroutargs: rename.visit(arg) arg.type = c_ast.PtrDecl([], arg.type) arg.init = None fdecl = c_ast.FuncDecl( c_ast.ParamList(inargs + ptroutargs), c_ast.TypeDecl(name, [], c_ast.IdentifierType(['void']))) decl = c_ast.Decl(name, [], [], [], fdecl, None, None) assign = [] for ptr, var in zip(ptroutargs, outargs): assign.append( c_ast.Assignment('=', c_ast.UnaryOp('*', c_ast.ID(ptr.name)), c_ast.ID(var.name))) comp = c_ast.Compound(code + assign) return c_ast.FuncDef(decl, None, comp)
def update_value(ast_tree, ext_index, bock_item_index, var_name, func_name, var_size, func_size): Cast = c_ast.Cast( c_ast.Typename( None, [], c_ast.PtrDecl([], c_ast.TypeDecl(None, [], c_ast.IdentifierType(['void'])))), c_ast.ID(var_name)) new_node = c_ast.FuncCall( c_ast.ID('update_value'), c_ast.ExprList([ c_ast.UnaryOp('&', c_ast.ID('global_log')), Cast, c_ast.Constant('string', '"' + var_name + '"'), c_ast.Constant('string', '"' + func_name + '"'), c_ast.Constant('int', str(var_size)), c_ast.Constant('int', str(func_size)) ])) return merge_ast_tree(ast_tree, ext_index, bock_item_index, new_node, "insert_after")
def _get_assume_definition(self): param_name = '__cond' int_type = a.TypeDecl(param_name, [], a.IdentifierType(['int'])) param_list = a.ParamList( [a.Decl(param_name, [], [], [], int_type, None, None)]) assume_type = a.TypeDecl('__VERIFIER_assume', [], a.IdentifierType(['void'])) assume_func_decl = a.FuncDecl(param_list, assume_type) assume_decl = a.Decl('__VERIFIER_assume', list(), list(), list(), assume_func_decl, None, None) exit_code = a.ExprList([a.Constant('int', '0')]) true_branch = a.Compound([a.FuncCall(a.ID('exit'), exit_code)]) false_branch = None if_statement = a.If(a.UnaryOp('!', a.ID(param_name)), true_branch, false_branch) return_statement = a.Return(None) body_items = [if_statement, return_statement] assume_body = a.Compound(body_items) return a.FuncDef(assume_decl, None, assume_body)
def visitor(expr: Expression) -> None: if DEBUG_EAGER_TYPES: decayed_expr_type(expr, typemap) if not region.contains_node(expr): return orig_expr = expr if should_make_ptr: if not ast_util.is_lvalue(expr): return expr = ca.UnaryOp("&", expr) eind = einds.get(expr, 0) prev_write, _ = surrounding_writes(expr, orig_expr) for place in assignment_cands[::-1]: # If expr contains an ID which is written to within # [place, expr), bail out; we're trying to move the # assignment too high up. # TODO: also fail on moving past function calls, or # possibly-aliasing writes. if indices[place[2]] <= prev_write: break # Make far-away places less likely, and similarly for # trivial expressions. eind += 1 prob = 1 / eind if isinstance(orig_expr, (ca.ID, ca.Constant)): prob *= 0.15 if should_make_ptr else 0.5 reuse_cand = random.choice( reuse_cands) if reuse_cands else None candidates.append((prob, (place, expr, reuse_cand))) einds[expr] = eind
def create_loop_counter_stmt(self): stmt = c_ast.UnaryOp("p++", c_ast.ID("loop_counter[%d]" % (self.loop_counter_index))) self.loop_counter_index += 1 return stmt
def v_ArrayRef(self, n, store=False): # A array refrence is a[x] but this is just syntax shurger for #*(a + x) so just do that add_node = c_ast.BinaryOp("+", n.name, n.subscript) ptr_node = c_ast.UnaryOp(op='*', expr=add_node) self.v_UnaryOp(ptr_node, store)
def statement_rules(self, stmt, stmt_id, parent_id): if type(stmt) == c_ast.Compound: if len(stmt.block_items) == 1: self.statement_rules(stmt.block_items[0], stmt_id, parent_id) else: block_id = self.next_id() self.rule_body.append('sequenceT({0}, {1}, {2})'.format(stmt_id, parent_id, block_id)) items_ids = [self.next_id() for s in stmt.block_items if type(s) != c_ast.Label] if stmt_id == RuleID.INITIAL_ID: self.rule_body.append('{0} = {1}'.format(RuleID.CHILDREN_IDs, self.list_to_string(items_ids))) else: self.rule_body.append('length({0}, {1})'.format(block_id, len(items_ids))) for idx in range(0, len(stmt.block_items)): if type(stmt.block_items[idx]) == c_ast.Label: self.parse_label(stmt.block_items[idx]) else: self.statement_rules(stmt.block_items[idx], items_ids[idx], stmt_id) if idx > 0: self.rule_body.append('directly_after({0}, {1}, {2})'.format(items_ids[idx], items_ids[idx-1], block_id)) elif type(stmt) == c_ast.While or type(stmt) == c_ast.DoWhile: # LoopNode(LoopType.PRE_TESTED, get_ast(stmt.stmt), get_ast(stmt.cond)) condition_id = self.next_id() body_id = self.next_id() loop_type = 'doWhile' if type(stmt) == c_ast.DoWhile else 'while' self.rule_body.append('loopT({0}, {1}, \'{2}\', {3}, {4})'.format(stmt_id, parent_id, loop_type, condition_id, body_id)) self.statement_rules(stmt.cond, condition_id, stmt_id) self.statement_rules(stmt.stmt, body_id, stmt_id) elif type(stmt) == c_ast.For: pass elif type(stmt) == c_ast.If: #ConditionNode(stmt.cond, stmt.iftrue, stmt.iffalse) condition_id = self.next_id() true_id = self.next_id() if stmt.iftrue is not None else '\'null\'' false_id = self.next_id() if stmt.iffalse is not None else '\'null\'' self.rule_body.append('ifT({0}, {1}, {2}, {3}, {4})'.format(stmt_id, parent_id, condition_id, true_id, false_id)) self.statement_rules(stmt.cond, condition_id, stmt_id) if stmt.iftrue is not None: self.statement_rules(stmt.iftrue, true_id, stmt_id) if stmt.iffalse is not None: self.statement_rules(stmt.iffalse, false_id, stmt_id) elif type(stmt) == c_ast.Switch: pass elif type(stmt) == c_ast.Assignment: lhs_id = self.next_id() rhs_id = self.next_id() self.rule_body.append('assignT({0}, {1}, {2}, {3})'.format(stmt_id, parent_id, lhs_id, rhs_id)) self.statement_rules(stmt.lvalue, lhs_id, stmt_id) if stmt.op == c_lexer.CLexer.t_EQUALS: self.statement_rules(stmt.rvalue, rhs_id, stmt_id) else: binary_op = c_ast.BinaryOp(stmt.op[:-1], stmt.lvalue, stmt.rvalue) self.statement_rules(binary_op, rhs_id, stmt_id) elif type(stmt) == c_ast.FuncCall: args_block_id = self.next_id() self.rule_body.append('callT({0}, {1}, \'{2}\', {3})'.format(stmt_id, parent_id, stmt.name.name, args_block_id)) self.rule_body.append('length({0}, {1})'.format(args_block_id, len(stmt.args.exprs))) arg_ids = [self.next_id() for arg in stmt.args.exprs] for idx in range(0, len(arg_ids)): self.statement_rules(stmt.args.exprs[idx], arg_ids[idx], stmt_id) if idx > 0: self.rule_body.append('directly_after({0}, {1}, {2})'.format(arg_ids[idx], arg_ids[idx - 1], args_block_id)) elif type(stmt) == c_ast.UnaryOp: if stmt.op == '*': addr_expr_id = self.next_id() self.rule_body.append('memoryT({0}, {1}, {2})'.format(stmt_id, parent_id, addr_expr_id)) self.statement_rules(stmt.expr, addr_expr_id, stmt_id) elif stmt.op in ['p++', 'p--']: assignment = c_ast.Assignment(c_lexer.CLexer.t_EQUALS, stmt.expr, c_ast.BinaryOp('+', stmt.expr, c_ast.Constant('int', 1 if stmt.op == 'p++' else -1))) self.statement_rules(assignment, stmt_id, parent_id) else: self.operation_rules(stmt_id, parent_id, [stmt.expr], stmt.op) elif type(stmt) == c_ast.BinaryOp: if stmt.op == '-': stmt.op = '+' if type(stmt.right) == c_ast.Constant and stmt.right.type in ['int', 'float']: stmt.right.value = '-' + stmt.right.value else: stmt.right = c_ast.UnaryOp('-', stmt.right) self.operation_rules(stmt_id, parent_id, [stmt.left, stmt.right], stmt.op) elif type(stmt) == c_ast.TernaryOp: cond_id = self.next_id() true_id = self.next_id() false_id = self.next_id() self.rule_body.append('ternaryOperatorT({0}, {1}, {2}, {3}, {4})'.format(stmt_id, parent_id, cond_id, true_id, false_id)) self.statement_rules(stmt.cond, cond_id, stmt_id) self.statement_rules(stmt.iftrue, true_id, stmt_id) self.statement_rules(stmt.iffalse, false_id, stmt_id) elif type(stmt) == c_ast.ID: if stmt.name[0] == self.SPECIAL_VARIABLE_START: self.rule_body.append('{0} = {1}'.format(stmt.name[1:].title(), stmt_id)) else: self.rule_body.append('identT({0}, {1}, {2})'.format(stmt_id, parent_id, stmt.name.title())) self.variable_ids.add(stmt.name.title()) elif type(stmt) == c_ast.Constant: if stmt.type == 'int': try: val = int(stmt.value) except ValueError: val = int(stmt.value, 16) self.rule_body.append('numericLiteralT({0}, {1}, {2})'.format(stmt_id, parent_id, val)) elif type(stmt) == c_ast.Break: self.rule_body.append('breakT({0}, {1})'.format(stmt_id, parent_id)) elif type(stmt) == c_ast.Return: op_id = self.id_generator.next_id() self.rule_body.append('returnT({0}, {1}, {2})'.format(stmt_id, parent_id, op_id)) self.statement_rules(stmt.expr, op_id, stmt_id) elif type(stmt) == c_ast.Label: self.parse_label(stmt) else: assert False, "unrecognized stmt: {0}\n".format(type(stmt))
def visit_If(self, n): logger.debug('types(before branch): {}'.format(self._types)) logger.debug('Line {}: if({})'.format(n.coord.line, _code_generator.visit(n.cond))) # update pc value updPC before_pc = self._pc self._pc = self._update_pc(self._pc, self._types, n.cond) before_types = self._types.copy() # corresponds to \Gamma_0 in paper types_0 = self._types.copy() # promote the shadow distances of the assigned variables to * shadow_finder = _ExpressionFinder(lambda node: isinstance(node, c_ast.Assignment) and node.lvalue) for assign_node in shadow_finder.visit(n): if isinstance(assign_node.lvalue, c_ast.ID): varname = assign_node.lvalue.name elif isinstance(assign_node.lvalue, c_ast.ArrayRef): varname = assign_node.lvalue.name.name else: raise NotImplementedError( 'Assign node lvalue type not supported {}'.format(type(assign_node.lvalue))) align, shadow = types_0.get_distance(varname) types_0.update_distance(varname, align, '*') if self._pc and not before_pc: self._types = types_0 # backup the current types before entering the true or false branch cur_types = self._types.copy() self._inserted_query_assumes.append([]) # add current condition for simplification self._types.apply(n.cond, True) # to be used in if branch transformation assert(e^aligned); aligned_true_cond = _ExpressionReplacer(self._types, True).visit( copy.deepcopy(n.cond)) self.visit(n.iftrue) true_types = self._types logger.debug('types(true branch): {}'.format(true_types)) true_assumes = self._inserted_query_assumes.pop() self._inserted_query_assumes.append([]) # revert current types back to enter the false branch self._types = cur_types self._types.apply(n.cond, False) if n.iffalse: logger.debug('Line: {} else'.format(n.iffalse.coord.line)) self.visit(n.iffalse) # to be used in else branch transformation assert(not (e^aligned)); aligned_false_cond = _ExpressionReplacer(self._types, True).visit(copy.deepcopy(n.cond)) logger.debug('types(false branch): {}'.format(self._types)) false_types = self._types.copy() self._types.merge(true_types) logger.debug('types(after merge): {}'.format(self._types)) false_assumes = self._inserted_query_assumes.pop() exp_checker = _ExpressionFinder( lambda node: isinstance(node, c_ast.ArrayRef) and '__SHADOWDP_' in node.name.name and self._parameters[2] in node.name.name) if self._loop_level == 0: if self._pc and not before_pc: # insert c_s c_s = self._instrument(before_types, types_0, before_pc) if_index = self._parents[n].block_items.index(n) self._parents[n].block_items[if_index:if_index] = c_s for statement in c_s: self._inserted.add(statement) self._inserted.add(n) # insert c_shadow shadow_cond = _ExpressionReplacer(types_0, False).visit( copy.deepcopy(n.cond)) shadow_branch = c_ast.If(cond=shadow_cond, iftrue=c_ast.Compound( block_items=copy.deepcopy(n.iftrue.block_items)), iffalse=c_ast.Compound( block_items=copy.deepcopy(n.iffalse.block_items)) if n.iffalse else None) shadow_branch_generator = _ShadowBranchGenerator( {name for name, (_, shadow) in types_0.variables() if shadow == '*'}, types_0) shadow_branch_generator.visit(shadow_branch) if_index = self._parents[n].block_items.index(n) self._parents[n].block_items.insert(if_index + 1, shadow_branch) self._inserted.add(shadow_branch) # insert assume functions before the shadow branch for query_node in exp_checker.visit(shadow_cond): assume_functions = self._assume_query(query_node) index = self._parents[n].block_items.index(n) + 1 self._parents[n].block_items[index:index] = assume_functions for assume_function in assume_functions: self._inserted.add(assume_function) # create else branch if doesn't exist n.iffalse = n.iffalse if n.iffalse else c_ast.Compound(block_items=[]) # insert assert and assume functions to corresponding branch for aligned_cond in (aligned_true_cond, aligned_false_cond): block_node = n.iftrue if aligned_cond is aligned_true_cond else n.iffalse # insert the assertion assert_body = c_ast.ExprList(exprs=[aligned_cond]) if aligned_cond is aligned_true_cond else \ c_ast.UnaryOp(op='!', expr=c_ast.ExprList(exprs=[aligned_cond])) block_node.block_items.insert(0, c_ast.FuncCall(name=c_ast.ID(self._func_map['assert']), args=assert_body)) # if the expression contains `query` variable, # add assume functions on __SHADOWDP_ALIGNED_DISTANCE_query and __SHADOWDP_SHADOW_DISTANCE_query inserted = true_assumes if aligned_cond is aligned_true_cond else false_assumes self._inserted_query_assumes.append(inserted) for query_node in exp_checker.visit(aligned_cond): assume_functions = self._assume_query(query_node) block_node.block_items[0:0] = assume_functions self._inserted_query_assumes.pop() # instrument statements for updating aligned or shadow distance variables (Instrumentation rule) for types in (true_types, false_types): block_node = n.iftrue if types is true_types else n.iffalse inserted = true_assumes if types is true_types else false_assumes self._inserted_query_assumes.append(inserted) instruments = self._instrument(types, self._types, self._pc) block_node.block_items.extend(instruments) for instrument in instruments: self._inserted.add(instrument) self._inserted_query_assumes.pop() self._pc = before_pc
def take_address_of(self, expr): return c_ast.UnaryOp("&", expr)
def make_call_from_mutator_decl(arg_name, decl): name = c_ast.ID(decl.name) args = c_ast.ExprList(exprs=[c_ast.UnaryOp("&", c_ast.ID(arg_name))]) call = c_ast.FuncCall(name, args) return call