/// <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> /// Gets a method store from a method signature /// </summary> /// <param name="msignature"></param> /// <param name="ms"></param> /// <returns></returns> public bool TryGetMethodStoreFromSignature(string msignature, out MethodStore ms) { foreach (var key in this.MethodDictionary.Keys) { string keysig = MethodOrFieldAnalyzer.GetMethodSignature(key); if (keysig == msignature) { ms = this.MethodDictionary[key]; return(true); } } ms = null; return(false); }
/// <summary> /// Makes a mapping relationship between a calling method and a called method /// </summary> /// <param name="callingMethod"></param> /// <param name="calledMethod"></param> public void AddMethodMapping(Method callingMethod, Method calledMethod) { //Updating the method store for calling methods MethodStore callingMethodStore = null; if (!methodDic.TryGetValue(callingMethod, out callingMethodStore)) { callingMethodStore = new MethodStore(); callingMethodStore.methodName = calledMethod; methodDic[callingMethod] = callingMethodStore; } callingMethodStore.CalledMethods.Add(calledMethod); //Updating the method store for called methods MethodStore calledMethodStore = null; if (!methodDic.TryGetValue(calledMethod, out calledMethodStore)) { calledMethodStore = new MethodStore(); calledMethodStore.methodName = calledMethod; methodDic[calledMethod] = calledMethodStore; } TypeEx callingMethodType; if (!callingMethod.TryGetDeclaringType(out callingMethodType)) { this.Log.LogError(WikiTopics.MissingWikiTopic, "methodmapping", "Failed to get the declared type for method " + calledMethod); return; } SafeSet <Method> localCallingMethods; if (!calledMethodStore.CallingMethods.TryGetValue(callingMethodType, out localCallingMethods)) { localCallingMethods = new SafeSet <Method>(); calledMethodStore.CallingMethods[callingMethodType] = localCallingMethods; } localCallingMethods.Add(callingMethod); }
/// <summary> /// Function the retrieves associated Persistent store for each MethodStore /// </summary> /// <param name="ms"></param> /// <param name="pms"></param> /// <returns></returns> public static bool TryGetPersistentMethodStore(MethodStore ms, out PersistentMethodStore pms) { pms = new PersistentMethodStore(); pms.methodName = MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(ms.methodName); //foreach (var field in ms.ReadFields) // pms.ReadFields.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfField(field)); foreach (var field in ms.WriteFields) pms.WriteFields.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfField(field)); //foreach (var typeex in ms.CallingMethods.Keys) //{ // HashSet<string> wmethods = new HashSet<string>(); // pms.CallingMethods.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfTypeEx(typeex), wmethods); // var methods = ms.CallingMethods[typeex]; // 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 calledMethod in ms.CalledMethods) // pms.CalledMethods.Add(MethodOrFieldAnalyzer.GetPersistentStringFormOfMethod(calledMethod)); return true; }
/// <summary> /// Gets calling methods of a given called method on the given field in a given target type /// </summary> /// <returns></returns> public bool TryGetCallingMethodsInType(Method calledMethod, Field field, TypeEx targetType, out SafeSet<Method> callingMethods) { SafeDebug.AssumeNotNull(calledMethod, "method"); SafeDebug.AssumeNotNull(targetType, "type"); //Get the associated property of the field Property property; if (!MethodOrFieldAnalyzer.TryGetPropertyReadingField(this, targetType, field, out property)) { //TODO: error; } MethodStore mstore = null; if (this.MethodDictionary.TryGetValue(calledMethod, out mstore)) { if (mstore.CallingMethods.TryGetValue(targetType, out callingMethods)) return true; } //No method store found. create a fresh one if (mstore == null) { mstore = new MethodStore(); mstore.methodName = calledMethod; this.MethodDictionary[calledMethod] = mstore; } callingMethods = new SafeSet<Method>(); mstore.CallingMethods[targetType] = callingMethods; TypeEx calledMethodType; if (!calledMethod.TryGetDeclaringType(out calledMethodType)) { this.Log.LogError(WikiTopics.MissingWikiTopic, "callingmethods", "Failed to get the declaring type for the method " + calledMethod.FullName); return false; } //Needs to addess the array type issue over here. var targetdef = targetType.Definition; if (targetdef == null) { if (targetType.TypeKind != TypeKind.SzArrayElements) { this.Log.LogError(WikiTopics.MissingWikiTopic, "callingmethods", "The definition for the type " + targetType.FullName + " is null"); return false; } else { targetdef = targetType.ElementType.Definition; } } //Analyze each method in the given type to identify the calling methods //of the given method foreach (var typeMethod in targetdef.DeclaredInstanceMethods) { Method minstance = typeMethod.Instantiate(targetType.GenericTypeArguments, MethodOrFieldAnalyzer.GetGenericMethodParameters(this, typeMethod)); MethodEffects meffects; if (!MethodOrFieldAnalyzer.TryComputeMethodEffects(this, targetType, minstance, null, out meffects)) continue; //Check for a direct comparison if (meffects.DirectCalledMethods.Contains(calledMethod)) callingMethods.Add(minstance); else { //Use vtable lookup for addressing the abstract issues foreach (var dcallMethod in meffects.DirectCalledMethods) { if (dcallMethod.IsConstructor) continue; TypeEx dcallMethodType; if (dcallMethod.TryGetDeclaringType(out dcallMethodType)) { if (dcallMethodType == calledMethodType || !dcallMethodType.IsAbstract || !dcallMethodType.IsInterface) continue; if (!dcallMethodType.IsAssignableTo(calledMethodType) && !calledMethodType.IsAssignableTo(dcallMethodType)) continue; } try { var lookupMethod = calledMethodType.VTableLookup(dcallMethod); if (lookupMethod != null && calledMethod == lookupMethod) { callingMethods.Add(minstance); break; } } catch (Exception ex) { this.Log.LogWarningFromException(ex, WikiTopics.MissingWikiTopic, "vtablelookup", "Failed to perform vtablelookup for " + dcallMethod.FullName + " in type " + calledMethodType.FullName); } } } } //Check whether there are any private methods in calling methods. //If yes, replace them with their callers. if (!PexMeConstants.DISABLE_CALLING_METHODS_WITHIN_CLASS) { var newCallingMethods = new SafeSet<Method>(); foreach (var callingM in callingMethods) { if (callingM.Definition.DeclaredVisibility != Visibility.Private || callingM.IsConstructor) { newCallingMethods.Add(callingM); continue; } //Get other calling methods within this type SafeSet<Method> localCM; if (this.TryGetCallingMethodsInType(callingM, field, targetType, out localCM)) { newCallingMethods.AddRange(localCM); } } callingMethods.Clear(); callingMethods.AddRange(newCallingMethods); } //Needs to further analyze parent types TypeEx baseType = targetType.BaseType; if (baseType != null && baseType.FullName != "System.Object") //TODO: Avoid string comparisons. needs to figure out how to do that { SafeSet<Method> baseCallingMethods; TryGetCallingMethodsInType(calledMethod, field, baseType, out baseCallingMethods); callingMethods.AddRange(baseCallingMethods); } return true; }
/// <summary> /// Adds a monitored field to the database. Updates two kinds of hashmaps /// a. Field to Method mapper, which gives what the methods modifying a given field /// b. Method to Field mapper, which gives what fields are modified by each method (later used to identify a minimized set of methods) /// </summary> /// <param name="tm"></param> /// <param name="method"></param> /// <param name="f"></param> /// <param name="indices"></param> /// <param name="fieldValue"></param> public void AddMonitoredField(TermManager tm, Method method, Field f, Term[] indices, Term fieldValue, Term initialValue) { string arrayIndex = ""; using (PexMeTermRewriter pexmeRewriter = new PexMeTermRewriter(tm)) { fieldValue = pexmeRewriter.VisitTerm(default(TVoid), fieldValue); //update the field value to accomodate array-type field //if (indices.Length == 0) //not an array-type field if (indices.Length == 1) //is an array-type field { arrayIndex = " at index of " + indices[0].UniqueIndex.ToString(); } if (initialValue != null) { initialValue = pexmeRewriter.VisitTerm(default(TVoid), initialValue); } } //Updating the method store MethodStore ms; if (!methodDic.TryGetValue(method, out ms)) { ms = new MethodStore(); ms.methodName = method; methodDic[method] = ms; } ms.WriteFields.Add(f); //TODO: Gather information of read fields //Updating the field store FieldStore fs; if (!fieldDic.TryGetValue(f, out fs)) { fs = new FieldStore(); fs.FieldName = f; fieldDic[f] = fs; } TypeEx declaringType; if (!method.TryGetDeclaringType(out declaringType)) { this.Log.LogError(WikiTopics.MissingWikiTopic, "monitorfield", "Failed to get the declaring type for the method " + method.FullName); return; } SafeSet <Method> writeMethods; if (!fs.WriteMethods.TryGetValue(declaringType, out writeMethods)) { writeMethods = new SafeSet <Method>(); fs.WriteMethods[declaringType] = writeMethods; } writeMethods.Add(method); var sb = new SafeStringBuilder(); var swriter = new TermSExpWriter(tm, new SafeStringWriter(sb), true, false); swriter.Write(fieldValue); sb.Append(arrayIndex); int value; if (tm.TryGetI4Constant(fieldValue, out value)) { int initialval; if (initialValue != null) { tm.TryGetI4Constant(initialValue, out initialval); } else { initialval = 0; } sb.Append(" constant value: " + value); if (f.Type.ToString() != "System.Boolean") { if (value < initialval) { fs.ModificationTypeDictionary[method] = FieldModificationType.DECREMENT; } else if (value > initialval) { fs.ModificationTypeDictionary[method] = FieldModificationType.INCREMENT; if (value == initialval + 1) { fs.PreciseModificationTypeDictionary[method] = FieldModificationType.INCREMENT_ONE; } } else { fs.ModificationTypeDictionary[method] = FieldModificationType.UNKNOWN; } } else { if (value == 0) { fs.ModificationTypeDictionary[method] = FieldModificationType.FALSE_SET; } else { fs.ModificationTypeDictionary[method] = FieldModificationType.TRUE_SET; } } } else if (tm.IsDefaultValue(fieldValue)) { if (initialValue != null && !tm.IsDefaultValue(initialValue)) { fs.ModificationTypeDictionary[method] = FieldModificationType.NULL_SET; } else { fs.ModificationTypeDictionary[method] = FieldModificationType.UNKNOWN; } sb.Append(" null reference "); } else { if (initialValue == null) { fs.ModificationTypeDictionary[method] = FieldModificationType.NON_NULL_SET; } else { fs.ModificationTypeDictionary[method] = FieldModificationType.UNKNOWN; } sb.Append(" not-null reference "); } fs.FieldValues.Add(sb.ToString()); }
/// <summary> /// Gets a method store from a method signature /// </summary> /// <param name="msignature"></param> /// <param name="ms"></param> /// <returns></returns> public bool TryGetMethodStoreFromSignature(string msignature, out MethodStore ms) { foreach (var key in this.MethodDictionary.Keys) { string keysig = MethodOrFieldAnalyzer.GetMethodSignature(key); if (keysig == msignature) { ms = this.MethodDictionary[key]; return true; } } ms = null; return false; }
/// <summary> /// Adds a monitored field to the database. Updates two kinds of hashmaps /// a. Field to Method mapper, which gives what the methods modifying a given field /// b. Method to Field mapper, which gives what fields are modified by each method (later used to identify a minimized set of methods) /// </summary> /// <param name="tm"></param> /// <param name="method"></param> /// <param name="f"></param> /// <param name="indices"></param> /// <param name="fieldValue"></param> public void AddMonitoredField(TermManager tm, Method method, Field f, Term[] indices, Term fieldValue, Term initialValue) { string arrayIndex = ""; using (PexMeTermRewriter pexmeRewriter = new PexMeTermRewriter(tm)) { fieldValue = pexmeRewriter.VisitTerm(default(TVoid), fieldValue); //update the field value to accomodate array-type field //if (indices.Length == 0) //not an array-type field if (indices.Length == 1) //is an array-type field { arrayIndex = " at index of " + indices[0].UniqueIndex.ToString(); } if(initialValue != null) initialValue = pexmeRewriter.VisitTerm(default(TVoid), initialValue); } //Updating the method store MethodStore ms; if(!methodDic.TryGetValue(method, out ms)) { ms = new MethodStore(); ms.methodName = method; methodDic[method] = ms; } ms.WriteFields.Add(f); //TODO: Gather information of read fields //Updating the field store FieldStore fs; if (!fieldDic.TryGetValue(f, out fs)) { fs = new FieldStore(); fs.FieldName = f; fieldDic[f] = fs; } TypeEx declaringType; if (!method.TryGetDeclaringType(out declaringType)) { this.Log.LogError(WikiTopics.MissingWikiTopic, "monitorfield", "Failed to get the declaring type for the method " + method.FullName); return; } SafeSet<Method> writeMethods; if (!fs.WriteMethods.TryGetValue(declaringType, out writeMethods)) { writeMethods = new SafeSet<Method>(); fs.WriteMethods[declaringType] = writeMethods; } writeMethods.Add(method); var sb = new SafeStringBuilder(); var swriter = new TermSExpWriter(tm, new SafeStringWriter(sb), true, false); swriter.Write(fieldValue); sb.Append(arrayIndex); int value; if (tm.TryGetI4Constant(fieldValue, out value)) { int initialval; if (initialValue != null) tm.TryGetI4Constant(initialValue, out initialval); else initialval = 0; sb.Append(" constant value: " + value); if (f.Type.ToString() != "System.Boolean") { if (value < initialval) fs.ModificationTypeDictionary[method] = FieldModificationType.DECREMENT; else if (value > initialval) { fs.ModificationTypeDictionary[method] = FieldModificationType.INCREMENT; if (value == initialval + 1) fs.PreciseModificationTypeDictionary[method] = FieldModificationType.INCREMENT_ONE; } else fs.ModificationTypeDictionary[method] = FieldModificationType.UNKNOWN; } else { if (value == 0) fs.ModificationTypeDictionary[method] = FieldModificationType.FALSE_SET; else fs.ModificationTypeDictionary[method] = FieldModificationType.TRUE_SET; } } else if (tm.IsDefaultValue(fieldValue)) { if (initialValue != null && !tm.IsDefaultValue(initialValue)) fs.ModificationTypeDictionary[method] = FieldModificationType.NULL_SET; else fs.ModificationTypeDictionary[method] = FieldModificationType.UNKNOWN; sb.Append(" null reference "); } else { if (initialValue == null) fs.ModificationTypeDictionary[method] = FieldModificationType.NON_NULL_SET; else fs.ModificationTypeDictionary[method] = FieldModificationType.UNKNOWN; sb.Append(" not-null reference "); } fs.FieldValues.Add(sb.ToString()); }
/// <summary> /// Makes a mapping relationship between a calling method and a called method /// </summary> /// <param name="callingMethod"></param> /// <param name="calledMethod"></param> public void AddMethodMapping(Method callingMethod, Method calledMethod) { //Updating the method store for calling methods MethodStore callingMethodStore = null; if (!methodDic.TryGetValue(callingMethod, out callingMethodStore)) { callingMethodStore = new MethodStore(); callingMethodStore.methodName = calledMethod; methodDic[callingMethod] = callingMethodStore; } callingMethodStore.CalledMethods.Add(calledMethod); //Updating the method store for called methods MethodStore calledMethodStore = null; if(!methodDic.TryGetValue(calledMethod, out calledMethodStore)) { calledMethodStore = new MethodStore(); calledMethodStore.methodName = calledMethod; methodDic[calledMethod] = calledMethodStore; } TypeEx callingMethodType; if (!callingMethod.TryGetDeclaringType(out callingMethodType)) { this.Log.LogError(WikiTopics.MissingWikiTopic, "methodmapping", "Failed to get the declared type for method " + calledMethod); return; } SafeSet<Method> localCallingMethods; if (!calledMethodStore.CallingMethods.TryGetValue(callingMethodType, out localCallingMethods)) { localCallingMethods = new SafeSet<Method>(); calledMethodStore.CallingMethods[callingMethodType] = localCallingMethods; } localCallingMethods.Add(callingMethod); }
/// <summary> /// Gets calling methods of a given called method on the given field in a given target type /// </summary> /// <returns></returns> public bool TryGetCallingMethodsInType(Method calledMethod, Field field, TypeEx targetType, out SafeSet <Method> callingMethods) { SafeDebug.AssumeNotNull(calledMethod, "method"); SafeDebug.AssumeNotNull(targetType, "type"); //Get the associated property of the field Property property; if (!MethodOrFieldAnalyzer.TryGetPropertyReadingField(this, targetType, field, out property)) { //TODO: error; } MethodStore mstore = null; if (this.MethodDictionary.TryGetValue(calledMethod, out mstore)) { if (mstore.CallingMethods.TryGetValue(targetType, out callingMethods)) { return(true); } } //No method store found. create a fresh one if (mstore == null) { mstore = new MethodStore(); mstore.methodName = calledMethod; this.MethodDictionary[calledMethod] = mstore; } callingMethods = new SafeSet <Method>(); mstore.CallingMethods[targetType] = callingMethods; TypeEx calledMethodType; if (!calledMethod.TryGetDeclaringType(out calledMethodType)) { this.Log.LogError(WikiTopics.MissingWikiTopic, "callingmethods", "Failed to get the declaring type for the method " + calledMethod.FullName); return(false); } //Needs to addess the array type issue over here. var targetdef = targetType.Definition; if (targetdef == null) { if (targetType.TypeKind != TypeKind.SzArrayElements) { this.Log.LogError(WikiTopics.MissingWikiTopic, "callingmethods", "The definition for the type " + targetType.FullName + " is null"); return(false); } else { targetdef = targetType.ElementType.Definition; } } //Analyze each method in the given type to identify the calling methods //of the given method foreach (var typeMethod in targetdef.DeclaredInstanceMethods) { Method minstance = typeMethod.Instantiate(targetType.GenericTypeArguments, MethodOrFieldAnalyzer.GetGenericMethodParameters(this, typeMethod)); MethodEffects meffects; if (!MethodOrFieldAnalyzer.TryComputeMethodEffects(this, targetType, minstance, null, out meffects)) { continue; } //Check for a direct comparison if (meffects.DirectCalledMethods.Contains(calledMethod)) { callingMethods.Add(minstance); } else { //Use vtable lookup for addressing the abstract issues foreach (var dcallMethod in meffects.DirectCalledMethods) { if (dcallMethod.IsConstructor) { continue; } TypeEx dcallMethodType; if (dcallMethod.TryGetDeclaringType(out dcallMethodType)) { if (dcallMethodType == calledMethodType || !dcallMethodType.IsAbstract || !dcallMethodType.IsInterface) { continue; } if (!dcallMethodType.IsAssignableTo(calledMethodType) && !calledMethodType.IsAssignableTo(dcallMethodType)) { continue; } } try { var lookupMethod = calledMethodType.VTableLookup(dcallMethod); if (lookupMethod != null && calledMethod == lookupMethod) { callingMethods.Add(minstance); break; } } catch (Exception ex) { this.Log.LogWarningFromException(ex, WikiTopics.MissingWikiTopic, "vtablelookup", "Failed to perform vtablelookup for " + dcallMethod.FullName + " in type " + calledMethodType.FullName); } } } } //Check whether there are any private methods in calling methods. //If yes, replace them with their callers. if (!PexMeConstants.DISABLE_CALLING_METHODS_WITHIN_CLASS) { var newCallingMethods = new SafeSet <Method>(); foreach (var callingM in callingMethods) { if (callingM.Definition.DeclaredVisibility != Visibility.Private || callingM.IsConstructor) { newCallingMethods.Add(callingM); continue; } //Get other calling methods within this type SafeSet <Method> localCM; if (this.TryGetCallingMethodsInType(callingM, field, targetType, out localCM)) { newCallingMethods.AddRange(localCM); } } callingMethods.Clear(); callingMethods.AddRange(newCallingMethods); } //Needs to further analyze parent types TypeEx baseType = targetType.BaseType; if (baseType != null && baseType.FullName != "System.Object") //TODO: Avoid string comparisons. needs to figure out how to do that { SafeSet <Method> baseCallingMethods; TryGetCallingMethodsInType(calledMethod, field, baseType, out baseCallingMethods); callingMethods.AddRange(baseCallingMethods); } return(true); }