/// <summary> /// Collects all definitions and uses among each class in the assembly under analysis /// </summary> /// <param name="ade"></param> private static void CollectAllDefsAndUsesInTypeDef(TypeDefinition td, DeclClassEntity ade) { var host = DUCoverStore.GetInstance().Host; SideEffectStore ses = SideEffectStore.GetInstance(); var psd = host.GetService <PexMeStaticDatabase>() as PexMeStaticDatabase; foreach (var constructor in td.DeclaredInstanceConstructors) { var method = constructor.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(host, td), MethodOrFieldAnalyzer.GetGenericMethodParameters(host, constructor)); CollectDefsAndUsesInMethod(psd, td, ade, method, null, ses); } foreach (var mdef in td.DeclaredInstanceMethods) { try { var method = mdef.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(host, td), MethodOrFieldAnalyzer.GetGenericMethodParameters(host, mdef)); CollectDefsAndUsesInMethod(psd, td, ade, method, null, ses); } catch (Exception ex) { logger.ErrorException("Failed to instantiate method " + mdef.FullName, ex); } } foreach (var prop in td.DeclaredProperties) { var getter = prop.Getter; if (getter != null) { Field usedField; int foffset; var method = getter.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(host, td), MethodOrFieldAnalyzer.GetGenericMethodParameters(host, getter)); if (TryGetFieldOfGetter(method, out usedField, out foffset)) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(usedField.FullName, out dfe)) { //Found an accessor. register the usage dfe.AddToUseList(method, foffset); } } } var setter = prop.Setter; if (setter != null) { var method = setter.Instantiate(MethodOrFieldAnalyzer.GetGenericTypeParameters(host, td), MethodOrFieldAnalyzer.GetGenericMethodParameters(host, setter)); CollectDefsAndUsesInMethod(psd, td, ade, method, null, ses); } } }
private static void HandleSetterMethod(DeclClassEntity ade, Method method, int offset, Method methodinner) { //found a definition Field definedField; if (TryGetFieldOfSetter(methodinner, out definedField)) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(definedField.FullName, out dfe)) { dfe.AddToDefList(method, offset); } } else { logger.Warn("Failed to retrive field associated with the setter method: " + methodinner.FullName); } }
private static void HandleGetterMethod(DeclClassEntity ade, Method method, int offset, Method methodinner, SafeList <Field> lastAccessedFieldList) { //found a use Field usedField; int foffset; if (TryGetFieldOfGetter(methodinner, out usedField, out foffset)) { lastAccessedFieldList.Add(usedField); DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(usedField.FullName, out dfe)) { dfe.AddToUseList(method, offset); } } else { logger.Warn("Failed to retrive field associated with the getter method: " + methodinner.FullName); } }
/// <summary> /// Handles a method call /// </summary> /// <param name="psd"></param> /// <param name="ade"></param> /// <param name="method"></param> /// <param name="offset"></param> /// <param name="lastAccessedFieldList"></param> /// <param name="methodinner"></param> private static void HandleMethodCall(PexMeStaticDatabase psd, DeclClassEntity ade, Method method, int offset, SafeList <Field> lastAccessedFieldList, Method methodinner, SideEffectStore ses) { SafeList <Field> fieldsProcessed = new SafeList <Field>(); Field receiverField = null; //Check whether the current method call is actually on the field previously loaded TypeEx methodDeclType; if (!methodinner.TryGetDeclaringType(out methodDeclType)) { logger.Error("Failed to get the declaring type of the method: " + methodinner.FullName); return; } if (methodDeclType.FullName == "System.String" || methodDeclType.FullName == "System.string") { return; //Do not process string types. } //Check whether the declaring type is in the fields list foreach (var field in lastAccessedFieldList) { var fieldType = field.Type; if (fieldType == methodDeclType || fieldType.IsAssignableTo(methodDeclType) || methodDeclType.IsAssignableTo(fieldType)) { fieldsProcessed.Add(field); receiverField = field; break; } } if (receiverField == null) { //Failed to identify the reciver field of this method return; } //Identify arguments of the current method call foreach (var argtype in methodinner.ParameterTypes) { foreach (var field in lastAccessedFieldList) { if (field == receiverField) { continue; } var fieldType = field.Type; if (fieldType == argtype || fieldType.IsAssignableTo(argtype) || argtype.IsAssignableTo(fieldType)) { fieldsProcessed.Add(field); break; } } } DUCoverStore dcs = DUCoverStore.GetInstance(); //If the method is known, its side-effects are well-known if (methodinner.ShortName.StartsWith("set_")) { foreach (var processedField in fieldsProcessed) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(processedField.FullName, out dfe)) { dfe.AddToDefList(method, offset); } lastAccessedFieldList.Remove(processedField); } } else if (methodinner.ShortName.StartsWith("get_")) { foreach (var processedField in fieldsProcessed) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(processedField.FullName, out dfe)) { dfe.AddToUseList(method, offset); } lastAccessedFieldList.Remove(processedField); } } else { //add all fiels to def or use, since we may not aware of their side-effects here foreach (var processedField in fieldsProcessed) { DeclFieldEntity dfe; if (ade.FieldEntities.TryGetValue(processedField.FullName, out dfe)) { bool defined, used; if (ses.TryGetFieldDefOrUseByMethod(method, processedField, offset, out defined, out used)) { if (defined) { dfe.AddToDefList(method, offset); } if (used) { dfe.AddToUseList(method, offset); } } else { dfe.AddToDefOrUseList(method, offset, methodinner); } } lastAccessedFieldList.Remove(processedField); } } }
/// <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); } }