// // AnalysisDecoder.cs // // Authors: // Alexander Chebaturkin (chebaturkin@gmail.com) // // Copyright (C) 2011 Alexander Chebaturkin // // Permission is hereby granted, free of charge, to any person obtaining // a copy of this software and associated documentation files (the // "Software"), to deal in the Software without restriction, including // without limitation the rights to use, copy, modify, merge, publish, // distribute, sublicense, and/or sell copies of the Software, and to // permit persons to whom the Software is furnished to do so, subject to // the following conditions: // // The above copyright notice and this permission notice shall be // included in all copies or substantial portions of the Software. // // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // using System; using System.Collections.Generic; using Mono.CodeContracts.Static.AST; using Mono.CodeContracts.Static.AST.Visitors; using Mono.CodeContracts.Static.ControlFlow; using Mono.CodeContracts.Static.DataStructures; using Mono.CodeContracts.Static.Lattices; using Mono.CodeContracts.Static.Providers; namespace Mono.CodeContracts.Static.Analysis.HeapAnalysis { struct AnalysisDecoder : IILVisitor { private readonly HeapAnalysis parent; public AnalysisDecoder (HeapAnalysis parent) { this.parent = parent; } public IContractProvider ContractProvider { get { return this.parent.ContractProvider; } } public IMetaDataProvider MetaDataProvider { get { return this.parent.MetaDataProvider; } } #region Helper Methods private void UnaryEffect (UnaryOperator op, int dest, int source, Domain data) { switch (op) { case UnaryOperator.Conv_i: data.AssignValueAndNullnessAtConv_IU (dest, source, false); break; case UnaryOperator.Conv_u: data.AssignValueAndNullnessAtConv_IU (dest, source, true); break; case UnaryOperator.Not: data.AssignSpecialUnary (dest, data.Functions.UnaryNot, source, MetaDataProvider.System_Int32); break; default: data.AssignPureUnary (dest, op, data.UnaryResultType (op, data.CurrentType (source)), source); break; } } private Domain BinaryEffect (APC pc, BinaryOperator op, int dest, int op1, int op2, Domain data) { FlatDomain resultType = data.BinaryResultType (op, data.CurrentType (op1), data.CurrentType (op2)); switch (op) { case BinaryOperator.Ceq: case BinaryOperator.Cobjeq: { SymValue srcValue = data.Value (op1); if (data.IsZero (srcValue)) { data.AssignSpecialUnary (dest, data.Functions.UnaryNot, op2, resultType); break; } SymValue val2 = data.Value (op2); if (data.IsZero (val2)) { data.AssignSpecialUnary (dest, data.Functions.UnaryNot, op1, resultType); break; } goto default; } case BinaryOperator.Cne_Un: { SymValue val1 = data.Value (op1); if (data.IsZero (val1)) { data.AssignSpecialUnary (dest, data.Functions.NeZero, op2, resultType); break; } SymValue val2 = data.Value (op2); if (data.IsZero (val2)) { data.AssignSpecialUnary (dest, data.Functions.NeZero, op1, resultType); break; } goto default; } default: data.AssignPureBinary (dest, op, resultType, op1, op2); break; } data.Havoc (2); return data; } private void LoadArgEffect (Parameter argument, bool isOld, int dest, Domain data) { SymValue address = isOld ? data.OldValueAddress (argument) : data.Address (argument); IMetaDataProvider metadataDecoder = MetaDataProvider; data.CopyValue (data.Address (dest), address, metadataDecoder.ManagedPointer (metadataDecoder.ParameterType (argument))); } private void StoreLocalEffect (Local local, int source, Domain data) { data.CopyValue (data.Address (local), data.Address (source), MetaDataProvider.ManagedPointer (MetaDataProvider.LocalType (local))); data.Havoc (source); } private void IsinstEffect (TypeNode type, int dest, Domain data) { data.AssignValue (dest, type); } private void LoadLocalEffect (Local local, int dest, Domain data) { data.CopyValue (data.Address (dest), data.Address (local), MetaDataProvider.ManagedPointer (MetaDataProvider.LocalType (local))); } private Domain AssumeEffect (APC pc, EdgeTag tag, int condition, Domain data) { data = data.Assume (condition, tag != EdgeTag.False); if (!data.IsBottom) data.Havoc (condition); return data; } private Domain AssertEffect (APC pc, EdgeTag tag, int condition, Domain data) { data = data.Assume (condition, true); if (!data.IsBottom) data.Havoc (condition); return data; } private static void LoadStackAddressEffect (APC pc, int offset, int dest, int source, Domain data) { data.CopyStackAddress (data.Address (dest), source); } private Domain CallEffect (APC pc, Method method, bool virt, TypeList extraVarargs, int dest, ArgList args, Domain data, TypeNode constraint, bool constrainedCall) where TypeList : IIndexable where ArgList : IIndexable { TypeNode t = constraint; if (!pc.InsideContract) data.ResetModifiedAtCall (); IImmutableMap instantiationMap = ComputeTypeInstantiationMap (pc, method); bool derefThis = false; if (virt) { if (MetaDataProvider.IsStruct (constraint)) DevirtualizeImplementingMethod (constraint, ref method); else { if (constrainedCall && MetaDataProvider.IsReferenceType (Specialize (instantiationMap, constraint))) derefThis = true; SymValue loc = data.Value (args[0]); if (derefThis) loc = data.Value (loc); AbstractType aType = data.GetType (loc); if (aType.IsNormal()) DevirtualizeImplementingMethod (aType.ConcreteType, ref method); } } string name = MetaDataProvider.Name (method); if (args.Count > 0) { if ((MetaDataProvider.Equal (t, MetaDataProvider.System_String) || MetaDataProvider.Equal (t, MetaDataProvider.System_Array)) && (name == "get_Length" || name == "get_LongLength")) { data.AssignArrayLength (data.Address (dest), data.Value (args[0])); return data; } if (MetaDataProvider.Equal (t, MetaDataProvider.System_Object) && name == "MemberwiseClone") { TypeNode t2 = data.GetType (data.Value (args[0])).ConcreteType; SymValue obj = data.CreateObject (t2); data.CopyStructValue (obj, data.Value (args[0]), t2); data.CopyAddress (data.Address (dest), obj, t2); return data; } if (args.Count > 1 && MetaDataProvider.IsReferenceType (t)) { if (name.EndsWith ("op_Inequality")) return Binary (pc, BinaryOperator.Cne_Un, dest, args[0], args[1], data); if (name.EndsWith ("op_Equality")) return Binary (pc, BinaryOperator.Cobjeq, dest, args[0], args[1], data); } if (MetaDataProvider.Equal (t, MetaDataProvider.System_IntPtr) && name.StartsWith ("op_Explicit")) { data.Copy (dest, args[0]); return data; } } //todo: // if (extraVarargs.Count == 0 && !this.MetaDataProvider.IsVoidMethod(method) && this.ContractProvider.) { Property property; if (MetaDataProvider.IsPropertySetter (method, out property)) { if (args.Count <= 2) { Method getter; if (MetaDataProvider.HasGetter (property, out getter)) { SymValue obj; SymValue srcAddr; if (args.Count == 1) { obj = data.Globals; srcAddr = data.Address (args[0]); } else { obj = data.Value (args[0]); if (derefThis) obj = data.Value (obj); srcAddr = data.Address (args[1]); } if (MetaDataProvider.Equal (MetaDataProvider.DeclaringType (this.parent.CurrentMethod), MetaDataProvider.Unspecialized (MetaDataProvider.DeclaringType (method)))) { data.HavocUp (obj, ref data.ModifiedAtCall, false); if (MetaDataProvider.IsAutoPropertyMember (method)) { foreach (Field f in this.parent.StackContextProvider.MethodContext.Modifies (method)) { TypeNode fieldAddressType; SymValue destAddr = data.FieldAddress (obj, f, out fieldAddressType); data.CopyValue (destAddr, srcAddr, fieldAddressType); } } else data.HavocFields (obj, this.parent.StackContextProvider.MethodContext.Modifies (method), ref data.ModifiedAtCall); } TypeNode pseudoFieldAddressType; SymValue destAddr1 = data.PseudoFieldAddress (obj, getter, out pseudoFieldAddressType, true); data.CopyValue (destAddr1, srcAddr, pseudoFieldAddressType); data.AssignValue (dest, MetaDataProvider.System_Void); return data; } } else { Method getter; if (MetaDataProvider.HasGetter (property, out getter)) { var args1 = new SymValue[GetNonOutArgs (method) - 1]; int num = 0; for (int i = 0; i < args.Count - 1; i++) { bool isOut; SymValue sv = KeyForPureFunctionArgument (method, i, args[i], data, instantiationMap, out isOut); if (!isOut) args1[num++] = sv; } SymValue thisSV = data.Value (args[0]); if (derefThis) thisSV = data.Value (thisSV); TypeNode pseudoFieldAddressType; SymValue pseudoField = data.PseudoFieldAddress (args1, getter, out pseudoFieldAddressType, false); AssignAllOutParameters (data, pseudoField, method, args); SymValue srcAddr = data.Address (args[args.Count - 1]); data.CopyValue (pseudoField, srcAddr, pseudoFieldAddressType); if (MetaDataProvider.Equal (MetaDataProvider.DeclaringType (this.parent.CurrentMethod), MetaDataProvider.Unspecialized (MetaDataProvider.DeclaringType (method)))) { data.HavocUp (thisSV, ref data.ModifiedAtCall, false); data.HavocFields (thisSV, this.parent.StackContextProvider.MethodContext.Modifies (method), ref data.ModifiedAtCall); } } data.AssignValue (dest, MetaDataProvider.System_Void); return data; } } bool insideConstructor = MetaDataProvider.IsConstructor (method); HavocParameters (pc, method, extraVarargs, args, data, constraint, insideConstructor, false, derefThis); data.AssignReturnValue (dest, MetaDataProvider.ReturnType (method)); return data; } } private static Domain DoWithBothDomains (Domain data, Func action) { data = action (data); if (data.OldDomain != null) data.OldDomain = action (data.OldDomain); return data; } private static Domain DoWithBothDomains (Domain data, Action action) { action (data); if (data.OldDomain != null) action (data.OldDomain); return data; } #endregion #region IILVisitor Members public Domain Binary (APC pc, BinaryOperator op, int dest, int operand1, int operand2, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.BinaryEffect (pc, op, dest, operand1, operand2, d)); } public Domain Isinst (APC pc, TypeNode type, int dest, int obj, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.IsinstEffect (type, dest, d)); } public Domain LoadNull (APC pc, int dest, Domain polarity) { return DoWithBothDomains (polarity, d => d.AssignNull (dest)); } public Domain LoadConst (APC pc, TypeNode type, object constant, int dest, Domain data) { return DoWithBothDomains (data, d => d.AssignConst (dest, type, constant)); } public Domain Sizeof (APC pc, TypeNode type, int dest, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => d.AssignValue (dest, it.MetaDataProvider.System_Int32)); } public Domain Unary (APC pc, UnaryOperator op, bool unsigned, int dest, int source, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.UnaryEffect (op, dest, source, d)); } public Domain Entry (APC pc, Method method, Domain data) { IIndexable locals = MetaDataProvider.Locals (method); for (int i = 0; i < locals.Count; i++) MaterializeLocal (locals [i], method, data); TypeNode declaringType = MetaDataProvider.DeclaringType (method); IIndexable parameters = MetaDataProvider.Parameters (method); for (int i = 0; i < parameters.Count; i++) MaterializeParameter (parameters [i], declaringType, data, false); if (!MetaDataProvider.IsStatic (method)) MaterializeParameter (MetaDataProvider.This (method), declaringType, data, true); if (MetaDataProvider.IsConstructor (method)) { Parameter p = MetaDataProvider.This (method); SymValue ptr = data.Value (p); foreach (Field field in MetaDataProvider.Fields (declaringType)) { if (MetaDataProvider.IsStatic (field)) continue; TypeNode fieldType = MetaDataProvider.FieldType (field); if (MetaDataProvider.IsStruct (fieldType)) data.AssignConst (data.FieldAddress (ptr, field), fieldType, 0); else data.AssignNull (data.FieldAddress (ptr, field)); } foreach (Property property in MetaDataProvider.Properties (declaringType)) { Method getter; if (!MetaDataProvider.IsStatic (property) && MetaDataProvider.HasGetter (property, out getter) && MetaDataProvider.IsCompilerGenerated (getter) && MetaDataProvider.Parameters (getter).Count == 0) { TypeNode propertyType = MetaDataProvider.ReturnType (getter); if (MetaDataProvider.IsStruct (propertyType)) data.AssignConst (data.PseudoFieldAddress (ptr, getter), propertyType, 0); else data.AssignNull (data.PseudoFieldAddress (ptr, getter)); } } } return data; } public Domain Assume (APC pc, EdgeTag tag, int condition, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.AssumeEffect (pc, tag, condition, data)); } public Domain Assert (APC pc, EdgeTag tag, int condition, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.AssertEffect (pc, tag, condition, data)); } public Domain BeginOld (APC pc, APC matchingEnd, Domain data) { if (data.InsideOld++ == 0) { Domain oldState = FindOldState (pc, data); if (oldState == null) throw new InvalidOperationException ("begin_old in weird calling context"); Domain domain = oldState.Clone (); domain.BeginOldPC = pc; data.OldDomain = domain; } return data; } public Domain EndOld (APC pc, APC matchingBegin, TypeNode type, int dest, int source, Domain data) { if (--data.InsideOld == 0) data.OldDomain = null; data.Copy (dest, source); return data; } public Domain LoadStack (APC pc, int offset, int dest, int source, bool isOld, Domain data) { if (isOld) { Domain oldState = FindOldState (pc, data); oldState.CopyOldValue (pc, dest, source, data, false); if (data.OldDomain != null) oldState.CopyOldValue (pc, dest, source, data.OldDomain, false); } else { data.Copy (dest, source); if (data.OldDomain != null) data.OldDomain.Copy (dest, source); } return data; } public Domain LoadStackAddress (APC pc, int offset, int dest, int source, TypeNode type, bool isOld, Domain data) { if (isOld) { TypeNode ptrType = MetaDataProvider.ManagedPointer (type); Domain oldState = FindOldState (pc, data); SymValue srcOldAddr = oldState.Address (source); SymValue sv = data.CreateValue (type); oldState.CopyOldValue (pc, sv, srcOldAddr, data, true); data.CopyAddress (data.Address (dest), sv, ptrType); if (data.OldDomain != null) { TypeNode ptrPtrType = MetaDataProvider.ManagedPointer (ptrType); oldState.CopyOldValueToDest (pc, data.OldDomain.Address (dest), srcOldAddr, ptrPtrType, data.OldDomain); } } else { LoadStackAddressEffect (pc, offset, dest, source, data); if (data.OldDomain != null) LoadStackAddressEffect (pc, offset, dest, source, data.OldDomain); } return data; } public Domain LoadResult (APC pc, TypeNode type, int dest, int source, Domain data) { return DoWithBothDomains (data, d => d.Copy (dest, source)); } public Domain Arglist (APC pc, int dest, Domain data) { throw new NotImplementedException (); } public Domain Branch (APC pc, APC target, bool leavesExceptionBlock, Domain data) { throw new InvalidOperationException ("Should not see branches, should see assumes. See APCDecoder"); } public Domain BranchCond (APC pc, APC target, BranchOperator bop, int value1, int value2, Domain data) { throw new InvalidOperationException ("Should not see branches, should see assumes. See APCDecoder"); } public Domain BranchTrue (APC pc, APC target, int cond, Domain data) { throw new InvalidOperationException ("Should not see branches, should see assumes. See APCDecoder"); } public Domain BranchFalse (APC pc, APC target, int cond, Domain data) { throw new InvalidOperationException ("Should not see branches, should see assumes. See APCDecoder"); } public Domain Break (APC pc, Domain data) { return data; } public Domain Call (APC pc, Method method, bool virt, TypeList extraVarargs, int dest, ArgList args, Domain data) where TypeList : IIndexable where ArgList : IIndexable { TypeNode declaringType = MetaDataProvider.DeclaringType (method); if (data.OldDomain == null) return CallEffect (pc, method, virt, extraVarargs, dest, args, data, declaringType, false); data.OldDomain = CallEffect (pc, method, virt, extraVarargs, dest, args, data.OldDomain, declaringType, false); if (!MetaDataProvider.IsVoidMethod (method)) data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true); return data; } public Domain Calli (APC pc, TypeNode returnType, TypeList argTypes, bool instance, int dest, int functionPointer, ArgList args, Domain data) where TypeList : IIndexable where ArgList : IIndexable { if (data.OldDomain == null) return CalliEffect (pc, returnType, argTypes, instance, dest, functionPointer, args, data); data.OldDomain = CalliEffect (pc, returnType, argTypes, instance, dest, functionPointer, args, data.OldDomain); if (!MetaDataProvider.IsVoid (returnType)) data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true); return data; } public Domain CheckFinite (APC pc, int dest, int source, Domain data) { data.Copy (dest, source); if (data.OldDomain != null) data.OldDomain.Copy (dest, source); return data; } public Domain CopyBlock (APC pc, int destAddress, int srcAddress, int len, Domain data) { data.Havoc (destAddress); data.Havoc (srcAddress); data.Havoc (len); return data; } public Domain EndFilter (APC pc, int decision, Domain data) { data.Havoc (decision); return data; } public Domain EndFinally (APC pc, Domain data) { return data; } public Domain Jmp (APC pc, Method method, Domain data) { return data; } public Domain LoadArg (APC pc, Parameter argument, bool isOld, int dest, Domain data) { LoadArgEffect (argument, isOld, dest, data); if (data.OldDomain != null) LoadArgEffect (argument, isOld, dest, data.OldDomain); return data; } public Domain LoadArgAddress (APC pc, Parameter argument, bool isOld, int dest, Domain data) { LoadArgAddressEffect (argument, isOld, dest, data); if (data.OldDomain != null) LoadArgAddressEffect (argument, isOld, dest, data.OldDomain); return data; } public Domain LoadLocal (APC pc, Local local, int dest, Domain data) { LoadLocalEffect (local, dest, data); if (data.OldDomain != null) data.CopyValueToOldState (data.OldDomain.BeginOldPC, MetaDataProvider.LocalType (local), dest, dest, data.OldDomain); return data; } public Domain LoadLocalAddress (APC pc, Local local, int dest, Domain data) { LoadLocalAddressEffect (local, dest, data); if (data.OldDomain != null) LoadLocalAddressEffect (local, dest, data.OldDomain); return data; } public Domain Nop (APC pc, Domain data) { return data; } public Domain Pop (APC pc, int source, Domain data) { data.Havoc (source); if (data.OldDomain != null) data.OldDomain.Havoc (source); return data; } public Domain Return (APC pc, int source, Domain data) { data.Havoc (source); return data; } public Domain StoreArg (APC pc, Parameter argument, int source, Domain data) { data.CopyValue (data.Address (argument), data.Address (source), MetaDataProvider.ManagedPointer (MetaDataProvider.ParameterType (argument))); data.Havoc (source); return data; } public Domain StoreLocal (APC pc, Local local, int source, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.StoreLocalEffect (local, source, d)); } public Domain Switch (APC pc, TypeNode type, IEnumerable> cases, int value, Domain data) { throw new InvalidOperationException ("Should only see assumes"); } public Domain Box (APC pc, TypeNode type, int dest, int source, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, (d) => it.BoxEffect (type, dest, source, d)); } public Domain ConstrainedCallvirt (APC pc, Method method, TypeNode constraint, TypeList extraVarargs, int dest, ArgList args, Domain data) where TypeList : IIndexable where ArgList : IIndexable { if (data.OldDomain == null) return CallEffect (pc, method, true, extraVarargs, dest, args, data, constraint, true); data.OldDomain = CallEffect (pc, method, true, extraVarargs, dest, args, data.OldDomain, constraint, true); if (!MetaDataProvider.IsVoidMethod (method)) data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true); return data; } public Domain CastClass (APC pc, TypeNode type, int dest, int obj, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.CastClassEffect (type, dest, obj, d)); } public Domain CopyObj (APC pc, TypeNode type, int destPtr, int sourcePtr, Domain data) { data.CopyValue (data.Value (destPtr), data.Value (sourcePtr), MetaDataProvider.ManagedPointer (type)); data.Havoc (destPtr); data.Havoc (sourcePtr); return data; } public Domain Initobj (APC pc, TypeNode type, int ptr, Domain data) { SymValue obj = data.Value (ptr); data.Havoc (obj); foreach (Field field in MetaDataProvider.Fields (type)) { SymValue dest = data.FieldAddress (obj, field); data.AssignZeroEquivalent (dest, MetaDataProvider.FieldType (field)); } data.Havoc (ptr); return data; } public Domain LoadElement (APC pc, TypeNode type, int dest, int array, int index, Domain data) { if (data.OldDomain != null) { LoadElementEffect (type, dest, array, index, data.OldDomain); data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true); } else LoadElementEffect (type, dest, array, index, data); return data; } public Domain LoadField (APC pc, Field field, int dest, int obj, Domain data) { if (data.OldDomain != null) { LoadFieldEffect (field, dest, obj, data.OldDomain); data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true); } else LoadFieldEffect (field, dest, obj, data); return data; } public Domain LoadFieldAddress (APC pc, Field field, int dest, int obj, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, domain => it.LoadFieldAddressEffect (pc, field, dest, obj, domain)); } public Domain LoadLength (APC pc, int dest, int array, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, domain => it.LoadLengthEffect (dest, array, domain)); } public Domain LoadStaticField (APC pc, Field field, int dest, Domain data) { if (data.OldDomain != null) { LoadStaticFieldEffect (field, dest, data.OldDomain); data.OldDomain.CopyOldValue (data.OldDomain.BeginOldPC, dest, dest, data, true); } else LoadStaticFieldEffect (field, dest, data); return data; } public Domain LoadStaticFieldAddress (APC pc, Field field, int dest, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, domain => it.LoadStaticFieldAddressEffect (field, dest, domain)); } public Domain LoadTypeToken (APC pc, TypeNode type, int dest, Domain data) { throw new NotImplementedException (); } public Domain LoadFieldToken (APC pc, Field type, int dest, Domain data) { throw new NotImplementedException (); } public Domain LoadMethodToken (APC pc, Method type, int dest, Domain data) { throw new NotImplementedException (); } public Domain NewArray (APC pc, TypeNode type, int dest, ArgList lengths, Domain data) where ArgList : IIndexable { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.NewArrayEffect (type, dest, lengths, d)); } public Domain NewObj (APC pc, Method ctor, int dest, ArgList args, Domain data) where ArgList : IIndexable { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.NewObjEffect (pc, ctor, dest, args, d)); } public Domain MkRefAny (APC pc, TypeNode type, int dest, int obj, Domain data) { throw new NotImplementedException (); } public Domain RefAnyType (APC pc, int dest, int source, Domain data) { throw new NotImplementedException (); } public Domain RefAnyVal (APC pc, TypeNode type, int dest, int source, Domain data) { throw new NotImplementedException (); } public Domain Rethrow (APC pc, Domain data) { return data.Bottom; } public Domain StoreElement (APC pc, TypeNode type, int array, int index, int value, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => it.StoreElementEffect (type, array, index, value, d)); } public Domain StoreField (APC pc, Field field, int obj, int value, Domain data) { data.CopyValue (data.FieldAddress (data.Value (obj), field), data.Address (value)); if (!MetaDataProvider.IsCompilerGenerated (field)) data.HavocPseudoFields (data.Value (obj)); data.Havoc (obj); data.Havoc (value); return data; } public Domain StoreStaticField (APC pc, Field field, int value, Domain data) { data.CopyValue (data.FieldAddress (data.Globals, field), data.Address (value)); data.Havoc (value); return data; } public Domain Throw (APC pc, int exception, Domain data) { data.Havoc (exception); return data; } public Domain Unbox (APC pc, TypeNode type, int dest, int obj, Domain data) { AnalysisDecoder it = this; return DoWithBothDomains (data, d => d.AssignValue (dest, it.MetaDataProvider.ManagedPointer (type))); } public Domain UnboxAny (APC pc, TypeNode type, int dest, int obj, Domain data) { return DoWithBothDomains (data, d => d.AssignValue (dest, type)); } #endregion private void MaterializeParameter (Parameter parameter, TypeNode declaringType, Domain data, bool aggressiveMaterialization) { TypeNode type = MetaDataProvider.ParameterType (parameter); data.Assign (parameter, type); MaterializeParameterInfo (data.Address (parameter), MetaDataProvider.ManagedPointer (type), 0, data, declaringType, aggressiveMaterialization); data.CopyParameterIntoShadow (parameter); } private void MaterializeParameterInfo (SymValue sv, TypeNode t, int depth, Domain data, TypeNode fromType, bool aggressiveMaterialization) { data.MakeUnmodified (sv); data.SetType (sv, t); if (depth > 2 && !aggressiveMaterialization || depth > 5) return; if (MetaDataProvider.IsManagedPointer (t)) { TypeNode elemType = MetaDataProvider.ElementType (t); if (!MetaDataProvider.HasValueRepresentation (elemType)) { data.ManifestStructId (sv); foreach (Field field in MetaDataProvider.Fields (elemType)) { if (!MetaDataProvider.IsStatic (field) && MetaDataProvider.IsVisibleFrom (field, fromType)) { TypeNode fieldAddressType; MaterializeParameterInfo (data.FieldAddress (sv, field, out fieldAddressType), fieldAddressType, depth + 1, data, fromType, aggressiveMaterialization); } } ManifestProperties (sv, depth + 1, data, fromType, aggressiveMaterialization, elemType); } else MaterializeParameterInfo (data.Value (sv), elemType, depth + 1, data, fromType, aggressiveMaterialization); } else { if (MetaDataProvider.IsClass (t)) { foreach (Field field in MetaDataProvider.Fields (t)) { if (!MetaDataProvider.IsStatic (field) && MetaDataProvider.IsVisibleFrom (field, fromType)) { TypeNode fieldAddressType; MaterializeParameterInfo (data.FieldAddress (sv, field, out fieldAddressType), fieldAddressType, depth + 1, data, fromType, aggressiveMaterialization); } } } else if (data.NeedsArrayLengthManifested (t)) data.ManifestArrayLength (sv); } } private void ManifestProperties (SymValue sv, int depth, Domain data, TypeNode fromType, bool aggressiveMaterialization, TypeNode type) { foreach (Property property in MetaDataProvider.Properties (type)) { Method getter; if (MetaDataProvider.IsStatic (property) || !MetaDataProvider.HasGetter (property, out getter) || !MetaDataProvider.IsVisibleFrom (getter, fromType)) continue; TypeNode pseudoFieldAddressType; MaterializeParameterInfo (data.PseudoFieldAddress (sv, getter, out pseudoFieldAddressType, false), pseudoFieldAddressType, depth + 1, data, fromType, aggressiveMaterialization); } if (!MetaDataProvider.IsInterface (type)) return; foreach (TypeNode iface in MetaDataProvider.Interfaces (type)) { if (MetaDataProvider.IsVisibleFrom (iface, fromType)) ManifestProperties (sv, depth, data, fromType, aggressiveMaterialization, iface); } } private void MaterializeLocal (Local local, Method method, Domain data) { TypeNode t = MetaDataProvider.LocalType (local); data.AssignZeroEquivalent (data.Address (local), t); } private void HavocParameters (APC pc, Method method, IIndexable extraVarargs, IIndexable args, Domain data, TypeNode declaringType, bool insideConstructor, bool thisArgMissing, bool derefThis) { IIndexable parameters = MetaDataProvider.Parameters (method); IIndexable unspecializedParameters = null; if (MetaDataProvider.IsSpecialized (method)) unspecializedParameters = MetaDataProvider.Parameters (MetaDataProvider.Unspecialized (method)); int index2 = 0; int num1 = 0; for (int index1 = 0; index1 < args.Count; ++index1) { bool materialize = false; bool nonFirstThis = false; int num2 = args [index1]; bool parameterHasGenericType = false; bool havocReadonlyFields = false; TypeNode ype; if (index1 == 0 && !thisArgMissing && !MetaDataProvider.IsStatic (method)) { num1 = 1; ype = MetaDataProvider.ParameterType (MetaDataProvider.This (method)); if (MetaDataProvider.IsPrimitive (declaringType) || MetaDataProvider.Equal (declaringType, MetaDataProvider.System_Object)) { if (MetaDataProvider.IsStruct (declaringType)) data.Value (data.Value (args [0])); continue; } if (MetaDataProvider.IsConstructor (method)) { if (insideConstructor && data.IsThis (this.parent.CurrentMethod, num2)) { if (TypesEqualModuloInstantiation (declaringType, MetaDataProvider.DeclaringType (this.parent.CurrentMethod))) havocReadonlyFields = true; else continue; } if (MetaDataProvider.IsStruct (declaringType)) materialize = true; } } else if (index2 < parameters.Count) { if (data.IsThis (this.parent.CurrentMethod, num2)) nonFirstThis = true; Parameter p = parameters [index2]; materialize = MetaDataProvider.IsOut (p); ype = MetaDataProvider.ParameterType (p); if (unspecializedParameters != null) { TypeNode unspecType = MetaDataProvider.ParameterType (unspecializedParameters [index2]); parameterHasGenericType = MetaDataProvider.IsFormalTypeParameter (unspecType) || MetaDataProvider.IsMethodFormalTypeParameter (unspecType); } ++index2; } else if (!data.IsThis (this.parent.CurrentMethod, num2)) ype = extraVarargs [index1 - index2 - num1]; else continue; if (!pc.InsideContract) { bool havocFields = AggressiveUpHavocMethod (method); if (havocFields || materialize || MustHavocParameter (method, declaringType, ype, parameterHasGenericType, nonFirstThis)) { SymValue loc = data.Value (num2); if (derefThis && index1 == 0 && num1 == 1) loc = data.Value (loc); data.HavocObjectAtCall (loc, ref data.ModifiedAtCall, havocFields, havocReadonlyFields); if (materialize) data.MaterializeAccordingToType (loc, ype, 0); } } data.Havoc (num2); } } private bool MustHavocParameter (Method method, TypeNode declaringType, TypeNode pt, bool parameterHasGenericType, bool nonFirstThis) { if (parameterHasGenericType || MetaDataProvider.IsStruct (pt) || MetaDataProvider.Equal (declaringType, MetaDataProvider.System_Object) || IsImmutable (pt) || nonFirstThis || MetaDataProvider.Equal (pt, MetaDataProvider.System_Object)) return false; return true; } private bool IsImmutable (TypeNode pt) { return MetaDataProvider.Equal (pt, MetaDataProvider.System_String); } private bool AggressiveUpHavocMethod (Method method) { if (MetaDataProvider.Name (MetaDataProvider.DeclaringType (method)) != "Monitor") return false; string name = MetaDataProvider.Name (method); return (name == "Exit" || name == "Wait"); } private bool TypesEqualModuloInstantiation (TypeNode a, TypeNode b) { a = MetaDataProvider.Unspecialized (a); b = MetaDataProvider.Unspecialized (b); return MetaDataProvider.Equal (a, b); } private SymValue KeyForPureFunctionArgument (Method method, int index, int arg, Domain data, IImmutableMap specialization, out bool isOut) { bool isByRef; TypeNode type; bool isPrimitive; if (!ParameterHasValueRepresentation (method, index, specialization, out isPrimitive, out isOut, out isByRef, out type)) return data.StructId (isByRef ? data.Value (arg) : data.Address (arg)); SymValue sv = data.Value (arg); if (isByRef) sv = data.Value (sv); return isPrimitive || IsImmutableType (type) ? sv : data.ObjectVersion (sv); } private bool ParameterHasValueRepresentation (Method method, int index, IImmutableMap specialization, out bool isPrimitive, out bool isOut, out bool isByRef, out TypeNode type) { if (index == 0 && !MetaDataProvider.IsStatic (method)) { isOut = false; type = MetaDataProvider.DeclaringType (method); isPrimitive = MetaDataProvider.IsPrimitive (type); bool hasValueRepresentation = MetaDataProvider.HasValueRepresentation (type); isByRef = (isPrimitive || !hasValueRepresentation); return hasValueRepresentation; } int paramIndex = MetaDataProvider.IsStatic (method) ? index : (index - 1); Parameter p = MetaDataProvider.Parameters (method) [paramIndex]; type = MetaDataProvider.ParameterType (p); type = Specialize (specialization, type); isOut = MetaDataProvider.IsOut (p); if (isByRef = MetaDataProvider.IsManagedPointer (type)) type = MetaDataProvider.ElementType (type); isPrimitive = MetaDataProvider.IsPrimitive (type); return MetaDataProvider.HasValueRepresentation (type); } private bool IsImmutableType (TypeNode type) { //todo: implement return false; } private int GetNonOutArgs (Method method) { int res = MetaDataProvider.IsStatic (method) ? 1 : 0; IIndexable parameters = MetaDataProvider.Parameters (method); for (int i = 0; i < parameters.Count; ++i) { if (!MetaDataProvider.IsOut (parameters [i])) ++res; } return res; } private void AssignAllOutParameters (Domain data, SymValue fieldAddr, Method method, ArgList args) where ArgList : IIndexable { int index = 0; if (!MetaDataProvider.IsStatic (method)) ++index; IIndexable parameters = MetaDataProvider.Parameters (method); for (; index < parameters.Count; index++) { Parameter p = parameters [index]; if (MetaDataProvider.IsOut (p)) { TypeNode pType = MetaDataProvider.ParameterType (p); SymValue srcAddr = data.PseudoFieldAddressOfOutParameter (index, fieldAddr, pType); SymValue destAddr = data.Value (args [index]); data.CopyValue (destAddr, srcAddr, pType); } } } private TypeNode Specialize (IImmutableMap instantiationMap, TypeNode declaringType) { throw new NotImplementedException (); } private void DevirtualizeImplementingMethod (TypeNode declaringType, ref Method method) { throw new NotImplementedException (); } private IImmutableMap ComputeTypeInstantiationMap (APC pc, Method method) { IImmutableMap specialization = ImmutableMap.Empty; foreach (var edge in pc.SubroutineContext.AsEnumerable ()) { Method calledMethod; bool isVirtual; bool isNewObj; if (edge.From.IsMethodCallBlock (out calledMethod, out isNewObj, out isVirtual)) MetaDataProvider.IsSpecialized (calledMethod, ref specialization); else if (edge.To.IsMethodCallBlock (out calledMethod, out isNewObj, out isVirtual)) MetaDataProvider.IsSpecialized (calledMethod, ref specialization); } return specialization; } private Domain CalliEffect (APC pc, TypeNode returnType, TypeList argTypes, bool isInstance, int dest, int functionPointer, ArgList args, Domain data) where TypeList : IIndexable where ArgList : IIndexable { for (int i = 0; i < args.Count; i++) { int num = args [i]; TypeNode type; if (isInstance) { if (i > 0) type = argTypes [i - 1]; else { SymValue sv = data.Value (num); AbstractType aType = data.GetType (sv); type = aType.IsNormal() ? aType.ConcreteType : MetaDataProvider.System_Object; } } else type = argTypes [i]; if (!MetaDataProvider.IsStruct (type)) { data.ResetModifiedAtCall (); data.HavocObjectAtCall (data.Value (num), ref data.ModifiedAtCall, false, false); } data.Havoc (num); } data.AssignValue (dest, returnType); return data; } private void LoadArgAddressEffect (Parameter p, bool isOld, int dest, Domain data) { SymValue srcAddr = isOld ? data.OldValueAddress (p) : data.Address (p); data.CopyAddress (data.Address (dest), srcAddr, MetaDataProvider.ManagedPointer (MetaDataProvider.ParameterType (p))); } private void LoadLocalAddressEffect (Local local, int dest, Domain data) { data.CopyAddress (data.Address (dest), data.Address (local), MetaDataProvider.ManagedPointer (MetaDataProvider.LocalType (local))); } private void BoxEffect (TypeNode type, int dest, int source, Domain data) { if (MetaDataProvider.IsReferenceType (type)) data.Copy (dest, source); else { SymValue srcAddr = data.Address (source); TypeNode systemObject = MetaDataProvider.System_Object; SymValue specialUnary = data.GetSpecialUnary (data.Functions.BoxOperator, source, systemObject); data.SetValue (specialUnary, srcAddr, MetaDataProvider.ManagedPointer (type), false); data.AssignSpecialUnary (dest, specialUnary, systemObject); } } private void CastClassEffect (TypeNode type, int dest, int obj, Domain data) { SymValue destAddr = data.Address (dest); TypeNode mp = MetaDataProvider.ManagedPointer (type); data.CopyValueAndCast (destAddr, data.Address (obj), mp); } private void LoadElementEffect (TypeNode type, int dest, int array, int index, Domain data) { TypeNode t = type; if (!MetaDataProvider.IsStruct (type)) { SymValue sv = data.Value (array); AbstractType aType = data.GetType (sv); if (aType.IsNormal() && MetaDataProvider.IsArray (aType.ConcreteType)) { t = MetaDataProvider.ElementType (aType.ConcreteType); if (t == null) t = type; } } TypeNode elementAddressType = MetaDataProvider.ManagedPointer (t); data.CopyValue (data.Address (dest), data.ElementAddress (data.Value (array), data.Value (index), elementAddressType), elementAddressType); data.Havoc (index); } private void LoadFieldEffect (Field field, int dest, int obj, Domain data) { SymValue ptr; if (MetaDataProvider.IsStruct (MetaDataProvider.DeclaringType (field))) { AbstractType abstractType = data.GetType (data.Address (obj)); ptr = abstractType.IsNormal() && MetaDataProvider.IsManagedPointer (abstractType.ConcreteType) && MetaDataProvider.IsStruct (MetaDataProvider.ElementType (abstractType.ConcreteType)) ? data.Address (obj) : data.Value (obj); } else ptr = data.Value (obj); TypeNode fieldAddressType; SymValue srcAddr = data.FieldAddress (ptr, field, out fieldAddressType); data.CopyValue (data.Address (dest), srcAddr, fieldAddressType); } private void LoadFieldAddressEffect (APC pc, Field field, int dest, int obj, Domain data) { SymValue sv = data.Value (obj); TypeNode fieldAddressType; SymValue srcAddr = data.FieldAddress (sv, field, out fieldAddressType); data.CopyAddress (data.Address (dest), srcAddr, fieldAddressType); if (!pc.InsideContract && MetaDataProvider.Equal (MetaDataProvider.DeclaringType (this.parent.CurrentMethod), MetaDataProvider.Unspecialized (MetaDataProvider.DeclaringType (field)))) data.HavocPseudoFields (this.parent.StackContextProvider.MethodContext.AffectedGetters (field), sv); } private void LoadLengthEffect (int dest, int array, Domain data) { data.AssignArrayLength (data.Address (dest), data.Value (array)); } private void LoadStaticFieldEffect (Field field, int dest, Domain data) { TypeNode fieldAddressType; SymValue srcAddr = data.FieldAddress (data.Globals, field, out fieldAddressType); data.CopyValue (data.Address (dest), srcAddr, fieldAddressType); } private void LoadStaticFieldAddressEffect (Field field, int dest, Domain data) { TypeNode fieldAddressType; SymValue srcAddr = data.FieldAddress (data.Globals, field, out fieldAddressType); data.CopyAddress (data.Address (dest), srcAddr, fieldAddressType); } private void NewArrayEffect (TypeNode type, int dest, IIndexable list, Domain data) { if (list.Count == 1) { SymValue array = data.CreateArray (type, data.Value (list [0])); data.CopyAddress (data.Address (dest), array, MetaDataProvider.ArrayType (type, 1)); } else data.AssignValue (dest, type); } private void NewObjEffect (APC pc, Method ctor, int dest, ArgList args, Domain data) where ArgList : IIndexable { for (int i = 0; i < args.Count; ++i) data.Havoc (args [i]); TypeNode declaringType = MetaDataProvider.DeclaringType (ctor); if (MetaDataProvider.IsStruct (declaringType)) { SymValue srcAddr = data.CreateValue (declaringType); data.MaterializeAccordingToType (srcAddr, MetaDataProvider.ManagedPointer (declaringType), 0); HavocParameters (pc, ctor, Indexable.Empty, args, data, declaringType, false, true, false); data.CopyValue (data.Address (dest), srcAddr, MetaDataProvider.ManagedPointer (declaringType)); return; } SymValue sv = data.CreateObject (declaringType); HavocParameters (pc, ctor, Indexable.Empty, args, data, declaringType, false, true, false); data.CopyAddress (data.Address (dest), sv, declaringType); } private void StoreElementEffect (TypeNode type, int array, int index, int value, Domain data) { TypeNode elementAddressType = MetaDataProvider.ManagedPointer (type); SymValue arrayValue = data.Value (array); SymValue indexValue = data.Value (index); data.HavocArrayAtIndex (arrayValue, indexValue); data.CopyValue (data.ElementAddress (arrayValue, indexValue, elementAddressType), data.Address (value), elementAddressType); data.Havoc (array); data.Havoc (index); data.Havoc (value); } public static Domain FindOldState (APC pc, Domain data) { for (Sequence> list = pc.SubroutineContext; list != null; list = list.Tail) { Edge pair = list.Head; if (pair.Tag == EdgeTag.Exit || pair.Tag.Is (EdgeTag.AfterMask)) return data.GetStateAt (new APC (pair.From.Subroutine.EntryAfterRequires, 0, list.Tail)); } return null; } } }