def ConvertShortCircuitIf(if_stmt: c_ast.If, parent: c_ast.Node, id_gen: common.UniqueId): cond = if_stmt.cond if isinstance(cond, c_ast.UnaryOp) and cond.op == "!": # for a not not just swap the branches if_stmt.cond = cond.expr if_stmt.iffalse, if_stmt.iftrue = if_stmt.iftrue, if_stmt.iffalse ConvertShortCircuitIf(if_stmt, parent, id_gen) return if not isinstance(cond, c_ast.BinaryOp): return if cond.op != "&&" and cond.op != "||": return labelnext = id_gen.next("branch") if cond.op == "&&": if_stmt2 = c_ast.If(cond.left, c_ast.Goto(labelnext), if_stmt.iffalse) else: assert cond.op == "||" if_stmt2 = c_ast.If(cond.left, if_stmt.iftrue, c_ast.Goto(labelnext)) if_stmt.cond = cond.right stmts = common.GetStatementList(parent) # this is easy to fix but basically guaranteed after running IfTransform assert stmts, parent pos = stmts.index(if_stmt) stmts[pos:pos + 1] = [if_stmt2, c_ast.Label(labelnext, c_ast.EmptyStatement()), if_stmt] ConvertShortCircuitIf(if_stmt2, parent, id_gen) ConvertShortCircuitIf(if_stmt, parent, id_gen)
def visit_Compound(self, node): to_chain = [] for n in node.block_items: if type(n) == c_ast.If: to_chain.append(n) self.generic_visit(n) if len(to_chain) > 1: for n in to_chain: node.block_items.remove(n) first_if = to_chain[0] chained_if = c_ast.If(first_if.cond, iftrue=first_if.iftrue, iffalse=None) prev_if = chained_if node.block_items.append(chained_if) for n in to_chain[1:-1]: new_if = c_ast.If(n.cond, iftrue=n.iftrue, iffalse=None) prev_if.iffalse = new_if prev_if = new_if last_if = to_chain[-1] prev_if.iffalse = c_ast.If(last_if.cond, iftrue=last_if.iftrue, iffalse=None)
def insertTest(self,block,functionName,varVals,varTypes,timer): #Fork call cFork=c_ast.Assignment( lvalue=c_ast.ID(name='child_pid'), op='=', rvalue=c_ast.FuncCall( c_ast.ID(name='fork'), args=None)) #Child if self.functype=='int' or self.functype=="bool": printLeft=c_ast.Constant(type="char",value='"'+"%d" +'"') elif self.functype=='float' or self.functype=='double': printLeft=c_ast.Constant(type="char",value='"'+"%f" +'"') else: printLeft=c_ast.Constant(type="char",value='"'+"%d" +'"') expressList = list(c_ast.Constant(type=varTypes[i],value=str(varVals[i])) for i in range(len(varVals))) funcCall = c_ast.FuncCall(c_ast.ID(name=functionName),c_ast.ExprList(expressList)) expressList = [printLeft,funcCall] funcCall = c_ast.FuncCall(c_ast.ID(name="printf"),c_ast.ExprList(expressList)) funcCall2 = c_ast.FuncCall(c_ast.ID(name="exit"),c_ast.ExprList([c_ast.Constant(type='int',value='0')])) #Parent cAlarm=c_ast.FuncCall( c_ast.ID(name='alarm'),c_ast.ExprList([c_ast.Constant(type='int',value=str(timer))])) cWait=c_ast.FuncCall( c_ast.ID(name='wait'),c_ast.ExprList([c_ast.ID(name='0')])) #IFs if_false= c_ast.If( c_ast.BinaryOp(left=c_ast.ID(name='child_pid'),op='==',right= c_ast.Constant(type='int',value='0')), c_ast.Compound([funcCall,funcCall2]),iffalse=None) if_ini=c_ast.If( c_ast.BinaryOp(left=c_ast.ID(name='child_pid'),op='>',right= c_ast.Constant(type='int',value='0')), c_ast.Compound([cAlarm,cWait]),iffalse=if_false) block.body.block_items.insert(1,if_ini) block.body.block_items.insert(1,cFork)
def insertTest(self,block,functionName,varVals,varTypes,timer,preOut,testId): #Fork call cFork=c_ast.Assignment( lvalue=c_ast.ID(name='child_pid'), op='=', rvalue=c_ast.FuncCall( c_ast.ID(name='fork'), args=None)) #Child ##stdout = freopen("out.txt", "w", stdout); if self.functype=='int': printLeft=c_ast.Constant(type="char",value='"'+"%d" +'"') elif self.functype=='float' or self.functype=='double': printLeft=c_ast.Constant(type="char",value='"'+"%f" +'"') else: printLeft=c_ast.Constant(type="char",value='"'+"%d" +'"') fileOut=c_ast.Constant(type="char",value='"'+preOut +'.' +testId+".out.txt" +'"') fileW=c_ast.Constant(type="char",value='"'+"w" +'"') fileStdout=c_ast.ID(name='stdout') expressList = [fileOut,fileW,fileStdout] freopenC = c_ast.FuncCall(c_ast.ID(name="freopen"),c_ast.ExprList(expressList)) outReassign=c_ast.Assignment( lvalue=fileStdout, op='=', rvalue=freopenC) ##mainfake() expressList = list(c_ast.Constant(type=varTypes[i],value=str(varVals[i])) for i in range(len(varVals))) funcCall = c_ast.FuncCall(c_ast.ID(name=functionName),c_ast.ExprList(expressList)) expressList = [printLeft,funcCall] funcCall = c_ast.FuncCall(c_ast.ID(name="printf"),c_ast.ExprList(expressList)) ##exit(0) funcCall2 = c_ast.FuncCall(c_ast.ID(name="exit"),c_ast.ExprList([c_ast.Constant(type='int',value='0')])) #Parent cAlarm=c_ast.FuncCall( c_ast.ID(name='alarm'),c_ast.ExprList([c_ast.Constant(type='int',value=str(timer))])) cWait=c_ast.FuncCall( c_ast.ID(name='wait'),c_ast.ExprList([c_ast.ID(name='0')])) #IFs if_false= c_ast.If( c_ast.BinaryOp(left=c_ast.ID(name='child_pid'),op='==',right= c_ast.Constant(type='int',value='0')), c_ast.Compound([outReassign,funcCall,funcCall2]),iffalse=None) if_ini=c_ast.If( c_ast.BinaryOp(left=c_ast.ID(name='child_pid'),op='>',right= c_ast.Constant(type='int',value='0')), c_ast.Compound([cAlarm,cWait]),iffalse=if_false) block.body.block_items.insert(1,if_ini) block.body.block_items.insert(1,cFork)
def visit_Assignment(self, node): if self.inner_for: self.remove_node() if self.begin: if not self.inner_begin_block: self.inner_begin_block = c_ast.Compound([]) code = c_ast.If(c_ast.BinaryOp("==", self.inner_index, c_ast.Constant('int', '0')), self.inner_begin_block, None) self.inner_for.stmt.block_items.insert(0, code) self.inner_begin_block.block_items.append(node) else: if not self.inner_end_block: self.inner_end_block = c_ast.Compound([]) code = c_ast.If(c_ast.BinaryOp("==", self.inner_index, c_ast.BinaryOp('-', self.inner_limit, c_ast.Constant('int', '1'))), self.inner_end_block, None) self.inner_for.stmt.block_items.append(code) self.inner_end_block.block_items.append(node)
def add_jumps(self, jump_map: Dict[str, c_ast.Node]): for ghost_var, code in jump_map.items(): #print(ghost_var) ghost_var_ast = c_ast.ID(ghost_var) self.update_ast.block_items.append( c_ast.If(ghost_var_ast, code, None))
def compile_node(lookup, decl_code, node): code = [] stack = {} inargs = [] pre = node.type + '_pre' post = node.type + '_post' compile_ast(lookup, stack, inargs, decl_code, code, pre) for word in node.quotation: compile_ast(lookup, stack, inargs, decl_code, code, word) compile_ast(lookup, stack, inargs, decl_code, code, node.type) call = code[-1] end_stack = deepcopy(stack) end_inargs = deepcopy(inargs) end_code = [] compile_ast(lookup, end_stack, end_inargs, decl_code, end_code, post) outargs = [a for args in end_stack.values() for a in args] assign_results(outargs, end_code) end_code.append(c_ast.Return(None)) end = c_ast.Compound(end_code) condition = c_ast.If(call, end, None) code[-1] = condition compile_ast(lookup, stack, inargs, decl_code, code, post) outargs = [a for args in stack.values() for a in args] name = gensym(node.type) fn = fndecl(name, inargs, outargs, code) decl_code.append(fn) lookup[name] = (inargs, outargs) return name
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 _build_handle_function(functions): """ Wraps the switch statement in a function definition """ case_statement = _build_case(functions) available_check = c_ast.If( c_ast.BinaryOp( '<', c_ast.FuncCall( c_ast.ID('mailbox_available'), c_ast.ExprList([c_ast.Constant('int', '2')]) ), c_ast.Constant('int', '4') ), c_ast.Return(None), None ) handle_decl = c_ast.FuncDecl( None, c_ast.TypeDecl('_handle_events', [], c_ast.IdentifierType(['void'])), ) command_decl = c_ast.Decl('command', [], [], [], c_ast.TypeDecl('command', [], c_ast.IdentifierType(['int'])), [], []) command_read = _generate_read('command') body = c_ast.Compound([available_check, command_decl, command_read, case_statement]) return c_ast.FuncDef(handle_decl, [], body)
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 optimize_new(graph, tabDeg, myWhile): maxdeg = max_deg_of_list(tabDeg) while_node = myWhile.node_while peeling_deg = maxdeg + 1 if peeling_deg == 0: myWhile.isOpt = True return 0 initial_indices = [] tabDegs = [] nodelists = [] listIf = [] for i in range(peeling_deg): nodelists.append([]) tabDegs.append([]) initial_indices.append([]) for i in range(len(tabDeg)): for j in range(len(initial_indices)): initial_indices[j].append(i) for deg in tabDeg: for i in range(len(tabDegs)): tabDegs[i].append(deg) for node in while_node.stmt.block_items: for i in range(peeling_deg): nodelists[i].append(node) for i in range(maxdeg): tbrm = [] for init_ind in initial_indices[i]: if init_ind != -1: if tabDeg[init_ind] == i + 1: tbrm.append(init_ind) for init_ind in tbrm: curr_ind = initial_indices[i].index(init_ind) (capture_tab, recover_tab) = captures(init_ind, myWhile.node_while, tabDeg, graph) for capture in capture_tab: if capture[1] == -1 or capture[1] > i + 1: for k in range(len(capture[0])): nodelists[i].insert(curr_ind + 1, capture[0][k]) initial_indices[i].insert(curr_ind + 1, -1) for j in range(i + 1, peeling_deg): curr_ind = initial_indices[j].index(init_ind) for (recover, deg) in recover_tab: if deg == -1 or deg > j: nodelists[j].insert(curr_ind + 1, recover) initial_indices[j].insert(curr_ind + 1, -1) nodelists[j].pop(curr_ind) initial_indices[j].pop(curr_ind) if DEBUG_LEVEL >= 3: print(maxdeg, nodelists, initial_indices) listIf.append( c_ast.If(while_node.cond, c_ast.Compound(nodelists[i]), None)) listIf.append( c_ast.While(while_node.cond, c_ast.Compound(nodelists[maxdeg]), None)) myWhile.parent[0].block_items.pop(myWhile.parent[1]) listIf.reverse() for node in listIf: myWhile.parent[0].block_items.insert(myWhile.parent[1], node) myWhile.show() myWhile.isOpt = True
def add_jump_guard(ast_to_guard, phase_var, round_var, label): guarded_ast = c_ast.If( c_ast.BinaryOp( '&&', c_ast.BinaryOp('==', c_ast.ID(phase_var), c_ast.ID('PHASE')), c_ast.BinaryOp('==', c_ast.ID(round_var), c_ast.ID(label))), ast_to_guard, None) return c_ast.Compound([guarded_ast])
def visit_If(self, n: ca.If) -> str: n2 = n if (n.iffalse and isinstance(n.iffalse, ca.Compound) and n.iffalse.block_items and len(n.iffalse.block_items) == 1 and isinstance(n.iffalse.block_items[0], ca.If)): n2 = ca.If(cond=n.cond, iftrue=n.iftrue, iffalse=n.iffalse.block_items[0]) return super().visit_If(n2) # type: ignore
def createOutputIf(self, expr): expressList = [c_ast.Constant(type='int', value='0')] funcCall = c_ast.FuncCall(c_ast.ID(name="assert"), c_ast.ExprList(expressList)) if_all = c_ast.If(c_ast.BinaryOp(left=c_ast.ID(name='__out_var'), op='==', right=expr), c_ast.Compound([funcCall]), iffalse=None) return (if_all)
def visit_While(self, node): global global_trick_counter if isinstance(self.current_parent, c_ast.Compound): for i in xrange(len(self.current_parent.block_items)): if self.current_parent.block_items[i] == node: if global_do_trick: global_trick_counter -= 1 if global_trick_counter == 0: self.current_parent.block_items[i] = c_ast.If(node.cond, node.stmt, None, node.coord) else: global_trick_counter+= 1;
def test_nested_else_if_line_breaks(self): generator = c_generator.CGenerator() test_ast1 = c_ast.If(None, None, None) test_ast2 = c_ast.If(None, None, c_ast.If(None, None, None)) test_ast3 = c_ast.If(None, None, c_ast.If(None, None, c_ast.If(None, None, None))) test_ast4 = c_ast.If( None, c_ast.Compound([]), c_ast.If(None, c_ast.Compound([]), c_ast.If(None, c_ast.Compound([]), None))) self.assertEqual(generator.visit(test_ast1), 'if ()\n \n') self.assertEqual(generator.visit(test_ast2), 'if ()\n \nelse\n if ()\n \n') self.assertEqual(generator.visit(test_ast3), 'if ()\n \nelse\n if ()\n \nelse\n if ()\n \n') self.assertEqual( generator.visit(test_ast4), 'if ()\n{\n}\nelse\n if ()\n{\n}\nelse\n if ()\n{\n}\n')
def ConvertWhileLoop(ast, id_gen: common.UniqueId): def IsWhileLoop(node, _): return isinstance(node, (c_ast.DoWhile, c_ast.While)) candidates = common.FindMatchingNodesPostOrder(ast, ast, IsWhileLoop) for node, parent in candidates: loop_label = id_gen.next("while") test_label = loop_label + "_cond" exit_label = loop_label + "_exit" conditional = c_ast.If(node.cond, c_ast.Goto(loop_label), None) block = [c_ast.Label(loop_label, c_ast.EmptyStatement()), node.stmt, c_ast.Label(test_label, c_ast.EmptyStatement()), conditional, c_ast.Label(exit_label, c_ast.EmptyStatement())] if isinstance(node, c_ast.While): block = [c_ast.Goto(test_label)] + block common.ReplaceBreakAndContinue(node.stmt, node, test_label, exit_label) common.ReplaceNode(parent, node, c_ast.Compound(block))
def replaceByPrint(self, ast): expressList = [ c_ast.Constant(type='string', value='"[[REACHED]]"') ] ifexpress = c_ast.Assignment(op="=", lvalue=c_ast.ID(name="inst_flag"), rvalue=c_ast.Constant(type='int', value='1')) self.funcCall.name = c_ast.ID(name="perror") self.funcCall.args = c_ast.ExprList(expressList) if_all = c_ast.If(c_ast.BinaryOp(left=c_ast.ID(name='inst_flag'), op='==', right=c_ast.Constant(type='int', value='0')), c_ast.Compound([self.funcCall, ifexpress]), iffalse=None) for position, inst_block in enumerate(self.inst_block): inst_block[self.inst_pos[position]] = if_all
def addTestFunction(ast, expectedOutput, testFxn, initVars, initList): varList = [] exprList = [] fxnName = '' inFxn = False listi = 0 for i in range(len(initVars)): v = initVars[i] if inFxn: exprList.append(c_ast.Constant('int', initList[listi])) listi += 1 if (')' in v): inFxn = False newVar = c_ast.FuncCall(c_ast.ID(fxnName), c_ast.ExprList(exprList)) varList.append(newVar) exprList = [] else: if ('(' in v): fxnName = v[:v.index('(')] if (v[v.index('(')+1] != ')'): inFxn = True exprList.append(c_ast.Constant('int', initList[listi])) listi += 1 else: newVar = c_ast.FuncCall(c_ast.ID(fxnName), c_ast.ExprList([])) varList.append(newVar) else: newVar = c_ast.Assignment('=', c_ast.ID(v), c_ast.Constant('int', initList[listi])) listi += 1 varList.append(newVar) fxnDecl = c_ast.FuncDecl(None, c_ast.TypeDecl('klee_test_entry', [], c_ast.IdentifierType(['void']))) fxnCall = c_ast.FuncCall(c_ast.ID(testFxn), c_ast.ExprList([])) binaryOp = c_ast.BinaryOp('==', fxnCall, c_ast.Constant('int', expectedOutput)) ifFalse = c_ast.Compound([c_ast.FuncCall(c_ast.ID('klee_silent_exit'), c_ast.ExprList([c_ast.Constant('int', '0')]))]) ifTrue = c_ast.Compound([]) blockItems = [] for v in varList: blockItems.append(v) blockItems.append(c_ast.If(binaryOp, ifTrue, ifFalse)) fxnBody = c_ast.Compound(blockItems) fxnNode = c_ast.FuncDef(fxnDecl, None, fxnBody) ast.ext.append(fxnNode)
def convert(i): if i >= n: return item = node.stmt.block_items[i] # Item statement stmt = (c_ast.Compound(item.stmts, coord=item.coord) if isinstance(item.stmts, list) else item.stmts) if i == (n - 1) and isinstance(item, c_ast.Default): return stmt if isinstance(item, c_ast.Case): next = convert(i + 1) ifcond = c_ast.BinaryOp('==', node.cond, item.expr, coord=item.expr.coord) return c_ast.If(ifcond, stmt, next, coord=item.expr.coord)
def ConvertForLoop(ast, id_gen: common.UniqueId): candidates = common.FindMatchingNodesPostOrder( ast, ast, lambda n, _: isinstance(n, c_ast.For)) for node, parent in candidates: loop_label = id_gen.next("for") next_label = loop_label + "_next" test_label = loop_label + "_cond" exit_label = loop_label + "_exit" goto = c_ast.Goto(loop_label) conditional = c_ast.If(node.cond, goto, None) if node.cond else goto block = ExtractForInitStatements(node.init) + [ c_ast.Goto(test_label), c_ast.Label(loop_label, c_ast.EmptyStatement()), node.stmt, c_ast.Label(next_label, c_ast.EmptyStatement()), node.next if node.next else c_ast.EmptyStatement(), c_ast.Label(test_label, c_ast.EmptyStatement()), conditional, c_ast.Label(exit_label, c_ast.EmptyStatement()) ] common.ReplaceBreakAndContinue(node.stmt, node, next_label, exit_label) common.ReplaceNode(parent, node, c_ast.Compound(block))
def add_property(self, property: c_ast.ExprList, loop: c_ast.DoWhile or c_ast.While or c_ast.For, slice: bool = True): """ Adds the given expression to the end of the given loop. Note that by doing this, any previous property becomes unusable for our k-induction process. :param expression: The expression to be added. :param loop: The loop to add the property to. :param slice: Whether the code was sliced by Frama-C or not. """ if hasattr(loop, "stmt") and type(loop.stmt) is c_ast.Compound: if slice: SliceFuncCallUpdater().visit(property) property = self.join_expression_list("&&", property) property_check = c_ast.If( cond=property, iftrue=c_ast.Compound( [c_ast.FuncCall(c_ast.ID("__VERIFIER_error"), None)]), iffalse=None) loop.stmt.block_items.append(property_check)
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 cfg_path_to_ast(cfg): """Generates a AST from a CFG path (No FileAST support, it handles FuncDecl, If, While and no compound objects). Parameters ---------- cfg : ControlFlowGraph """ current_compound = c_ast.Compound([]) ast = current_compound previous_compound = None nodes = list(nx.topological_sort(cfg)) for n in nodes: if type(n) in {c_ast.FuncDef, c_ast.While, c_ast.If}: previous_compound = current_compound current_compound = c_ast.Compound([]) if type(n) == c_ast.FuncDef: inner_ast = c_ast.FuncDef(n.decl, n.param_decls, current_compound) elif type(n) == c_ast.While: inner_ast = c_ast.While(n.cond, current_compound) elif type(n) == c_ast.If: inner_ast = c_ast.If(n.cond, current_compound, None) previous_compound.block_items.append(inner_ast) elif type(n) not in { ControlFlowGraph.FuncDefEnd, ControlFlowGraph.IfEnd, ControlFlowGraph.IfStart, ControlFlowGraph.WhileEnd }: current_compound.block_items.append(n) return ast
def perm_ins_block(fn: ca.FuncDef, ast: ca.FileAST, indices: Indices, region: Region, random: Random) -> bool: """Wrap a random range of statements within `if (1) { ... }` or `do { ... } while(0)`. Control flow can have remote effects, so this mostly ignores the region restriction.""" cands: List[Block] = [] def rec(block: Block) -> None: cands.append(block) for stmt in ast_util.get_block_stmts(block, False): ast_util.for_nested_blocks(stmt, rec) rec(fn.body) block = random.choice(cands) stmts = ast_util.get_block_stmts(block, True) decl_count = 0 for stmt in stmts: if isinstance(stmt, (ca.Decl, ca.Pragma)): decl_count += 1 else: break lo = random.randrange(decl_count, len(stmts) + 1) hi = random.randrange(decl_count, len(stmts) + 1) if hi < lo: lo, hi = hi, lo new_block = ca.Compound(block_items=stmts[lo:hi]) if random.uniform(0, 1) < INS_BLOCK_DOWHILE_PROB and all( region.contains_node(n) for n in stmts[lo:hi]): cond = ca.Constant(type="int", value="0") stmts[lo:hi] = [ ca.Pragma("sameline start"), ca.DoWhile(cond=cond, stmt=new_block), ca.Pragma("sameline end"), ] else: cond = ca.Constant(type="int", value="1") stmts[lo:hi] = [ca.If(cond=cond, iftrue=new_block, iffalse=None)] return True
def loop_peel(graph, list_deg, loop): """Peel the loop based on the maximum invariance degree""" peeling_deg = max_deg_of_list(list_deg) + 1 if peeling_deg != 0: # if loop can be peeled loop_node = loop.loop_node parent_index = loop.parent[1] # index in the AST of the original loop loop.parent[0].block_items.pop(parent_index) # remove the orignal loop from AST commands = init_commands(peeling_deg, loop_node.stmt.block_items) # initialize all the commands in the body of the loop peel = [] # list of AST nodes for each peel for i in range(peeling_deg): peel_body = [] # list of commands for current peel for (node, ind) in commands[i]: # if the command can be peeled and has reached its peeling degree if ind != -1 and list_deg[ind] == i + 1: (capture_tab, recover_tab) = captures(ind, loop_node.stmt.block_items, list_deg, graph) add_new_vars(commands, i, node, ind, peeling_deg, capture_tab, recover_tab) peel_body.append(node) # if its the last peel, add the body to a while statement with the same cond exp as the original while loop if i == peeling_deg - 1: peel.append(c_ast.While(loop_node.cond, c_ast.Compound(peel_body))) else: # if not last peel, add the body to an if statement with the same cond exp as the original while loop peel.append(c_ast.If(loop_node.cond, c_ast.Compound(peel_body), None)) # if the loop contains a break/contiue, wrap the entire peeled loop inside of a while loop with the same cond # exp as the original if check_break(loop_node.stmt): peel = c_ast.While(loop_node.cond, c_ast.Compound(peel + [c_ast.Break()]), None) loop.parent[0].block_items.insert(parent_index, peel) else: for i in peel: # add each peel to the modified AST loop.parent[0].block_items.insert(parent_index, i) parent_index = parent_index + 1 loop.isOpt = True
def new_if(cond, iftrue, iffalse): return c_ast.If(cond, iftrue, iffalse)
def visit_FuncDef(self, node): if (len(self.varList) < 1): return self.name = node.decl.name # find the correct function name if (self.name == self.function): for idx, item in enumerate(node.body.block_items): # find the return statement within that function if (isinstance(item, c_ast.Return)): returnStatement = item for var in self.varList: outOfScope = False varArr = var.split(' ') # make sure all variables of the expression are in-scope for v in varArr: if any(scopeV in v for scopeV in self.outOfScopeVarList) and v != '': outOfScope = True break if outOfScope: # replace the return statement with a print of 0 node.body.block_items[idx] = c_ast.FuncCall( c_ast.ID('fprintf'), c_ast.ExprList([ c_ast.ID('stdout'), c_ast.Constant('str', '"%d,"'), c_ast.Constant('str', '"0"') ])) break else: # replace the return statement with the first printed variable node.body.block_items[idx] = c_ast.FuncCall( c_ast.ID('fprintf'), c_ast.ExprList([ c_ast.ID('stdout'), c_ast.Constant('str', '"%d,"'), c_ast.Constant('str', var) ])) break # add the remaining print statements for var in self.varList[1:]: # make sure all variables of the expression are in-scope outOfScope = False varArr = var.split(' ') for v in varArr: if any(scopeV in v for scopeV in self.outOfScopeVarList) and v != '': outOfScope = True break # print 0 if a variable is out of scope if outOfScope: node.body.block_items.append( c_ast.FuncCall( c_ast.ID('fprintf'), c_ast.ExprList([ c_ast.ID('stdout'), c_ast.Constant('str', '"%d,"'), c_ast.Constant('str', '"0"') ]))) # print the expression if all variables are in scope else: if ('/' in var): denom = var[var.index('/') + 1:] binaryOp = c_ast.BinaryOp('==', c_ast.Constant('str', denom), c_ast.Constant('int', '0')) ifTrue = c_ast.Compound([ c_ast.FuncCall( c_ast.ID('fprintf'), c_ast.ExprList([ c_ast.ID('stdout'), c_ast.Constant('str', '"NaN,"') ])) ]) ifFalse = c_ast.Compound([ c_ast.FuncCall( c_ast.ID('fprintf'), c_ast.ExprList([ c_ast.ID('stdout'), c_ast.Constant('str', '"%d,"'), c_ast.Constant('str', var) ])) ]) node.body.block_items.append( c_ast.If(binaryOp, ifTrue, ifFalse)) else: node.body.block_items.append( c_ast.FuncCall( c_ast.ID('fprintf'), c_ast.ExprList([ c_ast.ID('stdout'), c_ast.Constant('str', '"%d,"'), c_ast.Constant('str', var) ]))) # add a newline character and the original return statement at the end node.body.block_items.append( c_ast.FuncCall( c_ast.ID('fprintf'), c_ast.ExprList( [c_ast.ID('stdout'), c_ast.Constant('str', '"\\n"')]))) node.body.block_items.append(returnStatement)
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 _assume_query(self, query_node): """ instrument assume functions of query input (sensitivity guarantee) """ assume_functions = [] shadow_distance_node = copy.deepcopy(query_node) align_distance_node = copy.deepcopy(query_node) regex = re.compile(r'__SHADOWDP_[A-Z]+_DISTANCE_([_a-zA-Z][a-zA-Z0-9\[\]]*)') align_distance_node.name.name = regex.sub(r'__SHADOWDP_ALIGNED_DISTANCE_\g<1>', query_node.name.name) shadow_distance_node.name.name = regex.sub(r'__SHADOWDP_SHADOW_DISTANCE_\g<1>', query_node.name.name) common_assume = [ c_ast.FuncCall( name=c_ast.ID(self._func_map['assume']), args=c_ast.ExprList(exprs=[c_ast.BinaryOp(op='<=', left=align_distance_node, right=c_ast.Constant('int', '1'))])), c_ast.FuncCall( name=c_ast.ID(self._func_map['assume']), args=c_ast.ExprList(exprs=[c_ast.BinaryOp(op='>=', left=align_distance_node, right=c_ast.Constant('int', '-1'))])), c_ast.FuncCall( name=c_ast.ID(self._func_map['assume']), args=c_ast.ExprList(exprs=[c_ast.BinaryOp(op='==', left=shadow_distance_node, right=align_distance_node)])) ] # insert following statements: # if (i == __SHADOWDP_index) { # assume(__SHADOWDP_ALIGNED_DISTANCE_q[i] >= -1); assume(__SHADOWDP_ALIGNED_DISTANCE_q[i] <= 1); # assume(__SHADOWDP_SHADOW_DISTANCE_q[i] == __SHADOWDP_ALIGNED_DISTANCE_q[i]); # } # else { # assume(__SHADOWDP_ALIGNED_DISTANCE_q[i] == 0); # assume(__SHADOWDP_SHADOW_DISTANCE_q[i] == __SHADOWDP_ALIGNED_DISTANCE_q[i]); # } if self._one_differ: if_block = c_ast.If(cond=c_ast.BinaryOp('==', left=query_node.subscript, right=c_ast.ID(name='__SHADOWDP_index')), iftrue=c_ast.Compound(block_items=[]), iffalse=c_ast.Compound(block_items=[])) if_block.iftrue.block_items = common_assume if_block.iffalse.block_items = [ c_ast.FuncCall( name=c_ast.ID(self._func_map['assume']), args=c_ast.ExprList(exprs=[c_ast.BinaryOp(op='==', left=shadow_distance_node, right=align_distance_node)])), c_ast.FuncCall( name=c_ast.ID(self._func_map['assume']), args=c_ast.ExprList(exprs=[c_ast.BinaryOp(op='==', left=align_distance_node, right=c_ast.Constant('int', '0'))])) ] assume_functions.append(if_block) # insert following statements: # assume(__SHADOWDP_ALIGNED_DISTANCE_q[i] >= -1); assume(__SHADOWDP_ALIGNED_DISTANCE_q[i] <= 1); # assume(__SHADOWDP_SHADOW_DISTANCE_q[i] == __SHADOWDP_ALIGNED_DISTANCE_q[i]); else: assume_functions = common_assume # if assume function has already been inserted in this scope for inserted in self._inserted_query_assumes[-1]: if is_node_equal(assume_functions, inserted): return [] self._inserted_query_assumes[-1].append(assume_functions) return assume_functions