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> /// 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; } }
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; }
// 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> /// Adds a field to an unsuccessful code location. /// </summary> /// <param name="location"></param> /// <param name="fields"></param> public void AddFieldsOfUncoveredCodeLocations(CodeLocation location, SafeList<Field> fields, FieldModificationType fmt, Term condition, string terms, int fitnessval, TypeEx explorableType, SafeList<TypeEx> allFieldTypes) { //No need to process this location. if (fields.Count == 0) { return; } Field targetField; TypeEx declaringType; //This declaring type is considered as explorable type in the rest of the analysis if (!PexMeFactoryGuesser.GetTargetExplorableField(this, fields, out targetField, out declaringType)) { this.Log.LogError(WikiTopics.MissingWikiTopic, "factoryguesser", "Failed to retrieve the target field for uncovered location " + location.ToString()); return; } //Compare the declaring type and actual explorable type. //If there is a inheritance relation, use the actual one if (explorableType.IsAssignableTo(declaringType)) { declaringType = explorableType; } var uclskey = UncoveredCodeLocationStore.GetKey(location.ToString(), declaringType.ToString(), condition.UniqueIndex); UncoveredCodeLocationStoreList uclslist; if (!this.unCoveredLocationDic.TryGetValue(uclskey, out uclslist)) { uclslist = new UncoveredCodeLocationStoreList(); uclslist.Location = location; uclslist.ExplorableType = declaringType.ToString(); uclslist.TermIndex = condition.UniqueIndex; this.unCoveredLocationDic[uclskey] = uclslist; } var ucls = new UncoveredCodeLocationStore(); ucls.Location = location; ucls.ExplorableType = declaringType; ucls.TargetField = targetField; ucls.AllFields.AddRange(fields); ucls.AllFieldTypes.AddRange(allFieldTypes); ucls.TermIndex = condition.UniqueIndex; //add the sequence of method calls ucls.MethodCallSequence = new MethodSignatureSequence(); foreach (var m in this.LastExecutedFactoryMethodCallSequence) { ucls.MethodCallSequence.Sequence.Add(MethodOrFieldAnalyzer.GetMethodSignature(m)); } ucls.IsADefectDetectingSequence = this.DefectDetectingSequence; ucls.CUTMethodCallSequence = this.LastExecutedCUTMethodCallSequence; if (!uclslist.StoreList.Contains(ucls)) { ucls.TextualTerms.Add(terms); ucls.DesiredFieldModificationType = fmt; ucls.Fitnessvalue = fitnessval; uclslist.StoreList.Add(ucls); } }
public static bool TryCheckReturnTypeOfMethod(PexMeDynamicDatabase pmd, TypeDefinition tdef, MethodDefinition mdef, TypeEx targetTypeEx, out Method producingMethod) { var retType = mdef.ResultType; if (retType.ToString() == targetTypeEx.FullName) { producingMethod = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(pmd, tdef), MethodOrFieldAnalyzer.GetGenericMethodParameters(pmd, mdef)); return true; } //Get the actual type of return type and see whether it is assinable TypeEx retTypeEx; if (MethodOrFieldAnalyzer.TryGetTypeExFromName(pmd, pmd.CurrAssembly, retType.ToString(), out retTypeEx)) { if (targetTypeEx.IsAssignableTo(retTypeEx)) { producingMethod = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(pmd, tdef), MethodOrFieldAnalyzer.GetGenericMethodParameters(pmd, mdef)); return true; } } producingMethod = null; return false; }