public override void LeaveMethod() { if (!bStartMonitoring) { return; } if (this.methodStack.Count == 0) { return; } var poppedMethod = this.methodStack.Pop(); this.currOffset = this.offsetStack.Pop(); var previousLoadedFields = this.lastLoadedFieldsStack.Pop(); //If the last method call is a getter, add the field just loaded by that getter method //Or any other remaining loaded fields if (poppedMethod.ShortName.StartsWith("get_")) { Field usedField; int foffset; if (DeclEntityCollector.TryGetFieldOfGetter(poppedMethod, out usedField, out foffset)) { previousLoadedFields.AddRange(usedField); } } this.lastLoadedFields.Clear(); this.lastLoadedFields.AddRange(previousLoadedFields); //Updating the defined and used field list if (this.methodStoreStack.Count > 0) { ses.AppendMethodStore(currSEMethodStore); var poppedStore = this.methodStoreStack.Pop(); if (!poppedMethod.ShortName.StartsWith("get_")) { //Do not propogate for getter methods PropagateModificationsToCaller(poppedStore, currSEMethodStore, poppedMethod); } poppedStore.AppendMethodStore(currSEMethodStore, this.currOffset); currSEMethodStore = poppedStore; } if (poppedMethod.ShortName.Equals("Main") || poppedMethod.ShortName.Equals("DUCoverTerminate")) { ses.DumpToDatabase(); bStartMonitoring = false; } }
public override EnterMethodFlags EnterMethod(Method method) { //Console.WriteLine(method.FullName); if (this.methodStack.Count == 0 && !bStartMonitoring) { var assemblyShortname = method.Definition.Module.Assembly.ShortName; if (assemblyShortname == this.currentAssemblyLoc) { //Whereever the main method, it is the assembly under analysis, //since our tool assumes that there is only one assembly var assembly = method.Definition.Module.Assembly; ses.CurrAssembly = assembly; bStartMonitoring = true; } } if (bStartMonitoring) { this.methodStack.Push(method); if (currSEMethodStore != null) { this.methodStoreStack.Push(currSEMethodStore); } currSEMethodStore = new SEMethodStore(method.FullName); currSEMethodStore.OptionalMethod = method; var tempLastLoadedFields = new SafeList <Field>(); tempLastLoadedFields.AddRange(lastLoadedFields); this.lastLoadedFieldsStack.Push(tempLastLoadedFields); this.lastLoadedFields.Clear(); this.offsetStack.Push(this.currOffset); } return(base.EnterMethod(method)); // 'true' indicates that we want callbacks for the argument values }
/// <summary> /// Propagates the changes made by a called method to its caller, based on the lastLoadedFields /// For example, if the called method modifies any fields, then the related parent fields in the caller method /// are marked as updated /// </summary> /// <param name="callerMStore"></param> /// <param name="calledMethodStore"></param> private void PropagateModificationsToCaller(SEMethodStore callerMStore, SEMethodStore calledMethodStore, Method calledMethod) { if (this.lastLoadedFields.Count == 0) { return; } //Idenitfy relevant fields from the last loadedFields 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 (!calledMethod.TryGetDeclaringType(out methodDeclType)) { logger.Error("Failed to get the declaring type of the method: " + calledMethod.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 this.lastLoadedFields) { 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 calledMethod.ParameterTypes) { foreach (var field in this.lastLoadedFields) { if (field == receiverField) { continue; } var fieldType = field.Type; if (fieldType == argtype || fieldType.IsAssignableTo(argtype) || argtype.IsAssignableTo(fieldType)) { fieldsProcessed.Add(field); break; } } } if (calledMethodStore.DefinedFieldSet.Count == 0) { //If the called method does not define any field, all current fields are just loaded fields foreach (var field in fieldsProcessed) { callerMStore.AddToUsedList(field, this.currOffset); this.lastLoadedFields.Remove(field); } } else { //process each defined field foreach (var deffield in calledMethodStore.DefinedFieldSet.Values) { TypeEx deffieldType; if (deffield.OptionalField.TryGetDeclaringType(out deffieldType)) { //Identify the related field in the lastLoadedFields Field processedField = null; foreach (var field in fieldsProcessed) { var fieldType = field.Type; if (fieldType == deffieldType || fieldType.IsAssignableTo(deffieldType) || deffieldType.IsAssignableTo(fieldType)) { processedField = field; callerMStore.AddToDefinedList(field, this.currOffset); break; } } if (processedField != null) { fieldsProcessed.Remove(processedField); this.lastLoadedFields.Remove(processedField); } } } //Consider the remaining fields at usedfields and remove them from lastLoadedFields foreach (var field in fieldsProcessed) { callerMStore.AddToUsedList(field, this.currOffset); this.lastLoadedFields.Remove(field); } } }