protected override IDataFlowState VisitStatement(CfgBlock block, Statement statement, IDataFlowState dfstate) { // For debug purpose try{ Analyzer.WriteLine(new SampleInstructionVisitor().Visit(statement,null)+" ::: " +statement.SourceContext.SourceText); }catch(Exception){ Analyzer.WriteLine("Print error: "+statement); } IDataFlowState result=null; try{ result =(IDataFlowState)(iVisitor.Visit(statement,dfstate)); }catch(ModifiesException e){ typeSystem.HandleError(statement,System.Compiler.Error.Warning,":"+e.Message); }catch(Exception e){ typeSystem.HandleError(statement,System.Compiler.Error.Warning,":CFG1:"+e.Message); } Analyzer.WriteLine(dfstate); return dfstate; }
internal static Statement GenerateForLoop(Variable loopVariable, Expression lowerBound, Expression upperBound, Statement body) { Block bodyAsBlock = body as Block ?? new Block(new StatementList(body)); Block init = new Block(new StatementList(2)); Block increment = new Block(new StatementList(1)); Block test = new Block(new StatementList(new Branch( new BinaryExpression(loopVariable, upperBound, NodeType.Lt), bodyAsBlock))); //, false, true, false))); init.Statements.Add(new AssignmentStatement(loopVariable, lowerBound)); init.Statements.Add(new Branch(null, test)); increment.Statements.Add(new AssignmentStatement(loopVariable, new BinaryExpression(loopVariable, Literal.Int32One, NodeType.Add))); Block forLoop = new Block(new StatementList(4)); forLoop.Statements.Add(init); forLoop.Statements.Add(bodyAsBlock); forLoop.Statements.Add(increment); forLoop.Statements.Add(test); return forLoop; }
protected override object VisitLoadNull(Variable dest, Literal source, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; return arg; }
private static bool IsNonTrivial(Statement s) { if (s == null) return false; Block b = s as Block; if (b != null) return (IsNonTrivial(b)); if (s.NodeType == NodeType.Nop) return false; return true; }
public static bool IsClosureCreation(Method containingMethod, Statement s, out Local closureLocal) { var closureType = IsClosureCreation(containingMethod, s); if (closureType != null) { // it's a closure alright var assign = s as AssignmentStatement; if (assign != null) { closureLocal = assign.Target as Local; } else { closureLocal = null; } return true; } closureLocal = null; return false; }
/// <summary> /// Perform subsitution if necessary (create fresh nodes) /// </summary> internal Statement Visit(Statement statement) { Contract.Requires(this.IsValid); Contract.Requires(this.Depth >= 0); Contract.Ensures(this.Depth >= -1); if (statement == null) return null; switch (statement.NodeType) { case NodeType.Nop: case NodeType.Rethrow: case NodeType.EndFilter: case NodeType.EndFinally: break; case NodeType.Pop: // a pop statement rather than expression this.Depth--; if (this.Depth < 0) { // we popped the original closure from the stack. return null; } return statement; case NodeType.AssignmentStatement: var astmt = (AssignmentStatement) statement.Clone(); astmt.Target = Visit(astmt.Target); astmt.Source = Visit(astmt.Source); return astmt; case NodeType.ExpressionStatement: var estmt = (ExpressionStatement) statement.Clone(); if (estmt.Expression.NodeType == NodeType.Dup) { if (this.Depth == 0) { // duping the closure. Do nothing: return null; } // otherwise, leave dup } else if (estmt.Expression.NodeType == NodeType.Pop) { var unary = estmt.Expression as UnaryExpression; if (unary != null && unary.Operand != null) { // we are popping the thing we just push, so the depth does not change. unary = (UnaryExpression) unary.Clone(); unary.Operand = Visit(unary.Operand); estmt.Expression = unary; return estmt; } // a pop statement rather than expression this.Depth--; if (this.Depth < 0) { // we popped the original closure from the stack. return null; } } else { estmt.Expression = Visit(estmt.Expression); if (!IsVoidType(estmt.Expression.Type)) { this.Depth++; } } return estmt; case NodeType.Block: var block = (Block) statement.Clone(); block.Statements = Visit(block.Statements); return block; case NodeType.SwitchInstruction: var sw = (SwitchInstruction) statement.Clone(); sw.Expression = Visit(sw.Expression); return sw; case NodeType.Throw: var th = (Throw) statement.Clone(); th.Expression = Visit(th.Expression); return th; case NodeType.Return: var ret = (Return) statement.Clone(); ret.Expression = Visit(ret.Expression); return ret; default: var br = statement as Branch; if (br != null) { br = (Branch) br.Clone(); br.Condition = Visit(br.Condition); return br; } throw new NotImplementedException("ClosureNormalization Statement"); } return statement; }
/// <summary> /// Checks whether a given CciHelper statement encodes an MSIL Pop instruction. /// The correctness of this method depends heavily on what Herman does in the CciHelper reader ... /// </summary> /// <param name="stat">Statement to check.</param> /// <returns><c>true</c> iff <c>stat</c> encodes an MSIL Pop instruction.</returns> public static bool IsPopStatement(Statement stat) { if(stat.NodeType == NodeType.Pop) return true; ExpressionStatement expr_stat = stat as ExpressionStatement; if(expr_stat == null) return false; Expression expr = expr_stat.Expression; if (expr.NodeType != NodeType.Pop) return false; UnaryExpression unexpr = expr as UnaryExpression; if ((unexpr != null ) && (unexpr.Operand != null) && (unexpr.Operand.NodeType != NodeType.Pop)) return false; return true; }
private static Statement WrapTryCatch(Method method, Statement statement) { Block afterCatches = new Block(new StatementList()); Block tryBlock = new Block(new StatementList()); Block blockAfterTryBody = new Block(null); tryBlock.Statements.Add(statement); tryBlock.Statements.Add(new Branch(null, afterCatches, false, true, true)); tryBlock.Statements.Add(blockAfterTryBody); Block catchBlock = new Block(new StatementList()); // emit code that pops the exception and fools fxcop Block branchTargetToFoolFxCop = new Block(null); var branch = new Branch(new Expression(NodeType.Pop), branchTargetToFoolFxCop); SourceContext hiddenContext = new SourceContext(HiddenDocument.Document); branch.SourceContext = hiddenContext; catchBlock.Statements.Add(branch); var rethrowStatement = new Throw(); rethrowStatement.SourceContext = hiddenContext; rethrowStatement.NodeType = NodeType.Rethrow; catchBlock.Statements.Add(rethrowStatement); catchBlock.Statements.Add(branchTargetToFoolFxCop); var leave = new Branch(null, afterCatches, false, true, true); leave.SourceContext = hiddenContext; catchBlock.Statements.Add(leave); Block tryCatch = new Block(new StatementList()); tryCatch.Statements.Add(tryBlock); tryCatch.Statements.Add(catchBlock); tryCatch.Statements.Add(afterCatches); if (method.ExceptionHandlers == null) method.ExceptionHandlers = new ExceptionHandlerList(); ExceptionHandler exHandler = new ExceptionHandler(); exHandler.TryStartBlock = tryBlock; exHandler.BlockAfterTryEnd = blockAfterTryBody; exHandler.HandlerStartBlock = catchBlock; exHandler.BlockAfterHandlerEnd = afterCatches; exHandler.FilterType = SystemTypes.Exception; exHandler.HandlerType = NodeType.Catch; method.ExceptionHandlers.Add(exHandler); return tryCatch; }
protected override object VisitReturn(Variable var, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; // TODO: see if returned value is supposed to be exposed or not and then what do we know about it? return arg; }
protected override object VisitStoreField(Variable dest, Field field, Variable source, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; // static Fields if(field.IsStatic){ } // BUGBUG!! // It seems that it would be better to start off ctors with the method's "this" object // in the Exposed state, but I'm not sure how to do that. This t = null; ThisBinding tb = dest as ThisBinding; if (tb != null){ t = tb.BoundThis; }else{ t = dest as This; } if (t != null && this.ExposureChecker.currentMethod.NodeType == NodeType.InstanceInitializer && this.ExposureChecker.currentMethod.ThisParameter == t){ ; // skip }else{ ExposureState.Lattice.AVal valueOfdest = estate.GetAVal(dest); if (valueOfdest.lowerBound == null || valueOfdest.upperBound == null){ HandleError(stat, stat, Error.WritingPackedObject, dest.Name.Name); return arg; } if (valueOfdest.lowerBound.IsAssignableTo(field.DeclaringType)){ HandleError(stat, stat, Error.WritingPackedObject, dest.Name.Name); return arg; } } return arg; }
protected override object VisitLoadField(Variable dest, Variable source, Field field, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; // Check the receiver here only if one needs to be unpacked for read access //CheckReceiver(stat,source,estate); return arg; }
protected override object VisitConstrainedCall(Variable dest, Variable receiver, Method callee, ExpressionList arguments, TypeNode constraint, Statement stat, object arg) { Reference rtype = receiver.Type as Reference; if (rtype != null && rtype.ElementType != null && !rtype.ElementType.IsValueType) { // instance could be a reference type that could be null. // BUGBUG: when we track address of, we need to check here that target is indeed non-null } return VisitCall(dest, receiver, callee, arguments, true, stat, arg); }
protected override object VisitCall(Variable dest, Variable receiver, Method callee, ExpressionList arguments, bool virtcall, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; if (callee.CciKind == Cci.CciMemberKind.FrameGuardGetter){ // associate dest with receiver, because unpack is going to happen with dest as receiver estate.AssignFrameFor(dest,receiver,callee.DeclaringType); // receiver could be a subtype of the type that the frame guard is for }else if (callee == UnpackMethod){ if(estate.IsFrameExposable(receiver)) { // BUGBUG: Using CopyVariable encodes the assumption that StartWritingTransitively returns itself!!! It may not! estate.CopyVariable(receiver,dest); estate.AssignFrameForExposed(dest); }else{ TypeNode t = estate.LowerBoundOfObjectPointedToByFrame(receiver); if (t == null){ // BUGBUG: is this the same as it being Top? HandleError(stat, stat, Error.DontKnowIfCanExposeObject); }else{ HandleError(stat, stat, Error.ExposingExposedObject); } return null; } }else if (callee == PackMethod){ estate.AssignFrameForNotExposed(receiver); }else if (callee == IsExposableMethod){ estate.AssignFunctionLink(ExposureState.EqIsExposableId,dest,receiver); }else if (callee == IsExposedMethod){ estate.AssignEqIsExposed(dest,receiver); }else if (callee == AssertMethod){ Variable v = arguments[0] as Variable; if (v != null && estate.IsFalse(v)) return null; } // Push possible exceptions to handlers. for(int i=0;i<callee.Contract.Ensures.Count;i++){ EnsuresExceptional e=callee.Contract.Ensures[i] as EnsuresExceptional; if(e!=null){ ExposureState newnn=new ExposureState(estate); newnn.currentException=e.Type; ExposureChecker.PushExceptionState(ExposureChecker.currBlock,newnn); } } return arg; }
/// <summary> /// Note: casts don't require a non-null argument. null value casts always succeed. /// </summary> protected override object VisitCastClass(Variable dest, TypeNode type, Variable source, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; // acts like a copy retaining null status estate.CopyVariable(source, dest); return arg; }
protected override object VisitLoadConstant(Variable dest, Literal source, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; if (source == Literal.False){ estate.SetToFalse(dest); } return arg; }
/// <summary> /// Helper method for CCI decoding /// </summary> internal static Method ExtractCallFromStatement(Statement s) { MethodCall dummy; return ExtractCallFromStatement(s, out dummy); }
internal static Method ExtractCallFromStatement(Statement s, out MethodCall call) { call = null; ExpressionStatement es = s as ExpressionStatement; if (es == null) return null; call = es.Expression as MethodCall; if (call == null || call.Callee == null) { return null; } MemberBinding mb = call.Callee as MemberBinding; if (mb == null) { return null; } Method m = mb.BoundMember as Method; if (m == null) { return null; } return m; }
protected override object VisitNop(Statement stat, object arg) { return arg; }
public override void VisitReturn(Return Return) { this.ReturnStatement = Return; base.VisitReturn(Return); }
protected override object VisitBranch(Variable cond, Block target, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; if(cond==null) return arg; ExposureState trueState, falseState; estate.RefineBranchInformation(cond, out trueState, out falseState); if ( trueState != null ) { ExposureChecker.PushState(ExposureChecker.currBlock, ExposureChecker.currBlock.TrueContinuation, trueState); } if ( falseState != null ) { ExposureChecker.PushState(ExposureChecker.currBlock, ExposureChecker.currBlock.FalseContinuation, falseState); } return null; }
/// <summary> /// Analyzes a statement to see if it is a call to a method. /// </summary> /// <param name="s">Any statement.</param> /// <returns>The method m if the statement is an expression statement that is a method call to m or null</returns> internal static Method IsMethodCall(Statement s) { if (s == null) return null; ExpressionStatement es = s as ExpressionStatement; if (es == null) return null; // If the expression statement represents a method call, then it can // have two different values as its expression: // 0. if the method's return type is void, then the expression is just the // method call. // 1. if the method's return type is not void, then the value of the method // isn't needed and it is wrapped inside of a unary expression, // Pop(method call(...)) in order to throw away the return value // // We want the method call only if its return type is void, so just look // for pattern 0. // MethodCall mc = es.Expression as MethodCall; if (mc == null) return null; MemberBinding mb = mc.Callee as MemberBinding; if (mb == null) return null; return mb.BoundMember as Method; }
protected override object VisitBinaryOperator(NodeType op, Variable dest, Variable operand1, Variable operand2, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; // estate.AssignBinary(dest, op, operand1, operand2); return arg; }
private static bool IsDup(Statement statement) { var expr = statement as ExpressionStatement; if (expr == null) return false; if (expr.Expression != null && expr.Expression.NodeType == NodeType.Dup) return true; return false; }
protected override object VisitUnaryOperator(NodeType op, Variable dest, Variable operand, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; return arg; }
internal static TypeNode IsClosureCreation(Method containingMethod, Statement s) { AssignmentStatement assign = s as AssignmentStatement; if (assign == null) { goto MaybePush; } Construct ctorCall = assign.Source as Construct; if (ctorCall == null) { return null; } if (IsClosureType(containingMethod.DeclaringType, assign.Target.Type)) { return assign.Target.Type; } MaybePush: ExpressionStatement expr = s as ExpressionStatement; if (expr == null) { return null; } var construct = expr.Expression as Construct; if (construct == null) return null; if (IsClosureType(containingMethod.DeclaringType, construct.Type)) { return construct.Type; } return null; }
protected override object VisitSizeOf(Variable dest, TypeNode value_type, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; estate.AssignNonPointer(dest); return arg; }
internal void Visit(Statement statement) { Contract.Requires(this.IsValid); if (statement == null) return; switch (statement.NodeType) { case NodeType.Nop: case NodeType.Rethrow: case NodeType.EndFilter: case NodeType.EndFinally: break; case NodeType.Pop: // a pop statement rather than expression return; case NodeType.AssignmentStatement: var astmt = (AssignmentStatement) statement; Visit(astmt.Source); var savedInStore = this.inStore; try { this.inStore = true; Visit(astmt.Target); } finally { this.inStore = savedInStore; } return; case NodeType.ExpressionStatement: var estmt = (ExpressionStatement) statement; if (estmt.Expression.NodeType == NodeType.Dup) { return; // not an expression } if (estmt.Expression.NodeType == NodeType.Pop) { var unary = estmt.Expression as UnaryExpression; if (unary != null && unary.Operand != null) { // we are popping the thing we just push, so the depth does not change. Visit(unary.Operand); return; } // a pop statement rather than expression return; } Visit(estmt.Expression); return; case NodeType.Block: var block = (Block) statement; Visit(block.Statements); return; case NodeType.SwitchInstruction: var sw = (SwitchInstruction) statement; Visit(sw.Expression); return; case NodeType.Throw: var th = (Throw) statement; Visit(th.Expression); return; case NodeType.Return: var ret = (Return) statement; Visit(ret.Expression); return; default: var br = statement as Branch; if (br != null) { Visit(br.Condition); return; } throw new NotImplementedException(string.Format("Expression scanner: {0}", statement.NodeType)); } }
protected override object VisitBox(Variable dest, Variable source, TypeNode type, Statement stat, object arg) { ExposureState estate=(ExposureState)arg; return arg; }
/// <summary> /// Determines whether a statement is part of an anonymous delegate construction. /// </summary> /// <param name="statement">Statement to inspect.</param> /// <returns><c>true</c> if <paramref name="statement"/> is part of anonymous delegate construction; otherwise, false.</returns> internal static bool IsAnonymousDelegateConstruction(Statement statement) { AssignmentStatement assignment = statement as AssignmentStatement; if (assignment != null) { if (assignment.Target != null && assignment.Target.Type != null && HelperMethods.IsCompilerGenerated(assignment.Target.Type)) { return true; } MemberBinding binding = assignment.Target as MemberBinding; if (binding != null) { if (binding.TargetObject != null && binding.TargetObject.Type != null && HelperMethods.IsCompilerGenerated(binding.TargetObject.Type)) { return true; } if (HelperMethods.IsCompilerGenerated(binding.BoundMember)) return true; } Local local = assignment.Target as Local; if (local != null && local.Name != null && local.Name.Name != null && local.Name.Name.StartsWith("<")) { return true; } } return false; }
private static bool IsChainConstructorCall(Statement statement) { var expression = statement as ExpressionStatement; if (expression == null) return false; var method = expression.Expression as MethodCall; if (method == null) return false; var callee = method.Callee as MemberBinding; if (callee == null) return false; return callee.BoundMember is InstanceInitializer; }