/// <summary> /// Accepts a field in the form "assemblyname#typename#fieldname" and returns the actual field /// </summary> /// <param name="Field"></param> /// <returns></returns> public static bool TryGetFieldFromPersistentStringForm(IPexComponent host, string fstr, out Field field) { field = null; var splitarr = fstr.Split(new char[] { PexMeConstants.PexMePersistenceFormSeparator }); SafeDebug.Assume(splitarr.Length == 3, "Incorrect persistent store field name"); var assemblyname = splitarr[0]; var typename = splitarr[1]; var signature = splitarr[2]; FieldDefinition fdef; if (!TryGetFieldDefinition(host, assemblyname, typename, signature, out fdef)) { return(false); } TypeDefinition tdef; if (!fdef.TryGetDeclaringType(out tdef)) { return(false); } field = fdef.Instantiate(GetGenericTypeParameters(host, tdef)); return(true); }
public static string GeneratePUTCommand(Method putmethod) { TypeEx classdef; bool bresult = putmethod.TryGetDeclaringType(out classdef); SafeDebug.Assume(bresult, "Declaring type cannot be null"); var assemblyEx = classdef.Definition.Module.Assembly; var assemblyName = assemblyEx.Location; var namespacestr = classdef.Namespace; StringBuilder sb = new StringBuilder(); sb.Append("pex.exe "); sb.Append(assemblyName); sb.Append(" /nf:"); sb.Append(namespacestr); sb.Append(" /tf:"); sb.Append(classdef.ShortName.ToString() + "!"); sb.Append(" /mf:"); sb.Append(putmethod.ShortName.ToString() + "!"); sb.Append(" /nor"); sb.Append(" /rn:"); sb.Append(classdef.ShortName.ToString() + "_" + putmethod.ShortName.ToString()); if (PexMeConstants.ENABLE_DEBUGGING_MODE) { sb.Append(" /bos"); } sb.Append(" /fullmscorlib"); return(sb.ToString()); }
/// <summary> /// Gets a value indicating if the bitness is supported /// </summary> /// <param name="bitness">The bitness.</param> /// <returns>True if supported.</returns> public override bool SupportsProjectBitness(Bitness bitness) { SafeDebug.Assume(bitness != Bitness.Unsupported, "bitness != Bitness.Unsupported"); if (Net2process) { return(bitness == Bitness.AnyCpu || bitness == Bitness.x86); } else { return(true); } }
GetPersistentFieldDictionary(SafeDictionary <Field, FieldStore> fielddic) { var pfielddic = new System.Collections.Generic.Dictionary <string, PersistentFieldStore>(); foreach (var field in fielddic.Keys) { var fieldstr = MethodOrFieldAnalyzer.GetPersistentStringFormOfField(field); PersistentFieldStore pfs; bool bresult = PersistentFieldStore.TryGetPersistentFieldStore(this.host, fielddic[field], out pfs); SafeDebug.Assume(bresult, "Failed to get persistent field store!!!"); pfielddic[fieldstr] = pfs; } return(pfielddic); }
public MethodEffects(IFiniteSet <Field> writtenInstanceFields, IFiniteSet <Field> directSetFields, IFiniteSet <Method> directCalledMethods, IFiniteSet <Field> returnFields, SafeDictionary <Field, FieldModificationType> modificationTypeDic, int callDepth) { SafeDebug.AssumeNotNull(writtenInstanceFields, "writtenInstanceFields"); SafeDebug.Assume(callDepth >= 0, "callDepth>=0"); this.WrittenInstanceFields = writtenInstanceFields; this.DirectSetterFields = directSetFields; this.DirectCalledMethods = directCalledMethods; this.ReturnFields = returnFields; this.ModificationTypeDictionary = modificationTypeDic; this.CallDepth = callDepth; }
GetPersistentMethodDictionary(SafeDictionary <Method, MethodStore> methoddic) { var pmethoddic = new System.Collections.Generic.Dictionary <string, PersistentMethodStore>(); foreach (var method in methoddic.Keys) { var methodstr = MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(method); PersistentMethodStore pms; bool bresult = PersistentMethodStore.TryGetPersistentMethodStore(methoddic[method], out pms); SafeDebug.Assume(bresult, "Failed to get persistent method store!!!"); pmethoddic[methodstr] = pms; } return(pmethoddic); }
/// <summary> /// Function the retrieves associated Persistent store for each MethodStore /// </summary> /// <param name="ms"></param> /// <param name="pms"></param> /// <returns></returns> public static bool TryGetPersistentFieldStore(IPexComponent host, FieldStore fs, out PersistentFieldStore pfs) { pfs = new PersistentFieldStore(); pfs.FieldName = MethodOrFieldAnalyzer.GetPersistentStringFormOfField(fs.FieldName); //foreach(var value in fs.FieldValues) // pfs.FieldValues.Add(value); //TODO: Performance can be improved via caching over here foreach (var m in fs.ReadMethods) { pfs.ReadMethods.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(m)); } foreach (var typeex in fs.WriteMethods.Keys) { HashSet <string> wmethods = new HashSet <string>(); pfs.WriteMethods.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfTypeEx(typeex), wmethods); SafeSet <Method> methods; bool bresult = fs.WriteMethods.TryGetValue(typeex, out methods); SafeDebug.Assume(bresult, "Failed to get associated set of methods for a type"); var assemblyname = typeex.Definition.Module.Assembly.Location; var typename = typeex.FullName; foreach (var m in methods) { wmethods.Add(assemblyname + PexMeConstants.PexMePersistenceFormSeparator + typename + PexMeConstants.PexMePersistenceFormSeparator + MethodOrFieldAnalyzer.GetMethodSignature(m)); } } foreach (var m in fs.ModificationTypeDictionary.Keys) { var value = fs.ModificationTypeDictionary[m]; pfs.ModificationTypeDictionary.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(m), value); } foreach (var m in fs.PreciseModificationTypeDictionary.Keys) { var value = fs.PreciseModificationTypeDictionary[m]; pfs.PreciseModificationTypeDictionary.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(m), value); } return(true); }
internal SafeSet <Method> FilterCallingMethodsBasedOnField(Method tmw, Field field, SafeSet <Method> callingMethods) { SafeSet <Method> filteredMethods = new SafeSet <Method>(); foreach (var callingm in callingMethods) { //Filter the calling method based on the field MethodBodyEx body; if (!callingm.TryGetBody(out body) || !body.HasInstructions) { continue; } int offset = 0; Instruction instruction; bool bContinueWithNextMethod = false; Field lastAccessedField = null; while (body.TryGetInstruction(offset, out instruction) && !bContinueWithNextMethod) { SafeDebug.AssumeNotNull(instruction, "instruction"); OpCode opCode = instruction.OpCode; if (opCode == OpCodes.Ldfld || opCode == OpCodes.Ldflda) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField"); lastAccessedField = instruction.Field; } else if (opCode == OpCodes.Call || opCode == OpCodes.Callvirt) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineMethod, "opCode.OperandType == OperandType.InlineMethod"); Method methodinner = instruction.Method; if (methodinner == tmw && field == lastAccessedField) { filteredMethods.Add(callingm); bContinueWithNextMethod = true; } lastAccessedField = null; } offset = instruction.NextOffset; } } return(filteredMethods); }
private static SafeDictionary <Field, FieldStore> GetFieldDictionary(IPexComponent host, System.Collections.Generic.Dictionary <string, PersistentFieldStore> pfielddic) { var fielddic = new SafeDictionary <Field, FieldStore>(); foreach (var fieldstr in pfielddic.Keys) { Field field; bool bresult = MethodOrFieldAnalyzer.TryGetFieldFromPersistentStringForm(host, fieldstr, out field); SafeDebug.Assume(bresult, "Failed to get field from persistent store!!!"); FieldStore fs; bresult = PersistentFieldStore.TryGetFieldStore(host, pfielddic[fieldstr], out fs); SafeDebug.Assume(bresult, "Failed to get field store!!!"); fielddic[field] = fs; } return(fielddic); }
/// <summary> /// Returns a method call for a PUT. This should be of certain characteristics, /// It should contain only one method call as generated by us /// </summary> /// <param name="putmethod"></param> /// <returns></returns> public static bool TryRetrieveMethodCall(Method putmethod, out Method assocmethod) { SafeDebug.AssumeNotNull(putmethod, "putmethod"); assocmethod = null; MethodBodyEx mbodyex; bool bresult = putmethod.TryGetBody(out mbodyex); SafeDebug.Assert(bresult, "Failed to get the body"); int offset = 0; Instruction instruction; List <Method> allCalledMethods = new List <Method>(); while (mbodyex.TryGetInstruction(offset, out instruction)) { SafeDebug.AssumeNotNull(instruction, "instruction"); OpCode opCode = instruction.OpCode; if (opCode == OpCodes.Call || opCode == OpCodes.Callvirt) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineMethod, "opCode.OperandType == OperandType.InlineMethod"); allCalledMethods.Add(instruction.Method); } offset = instruction.NextOffset; } if (allCalledMethods.Count != 1) { return(false); } assocmethod = allCalledMethods[0]; return(true); }
/// <summary> /// Accepts a type in the form "assemblyname#typename" and returns the type name /// </summary> /// <param name="Field"></param> /// <returns></returns> public static bool TryGetTypeExFromPersistentStringForm(IPexComponent host, string typename, out TypeEx typeEx) { typeEx = null; var splitarr = typename.Split(new char[] { PexMeConstants.PexMePersistenceFormSeparator }); SafeDebug.Assume(splitarr.Length == 2, "Incorrect persistent store type name"); try { bool result = TryGetTypeExFromName(host, splitarr[0], splitarr[1], out typeEx); if (typeEx == null || !result) { return(false); } return(true); } catch (Exception) { return(false); } }
/// <summary> /// Computes method effects statically. All written fields of a method. /// Can be imprecise and conservative /// </summary> /// <param name="declaringType"></param> /// <param name="method"></param> /// <param name="effects"></param> /// <returns></returns> public static bool TryComputeMethodEffects(IPexComponent host, TypeEx declaringType, Method method, SafeSet <Method> visitedMethods, out MethodEffects effects) { SafeDebug.AssumeNotNull(declaringType, "declaringType"); SafeDebug.AssumeNotNull(method, "method"); try { if (visitedMethods == null) { visitedMethods = new SafeSet <Method>(); } if (visitedMethods.Contains(method)) { effects = null; return(false); } visitedMethods.Add(method); //Check whether this has been computed before var psd = host.GetService <IPexMeStaticDatabase>() as PexMeStaticDatabase; if (psd.MethodEffectsDic.TryGetValue(method.GlobalIndex, out effects)) { return(true); } var res = new SafeSet <string>(); var directSetFields = new SafeSet <string>(); var directCalledMethods = new SafeSet <Method>(); var returnFields = new SafeSet <Field>(); var modificationTypeDic = new SafeDictionary <string, FieldModificationType>(); var parameters = method.Parameters; MethodBodyEx body; if (!method.TryGetBody(out body) || !body.HasInstructions) { effects = null; return(false); } int callDepth = 0; int offset = 0; Instruction instruction; OpCode prevOpcode = OpCodes.Nop; //Stack for load instructions Field lastAccessedArrayField = null; Field lastAccessedField = null; while (body.TryGetInstruction(offset, out instruction)) { SafeDebug.AssumeNotNull(instruction, "instruction"); OpCode opCode = instruction.OpCode; if (LdcOpCodes.Contains(opCode)) { //topIsConstant = true; } else if (ConvOpCodes.Contains(opCode)) { // do not change topIsConstant } else { if (opCode == OpCodes.Stfld) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField"); Field field = instruction.Field; AddFieldToMethodEffects(host, declaringType, res, directSetFields, modificationTypeDic, prevOpcode, field, field.Type); } else if (opCode == OpCodes.Ldfld || opCode == OpCodes.Ldflda) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField"); Field accessedField = instruction.Field; if (accessedField.Type.Spec == TypeSpec.SzArray) { lastAccessedArrayField = accessedField; } else { lastAccessedField = accessedField; } } else if (StElemOpCodes.Contains(opCode)) { if (lastAccessedArrayField != null) { //Indicates that there is n array type modified AddFieldToMethodEffects(host, declaringType, res, directSetFields, modificationTypeDic, prevOpcode, lastAccessedArrayField, lastAccessedArrayField.Type); lastAccessedArrayField = null; } } else if (opCode == OpCodes.Call || opCode == OpCodes.Callvirt) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineMethod, "opCode.OperandType == OperandType.InlineMethod"); Method methodinner = instruction.Method; SafeDebug.AssumeNotNull(method, "method"); directCalledMethods.Add(methodinner); TypeEx methodDeclaringType; //are these function calls are within the parent types if (methodinner.TryGetDeclaringType(out methodDeclaringType) && declaringType.IsAssignableTo(methodDeclaringType)) { MethodEffects methodEffects; if (TryComputeMethodEffects(host, methodDeclaringType, methodinner, visitedMethods, out methodEffects)) { res.AddRange(methodEffects.WrittenInstanceFields); foreach (var key in methodEffects.ModificationTypeDictionary.Keys) { modificationTypeDic[key] = methodEffects.ModificationTypeDictionary[key]; } directSetFields.AddRange(methodEffects.DirectSetterFields); if (methodEffects.CallDepth > callDepth) { callDepth = methodEffects.CallDepth; } } } else { //introducing heuristics for inter-procedural static analysis if (lastAccessedField != null && lastAccessedField.Type.IsReferenceType && !(methodinner.ShortName.StartsWith("Get") || methodinner.ShortName.StartsWith("get") || methodinner.ShortName.StartsWith("Set") || methodinner.ShortName.StartsWith("set"))) { AddFieldToMethodEffects(host, declaringType, res, directSetFields, modificationTypeDic, prevOpcode, lastAccessedField, lastAccessedField.Type); } } } else if (opCode == OpCodes.Ret) { if (instruction.Field != null) { returnFields.Add(instruction.Field); } } //topIsConstant = false; } prevOpcode = opCode; offset = instruction.NextOffset; } effects = new MethodEffects((IFiniteSet <string>)res, directSetFields, directCalledMethods, returnFields, modificationTypeDic, callDepth + 1); psd.MethodEffectsDic[method.GlobalIndex] = effects; return(true); } catch (Exception ex) { host.Log.LogErrorFromException(ex, WikiTopics.MissingWikiTopic, "methodeffects", "Failed to compute method effects for method " + method.FullName + "," + ex.Message); effects = null; return(false); } }
public static TypeEx AddFieldToMethodEffects(IPexComponent host, TypeEx declaringType, SafeSet <string> res, SafeSet <string> directSetFields, SafeDictionary <string, FieldModificationType> modificationTypeDic, OpCode prevOpcode, Field field, TypeEx fieldType) { SafeDebug.AssumeNotNull(field, "field"); SafeDebug.Assume(!field.IsStatic, "!field.IsStatic"); TypeEx fieldDeclaringType; //The following check ensures that the field belongs to this class //or its base classes if (field.TryGetDeclaringType(out fieldDeclaringType) && declaringType.IsAssignableTo(fieldDeclaringType)) { res.Add(field.ShortName); FieldModificationType fmt = FieldModificationType.UNKNOWN; if (fieldType == SystemTypes.Int32 || fieldType == SystemTypes.Int64 || fieldType == SystemTypes.Int16) { if (prevOpcode == OpCodes.Add) { fmt = FieldModificationType.INCREMENT; } else if (prevOpcode == OpCodes.Sub) { fmt = FieldModificationType.DECREMENT; } else if (prevOpcode == OpCodes.Call || prevOpcode == OpCodes.Calli || prevOpcode == OpCodes.Callvirt) { fmt = FieldModificationType.METHOD_CALL; } else { host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype", "Encountered unknown modification type for integer type " + prevOpcode); } } else { if (field.Type.IsReferenceType) { if (prevOpcode == OpCodes.Ldnull) { fmt = FieldModificationType.NULL_SET; } else if (prevOpcode == OpCodes.Newarr || prevOpcode == OpCodes.Newobj) { fmt = FieldModificationType.NON_NULL_SET; } else if (LdArgOpCodes.Contains(prevOpcode)) { fmt = FieldModificationType.NON_NULL_SET; } else { fmt = FieldModificationType.METHOD_CALL; //A method call is invoked on this field, which updates this field } } else if (fieldType == SystemTypes.Bool) { if (prevOpcode == OpCodes.Ldc_I4_0) { fmt = FieldModificationType.FALSE_SET; } else if (prevOpcode == OpCodes.Ldc_I4_1) { fmt = FieldModificationType.TRUE_SET; } else { host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype", "Encountered unknown modification type for boolean type " + prevOpcode); } } } //Store the value of fmt. Sometimes, the same field //can be modified in different ways within the method, for example //setting a boolean field to both true or false. In that case, the modification //type is left as unknown FieldModificationType prevFMT; if (modificationTypeDic.TryGetValue(field.ShortName, out prevFMT)) { //There is some entry for this field if (prevFMT != FieldModificationType.UNKNOWN && prevFMT != fmt) { modificationTypeDic[field.ShortName] = FieldModificationType.UNKNOWN; } } else { modificationTypeDic[field.ShortName] = fmt; } //A heuristic based approach for aliasing analysis for checking whether the field is directly //assigned any parameters if (LdArgOpCodes.Contains(prevOpcode)) { directSetFields.Add(field.ShortName); } } return(fieldDeclaringType); }
/// <summary> /// Function that retrieves associated method store /// </summary> /// <param name="pms"></param> /// <param name="ms"></param> /// <returns></returns> public static bool TryGetFieldStore(IPexComponent host, PersistentFieldStore pfs, out FieldStore fs) { fs = new FieldStore(); bool bresult = MethodOrFieldAnalyzer.TryGetFieldFromPersistentStringForm(host, pfs.FieldName, out fs.FieldName); SafeDebug.Assume(bresult, "Failed to get field from the persistent store"); fs.FieldValues.AddRange(pfs.FieldValues); //TODO: Performance can be improved via caching over here foreach (var mname in pfs.ReadMethods) { Method m; bresult = MethodOrFieldAnalyzer.TryGetMethodFromPersistentStringForm(host, mname, out m); SafeDebug.Assume(bresult, "Failed to get method from persistent string form "); fs.ReadMethods.Add(m); } foreach (var typeex in pfs.WriteMethods.Keys) { SafeSet <Method> wmethods = new SafeSet <Method>(); TypeEx typeEx; bresult = MethodOrFieldAnalyzer.TryGetTypeExFromPersistentStringForm(host, typeex, out typeEx); SafeDebug.Assume(bresult, "Failed to get type from persistent string form " + typeex); fs.WriteMethods.Add(typeEx, wmethods); HashSet <string> methods; bresult = pfs.WriteMethods.TryGetValue(typeex, out methods); SafeDebug.Assume(bresult, "Failed to get associated set of methods for a type " + typeex); foreach (var m in methods) { Method method; bresult = MethodOrFieldAnalyzer.TryGetMethodFromPersistentStringForm(host, m, out method); SafeDebug.Assume(bresult, "Failed to get method from string form " + m); wmethods.Add(method); } } foreach (var m in pfs.ModificationTypeDictionary.Keys) { var value = pfs.ModificationTypeDictionary[m]; Method method; bresult = MethodOrFieldAnalyzer.TryGetMethodFromPersistentStringForm(host, m, out method); SafeDebug.Assume(bresult, "Failed to get method from string form " + m); fs.ModificationTypeDictionary.Add(method, value); } foreach (var m in pfs.PreciseModificationTypeDictionary.Keys) { var value = pfs.PreciseModificationTypeDictionary[m]; Method method; bresult = MethodOrFieldAnalyzer.TryGetMethodFromPersistentStringForm(host, m, out method); SafeDebug.Assume(bresult, "Failed to get method from string form " + m); fs.PreciseModificationTypeDictionary.Add(method, value); } return(true); }
/// <summary> /// The supports project bitness. /// </summary> /// <param name="bitness"> /// The bitness. /// </param> /// <returns> /// The <see cref="bool"/>. /// </returns> public override bool SupportsProjectBitness(Bitness bitness) { SafeDebug.Assume(bitness != Bitness.Unsupported, "bitness != Bitness.Unsupported"); return(true); }
/// <summary> /// Retrieves the PUT for the method we are looking for in the current assembly /// </summary> /// <param name="method"></param> /// <returns></returns> public static bool TryRetrievePUT(IPexComponent host, AssemblyEx assembly, Method method, out Method putmethod) { //Get the class name of the target class that is including //the method we are looking for TypeEx declaringType; bool bresult = method.TryGetDeclaringType(out declaringType); SafeDebug.Assume(bresult, "Failed to get the declaring type!!!"); string tclassname = null; var declaringTypeDef = declaringType.Definition; if (declaringTypeDef.GenericTypeParametersCount == 0) { tclassname = declaringType.ShortName.ToString(); } else { tclassname = declaringType.ShortName.ToString(); tclassname = tclassname.Substring(0, tclassname.IndexOf('`')); foreach (var param in declaringTypeDef.GenericTypeParameters) { tclassname = tclassname + param.Name; } } tclassname = tclassname + "Test"; foreach (var classdef in assembly.TypeDefinitions) { if (classdef.ShortName != tclassname) { continue; } //TODO: To be more robust, we can later replace //this piece of code by actually checking whether there //is a method call to the method of the library we are looking for foreach (var mdef in classdef.DeclaredInstanceMethods) { if (mdef.ShortName == method.ShortName) { bool isPexMethod = false; foreach (var attr in mdef.DeclaredAttributes) { if (attr.SerializableName.ToString().Contains("PexMethodAttribute")) { isPexMethod = true; break; } } if (isPexMethod) { putmethod = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(host, classdef), MethodOrFieldAnalyzer.GetGenericMethodParameters(host, mdef)); return(true); } } } } putmethod = null; return(false); }
// Find out how many fields require user provided factory methods public static bool GetTargetExplorableField(IEnumerable <Field> involvedFields, out Field targetField, out TypeEx declaringType, IPexComponent host, out TypeEx targetType) { targetField = null; var allInvolvedFields = new SafeList <Field>(); allInvolvedFields.AddRange(involvedFields); int numFields = allInvolvedFields.Count; if (numFields < 1) { declaringType = null; targetType = null; return(false); } // // if (numFields == 1) // { // targetField = allInvolvedFields[0]; // if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeDefinition(host, targetField, out declaringType)) // { // declaringType = null; // return false; // } // return true; // } // allInvolvedFields.Reverse(); TypeEx prevFieldType = null; for (int count = 0; count < allInvolvedFields.Count; count++) { var currentField = allInvolvedFields[count]; // if (count + 1 < allInvolvedFields.Count) // { // prevFieldType = allInvolvedFields[count + 1].Type; // } if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeDefinition(host, currentField, out declaringType)) { host.Log.LogError(WikiTopics.MissingWikiTopic, "targetfield", "Failed to get the declaring type for the field " + currentField.FullName); ErrorLog.AppendLine("Failed to get the declaring type for the field " + currentField.FullName); targetType = null; return(false); } try { SafeDebug.Assume( prevFieldType == null || prevFieldType == declaringType || prevFieldType.IsAssignableTo(declaringType) || declaringType.IsAssignableTo(prevFieldType), "The current field type (" + declaringType + ") should be the same as the previous field type (" + prevFieldType + ")"); if (MethodOrFieldAnalyzer.IsFieldExternallyVisible(host, declaringType, currentField)) { prevFieldType = currentField.Type; continue; } } catch (Exception ex) { ErrorLog.AppendLine("Failed to compute external visibility of field " + currentField.FullName + " because of " + ex); } targetField = currentField; targetType = declaringType; return(true); } targetField = allInvolvedFields[allInvolvedFields.Count - 1]; if (!MethodOrFieldAnalyzer.TryGetDeclaringTypeDefinition(host, targetField, out declaringType)) { host.Log.LogError(WikiTopics.MissingWikiTopic, "targetfield", "Failed to get the declaring type for the field " + targetField.FullName); targetType = null; return(false); } targetType = targetField.Type; return(true); }
/// <summary> /// Function that retrieves associated method store /// </summary> /// <param name="pms"></param> /// <param name="ms"></param> /// <returns></returns> public static bool TryGetMethodStore(IPexComponent host, PersistentMethodStore pms, out MethodStore ms) { ms = new MethodStore(); bool bresult = MethodOrFieldAnalyzer.TryGetMethodFromPersistentStringForm(host, pms.methodName, out ms.methodName); SafeDebug.Assume(bresult, "Failed to get the method from persistent form " + pms.methodName); foreach (var fieldstr in pms.ReadFields) { Field field; bresult = MethodOrFieldAnalyzer.TryGetFieldFromPersistentStringForm(host, fieldstr, out field); SafeDebug.Assume(bresult, "Failed to get the field from persistent form " + fieldstr); ms.ReadFields.Add(field); } foreach (var fieldstr in pms.WriteFields) { Field field; bresult = MethodOrFieldAnalyzer.TryGetFieldFromPersistentStringForm(host, fieldstr, out field); SafeDebug.Assume(bresult, "Failed to get the field from persistent form " + fieldstr); ms.WriteFields.Add(field); } foreach (var typeexstr in pms.CallingMethods.Keys) { SafeSet <Method> wmethods = new SafeSet <Method>(); TypeEx typeEx; bresult = MethodOrFieldAnalyzer.TryGetTypeExFromPersistentStringForm(host, typeexstr, out typeEx); if (!bresult) { //No strict safedebugging cannot be added for calling methods since there //can be several dummy methods from Pex side continue; } ms.CallingMethods.Add(typeEx, wmethods); var methods = pms.CallingMethods[typeexstr]; foreach (var mstr in methods) { Method method; bresult = MethodOrFieldAnalyzer.TryGetMethodFromPersistentStringForm(host, mstr, out method); if (!bresult) { continue; } wmethods.Add(method); } } foreach (var calledMethodStr in pms.CalledMethods) { Method method; bresult = MethodOrFieldAnalyzer.TryGetMethodFromPersistentStringForm(host, calledMethodStr, out method); if (!bresult) { continue; } ms.CalledMethods.Add(method); } return(true); }
/// <summary> /// Collects defs and uses within a method /// </summary> /// <param name="td"></param> /// <param name="ade"></param> /// <param name="constructor"></param> private static void CollectDefsAndUsesInMethod(PexMeStaticDatabase psd, TypeDefinition td, DeclClassEntity ade, Method method, SafeSet <Method> visitedMethods, SideEffectStore ses) { try { if (visitedMethods == null) { visitedMethods = new SafeSet <Method>(); } if (visitedMethods.Contains(method)) { return; } visitedMethods.Add(method); MethodBodyEx body; if (!method.TryGetBody(out body) || !body.HasInstructions) { return; } int offset = 0; Instruction instruction; OpCode prevOpcode = OpCodes.Nop; //Stack for load instructions Field lastAccessedArrayField = null; SafeList <Field> lastAccessedFieldList = new SafeList <Field>(); while (body.TryGetInstruction(offset, out instruction)) { SafeDebug.AssumeNotNull(instruction, "instruction"); OpCode opCode = instruction.OpCode; if (MethodOrFieldAnalyzer.LdcOpCodes.Contains(opCode)) { //topIsConstant = true; } else if (MethodOrFieldAnalyzer.ConvOpCodes.Contains(opCode)) { // do not change topIsConstant } else { if (opCode == OpCodes.Stfld) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField"); Field field = instruction.Field; DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(field.FullName, out dfe)) { //Found a definition of the field. register the definition dfe.AddToDefList(method, offset); } } else if (opCode == OpCodes.Ldfld || opCode == OpCodes.Ldflda) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineField, "opCode.OperandType == OperandType.InlineField"); Field accessedField = instruction.Field; if (PexMeFilter.IsPrimitiveType(accessedField.Type)) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(accessedField.FullName, out dfe)) { //Found an accessor. register the usage dfe.AddToUseList(method, offset); } lastAccessedArrayField = null; } else { if (accessedField.Type.Spec == TypeSpec.SzArray) { lastAccessedArrayField = accessedField; } else { //Any access needs to be registered as use lastAccessedFieldList.Add(accessedField); } } } else if (MethodOrFieldAnalyzer.StElemOpCodes.Contains(opCode)) { if (lastAccessedArrayField != null) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(lastAccessedArrayField.FullName, out dfe)) { //Found a definition of the field. register the definition dfe.AddToDefList(method, offset); } lastAccessedArrayField = null; } } else if (MethodOrFieldAnalyzer.BranchOpCodes.Contains(opCode)) { if (lastAccessedFieldList.Count > 0) { //A field is loaded and used in conditional statement. We use the offset of conditional statement as the usage point foreach (var field in lastAccessedFieldList) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(field.FullName, out dfe)) { //Found a definition of the field. register the definition dfe.AddToUseList(method, offset); } } lastAccessedFieldList.Clear(); } if (lastAccessedArrayField != null) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(lastAccessedArrayField.FullName, out dfe)) { //Found a definition of the field. register the definition dfe.AddToUseList(method, offset); } lastAccessedArrayField = null; } } else if (opCode == OpCodes.Ret) { //A field is accessed and is returned from here if (lastAccessedFieldList.Count > 0) { foreach (var field in lastAccessedFieldList) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(field.FullName, out dfe)) { //Found a use of the field. register the definition dfe.AddToUseList(method, offset); } } lastAccessedFieldList.Clear(); } } else if (opCode == OpCodes.Call || opCode == OpCodes.Callvirt) { SafeDebug.Assume(opCode.OperandType == OperandType.InlineMethod, "opCode.OperandType == OperandType.InlineMethod"); Method methodinner = instruction.Method; SafeDebug.AssumeNotNull(method, "method"); //If this condition is not satisfied, it could be a local method call, which is dealt separately if (lastAccessedFieldList.Count != 0) { HandleMethodCall(psd, ade, method, offset, lastAccessedFieldList, methodinner, ses); lastAccessedFieldList.Clear(); } else { var shortname = methodinner.ShortName; if (shortname.StartsWith("set_")) { HandleSetterMethod(ade, method, offset, methodinner); } else if (shortname.StartsWith("get_")) { HandleGetterMethod(ade, method, offset, methodinner, lastAccessedFieldList); } } } } prevOpcode = opCode; offset = instruction.NextOffset; } } catch (Exception ex) { logger.ErrorException("Exception thrown with static analysis " + ex.StackTrace, ex); } }
private static TypeEx AddFieldToMethodEffects(IPexComponent host, TypeEx declaringType, SafeSet <Field> res, SafeSet <Field> directSetFields, SafeDictionary <Field, FieldModificationType> modificationTypeDic, OpCode prevOpcode, Field field, TypeEx fieldType) { SafeDebug.AssumeNotNull(field, "field"); SafeDebug.Assume(!field.IsStatic, "!field.IsStatic"); TypeEx fieldDeclaringType; //The following check ensures that the field belongs to this class //or its base classes if (field.TryGetDeclaringType(out fieldDeclaringType) && declaringType.IsAssignableTo(fieldDeclaringType)) { res.Add(field); var fieldTypeStr = fieldType.ToString(); if (fieldTypeStr == "System.Int32" || fieldTypeStr == "System.Int64" || fieldTypeStr == "System.Int16") { if (prevOpcode == OpCodes.Add) { modificationTypeDic[field] = FieldModificationType.INCREMENT; } else if (prevOpcode == OpCodes.Sub) { modificationTypeDic[field] = FieldModificationType.DECREMENT; } else { host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype", "Encountered unknown modification type for integer type " + prevOpcode); } } else { if (field.Type.IsReferenceType) { if (prevOpcode == OpCodes.Ldnull) { modificationTypeDic[field] = FieldModificationType.NULL_SET; } else if (prevOpcode == OpCodes.Newarr || prevOpcode == OpCodes.Newobj) { modificationTypeDic[field] = FieldModificationType.NON_NULL_SET; } else { host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype", "Encountered unknown modification type for reference type " + prevOpcode); } } else if (fieldTypeStr == "System.Boolean") { if (prevOpcode == OpCodes.Ldc_I4_0) { modificationTypeDic[field] = FieldModificationType.FALSE_SET; } else if (prevOpcode == OpCodes.Ldc_I4_1) { modificationTypeDic[field] = FieldModificationType.TRUE_SET; } else { host.Log.LogWarning(WikiTopics.MissingWikiTopic, "fieldmodificationtype", "Encountered unknown modification type for boolean type " + prevOpcode); } } } //A heuristic based approach for aliasing analysis for checking whether the field is directly //assigned any parameters if (LdArgOpCodes.Contains(prevOpcode)) { directSetFields.Add(field); } } return(fieldDeclaringType); }