/// <summary> /// For the possible receiver v, check if it is nonnull. if no, file an proper /// error/warning. /// </summary> private void CheckReceiver(Statement stat, Variable v, ExposureState estate) { Node offendingNode = v; if (v == null) return; if(estate.IsNotExposed(v)) { HandleError(stat, offendingNode, Error.WritingPackedObject, v.Name.Name); //estate.AssignExposed(v); } else if(!estate.IsExposed(v)) { HandleError(stat, offendingNode, Error.WritingPackedObject, v.Name.Name); //estate.AssumeNonNull(v); } }
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> /// Implementation of visit Block. It is called from run. /// /// It calls VisitStatement. /// </summary> /// <param name="block"></param> /// <param name="stateOnEntry"></param> /// <returns></returns> protected override IDataFlowState VisitBlock(CfgBlock block, IDataFlowState stateOnEntry) { Debug.Assert(block!=null); currBlock=block; Analyzer.Write("---------block: "+block.UniqueId+";"); Analyzer.Write(" Exit:"); foreach (CfgBlock b in block.NormalSuccessors) Analyzer.Write(b.UniqueId+";"); if (block.UniqueSuccessor!=null) Analyzer.Write(" FallThrough: "+block.UniqueSuccessor+";"); if (block.ExceptionHandler!=null) Analyzer.Write(" ExHandler: "+block.ExceptionHandler.UniqueId+";"); Analyzer.WriteLine(""); ExposureState newState; if(stateOnEntry==null) newState=new ExposureState(typeSystem); else newState=new ExposureState((ExposureState)stateOnEntry); // if (block.ExceptionHandler!=null) // this.PushExceptionState(block,newState); return base.VisitBlock (block, newState); }
/// <summary> /// It split exceptions for current handler and the next chained handler. /// /// It will: /// /// If the exception is completely intercepted by current handler, the /// exception will be consumed. /// /// If the exception caught but not completely, both current handler and /// the next handler will take the states. /// /// If the exception is irrelevant to current caught, the next handler /// will take over the state. Current handler is then bypassed. /// </summary> /// <param name="handler"></param> /// <param name="currentHandlerState"></param> /// <param name="nextHandlerState"></param> protected override void SplitExceptions(CfgBlock handler, ref IDataFlowState currentHandlerState, out IDataFlowState nextHandlerState) { Debug.Assert(currentHandlerState!=null,"Internal error in NonNull Analysis"); ExposureState state = (ExposureState)currentHandlerState; if(handler==null || handler.Length==0){ nextHandlerState=null; return; } if(handler[0] is Unwind){ nextHandlerState=null; currentHandlerState=null; return; } Debug.Assert(handler[0] is Catch, "Exception Handler does not starts with Catch"); Debug.Assert(state.currentException!=null,"No current exception to handle"); Catch c=(Catch)handler[0]; if(handler.ExceptionHandler!=null && !state.currentException.IsAssignableTo(c.Type)) { nextHandlerState = state;; } else { nextHandlerState=null; } // Compute what trickles through to the next handler // and what sticks to this handler. if(state.currentException.IsAssignableTo(c.Type)) { // everything sticks nextHandlerState = null; } else if (c.Type.IsAssignableTo(state.currentException)) { // c sticks, rest goes to next handler nextHandlerState = state; // copy state to modify the currentException state = new ExposureState(state); state.currentException = c.Type; currentHandlerState = state; }else { // nothing stick all goes to next handler nextHandlerState = state; currentHandlerState = null; } return; }
/// <summary> /// Refines the given state according to the knowledge stored in the egraph about sv /// /// In addition, the state can be null when the knowledge is inconsistent. /// </summary> /// <param name="cv">symbolic value we assume to be non-null (true)</param> /// <param name="state">state if sv is non-null (true)</param> private static void AssumeTrue(ISymValue cv, ref ExposureState state) { if (state == null) return; foreach(EGraphTerm t in state.egraph.EqTerms(cv)){ ISymValue op = t.Args[0]; if (t.Function == ExposureState.EqIsExposedId){ // EqIsExposed(op) == true, therefore op *is* exposed state.AssignFrameForExposed(op); }else if (t.Function == ExposureState.EqIsExposableId){ state.AssignFrameForExposable(op); } } }
/// <summary> /// Refines the given state according to the knowledge stored in the egraph about sv /// /// In addition, the state can be null when the knowledge is inconsistent. /// </summary> /// <param name="cv">symbolic value we assume to be false</param> private static void AssumeFalse(ISymValue cv, ref ExposureState state) { if (state == null) return; foreach(EGraphTerm t in state.egraph.EqTerms(cv)) { if (t.Function == ExposureState.EqIsExposedId) { // EqIsExposed(op) == false, therefore op is *not* exposed ISymValue op = t.Args[0]; // state.AssignFrameForNotExposed(op); ISymValue guardedObject = state.egraph[FrameFor, op]; state.egraph[guardedObject] = Lattice.AVal.Top; // BUGBUG?? If it isn't exposed at this frame, then what is it? } } }
public void RefineBranchInformation(Variable cond, out ExposureState trueState, out ExposureState falseState) { ISymValue cv = this.egraph[cond]; trueState = new ExposureState(this); falseState = new ExposureState(this); AssumeTrue(cv, ref trueState); AssumeFalse(cv, ref falseState); }
/// <summary> /// Returns null, if result of Join is the same as atMerge. /// </summary> public static ExposureState Join(ExposureState atMerge, ExposureState incoming, CfgBlock joinPoint) { bool unchanged; IEGraph merged = atMerge.egraph.Join(incoming.egraph, joinPoint, out unchanged); TypeNode currentException = (atMerge.currentException != null)? ((incoming.currentException != null)? CciHelper.LeastCommonAncestor(atMerge.currentException, incoming.currentException) : null) : null; if (atMerge.currentException != currentException || !unchanged) { return new ExposureState(merged, currentException, atMerge.typeSystem); } return null; }
public ExposureState(ExposureState old){ this.typeSystem = old.typeSystem; this.egraph = (IEGraph)old.egraph.Clone(); this.currentException = old.currentException; }