static public string GetSource (Defect defect) { if (defect == null) return String.Empty; if (defect.Instruction != null) return GetSource (defect.Instruction); // rule didn't provide an Instruction but we do our best to // find something since this is our only link to the source code Instruction candidate; TypeDefinition type = null; // MethodDefinition, ParameterDefinition // return the method source file with (approximate) line number MethodDefinition method = FindMethodFromLocation (defect.Location); if (method != null) { candidate = ExtractFirst (method); if (candidate != null) return FormatSource (candidate); // we may still be lucky to find the (a) source file for the type itself type = (method.DeclaringType as TypeDefinition); } // TypeDefinition, FieldDefinition // return the type source file (based on the first ctor) if (type == null) type = FindTypeFromLocation (defect.Location); candidate = ExtractFirst (type); if (candidate != null) return FormatSource (candidate); return String.Empty; }
private void CheckForLegalCall (MethodDefinition caller, Instruction ins) { MethodDefinition target = ((MethodReference) ins.Operand).Resolve (); if (target != null) { ThreadModel callerModel = caller.ThreadingModel (); ThreadModel targetModel = target.ThreadingModel (); if (!IsValidCall (callerModel, targetModel)) { string mesg = string.Format ("{0} {1} cannot call {2} {3}.", callerModel, caller.Name, targetModel, target.Name); ++DefectCount; Log.WriteLine (this, "Defect: {0}", mesg); Defect defect = new Defect (this, caller, caller, ins, Severity.High, Confidence.High, mesg); Runner.Report (defect); } } }
// We use this little helper so that we can report a better defect count to the test. // (The test itself can't quite manage this because it can't tell what happened // inside TearDown if CheckType or CheckMethod failed). private void ReportDefect (IMetadataTokenProvider metadata, Severity severity, Confidence confidence, string mesg) { ++DefectCount; Log.WriteLine (this, "Defect: {0}", mesg); // We need to use the Defect Report overload because the runner's current // target won't be set if we land here via TearDown. Defect defect = new Defect (this, metadata, metadata, severity, confidence, mesg); Runner.Report (defect); }
public override void TearDown () { // We don't always know that an anonymous method was used as a thread // entry point when we check the method so we check them just before we // tear down. foreach (MethodDefinition caller in anonymous_entry_points) { foreach (Instruction ins in caller.Body.Instructions) { switch (ins.OpCode.Code) { case Code.Call: case Code.Callvirt: MethodDefinition target = ((MethodReference) ins.Operand).Resolve (); if (target != null) { ThreadModel targetModel = target.ThreadingModel (); if (targetModel == ThreadModel.MainThread) { string mesg = string.Format ("An anonymous thread entry point cannot call MainThread {0}.", target.Name); ++DefectCount; Log.WriteLine (this, "Defect: {0}", mesg); Defect defect = new Defect (this, caller, caller, ins, Severity.High, Confidence.High, mesg); Runner.Report (defect); } } break; } } } base.TearDown (); }
private void CheckMethodBody (MethodDefinition method) { var synchronizedEvents = new Dictionary<MethodReference, List<MethodReference>> (); var thisSynchronized = new List<TypeReference> (); foreach (Instruction ins in method.Body.Instructions) { MethodReference candidate = null; switch (ins.OpCode.Code) { case Code.Newobj: if (ins.Previous != null && ins.Previous.OpCode.Code == Code.Ldftn) { MethodReference ctor = (MethodReference) ins.Operand; TypeReference type = ctor.DeclaringType; if (type.IsDelegate ()) { string nspace = type.Namespace; // ldftn entry-point // newobj System.Void System.Threading.XXX::.ctor (System.Object,System.IntPtr) // i.e. creation of a System.Threading delegate if (nspace == "System.Threading") { string name = type.Name; if (name == "ThreadStart" || name == "ParameterizedThreadStart" || name == "WaitCallback" || name == "WaitOrTimerCallback" || name == "TimerCallback") { candidate = (MethodReference) ins.Previous.Operand; } // ldftn entry-point // newobj System.Void System.AsyncCallback::.ctor (System.Object,System.IntPtr) // i.e. creation of a async delegate } else if (nspace == "System") { if (type.Name == "AsyncCallback") { candidate = (MethodReference) ins.Previous.Operand; } // ldftn entry-point // newobj System.Void ThreadedDelegate::.ctor (System.Object,System.IntPtr) // i.e. creation of a delegate which is decorated with a threading attribute } else if (!ThreadRocks.ThreadedNamespace (nspace)) { // Delegates must be able to call the methods they are bound to. MethodDefinition target = ((MethodReference) ins.Previous.Operand).Resolve (); if (target != null) { ThreadModel callerModel = type.ThreadingModel (); if (!target.IsGeneratedCode () || target.IsProperty ()) { ThreadModel targetModel = target.ThreadingModel (); if (!IsValidCall (callerModel, targetModel)) { string mesg = string.Format ("{0} delegate cannot be bound to {1} {2} method.", callerModel, targetModel, target.Name); ++DefectCount; Log.WriteLine (this, "Defect: {0}", mesg); Defect defect = new Defect (this, method, method, ins, Severity.High, Confidence.High, mesg); Runner.Report (defect); } } else if (!callerModel.Is (ThreadModel.MainThread)) { anonymous_entry_points.Add (target); } } } } } break; case Code.Call: case Code.Callvirt: if (!method.IsGeneratedCode () || method.IsProperty ()) CheckForLegalCall (method, ins); // ldftn entry-point // newobj XXX // callvirt System.Void SynchronizedType::add_Name (XXX) // i.e. adding a delegate to an event in a type which uses SynchronizingObject MethodReference call = (MethodReference) ins.Operand; TypeReference call_type = call.DeclaringType; if (ins.Previous.Is (Code.Newobj) && ins.Previous.Previous.Is (Code.Ldftn)) { // A few events are blacklisted because they do not use SynchronizingObject and // are therefore always threaded. if (IsNonSynchronizedSetter (call)) { candidate = (MethodReference) ins.Previous.Previous.Operand; // But most events do use SynchronizingObject and therefore their threading // depends on whether and how SynchronizingObject is initialized. } else if (HasSynchronizingObject (call_type)) { List<MethodReference> methods; if (!synchronizedEvents.TryGetValue (call, out methods)) { methods = new List<MethodReference> (); synchronizedEvents.Add (call, methods); } methods.AddIfNew ((MethodReference) ins.Previous.Previous.Operand); // Misc threaded events. } else if (call_type.FullName == "System.ComponentModel.BackgroundWorker") { if (call.Name == "add_DoWork") { candidate = (MethodReference) ins.Previous.Previous.Operand; } } // callvirt System.Void System.Diagnostics.Process::set_SynchronizingObject (System.ComponentModel.ISynchronizeInvoke) } else if (SetSynchronizingObject.Matches (call)) { if (ins.Previous.OpCode.Code == Code.Ldarg_0) { thisSynchronized.Add (call_type); } } break; } if (candidate != null) { Log.WriteLine (this, "{0} is a thread entry point", candidate); CheckEntryPoint (candidate); } } // For every method added to a threaded event, ThreadModel? method_model = null; foreach (KeyValuePair<MethodReference, List<MethodReference>> entry in synchronizedEvents) { // if the event is synchronized on this then the target must have the same thread // as the current method's type or better and it should not be treated as a entry point. if (thisSynchronized.Contains (entry.Key.DeclaringType)) { if (method_model == null) method_model = method.DeclaringType.ThreadingModel (); foreach (MethodReference mr in entry.Value) { MethodDefinition target = mr.Resolve (); if (target != null) { ThreadModel targetModel = target.ThreadingModel (); if (!IsValidCall (method_model.Value, targetModel)) { string mesg = string.Format ("{0} {1} cannot be bound to {2} {3} method.", method_model, entry.Key, targetModel, target.Name); ReportDefect (method, Severity.High, Confidence.High, mesg); } } } // otherwise the method has to be treated as a thread entry point. } else { foreach (MethodReference mr in entry.Value) { Log.WriteLine (this, "{0} is a thread entry point", mr); CheckEntryPoint (mr); } } } }
private void WriteEntry (int index, Defect defect) { IRule rule = defect.Rule; BeginColor ( (Severity.Critical == defect.Severity || Severity.High == defect.Severity) ? ConsoleColor.DarkRed : ConsoleColor.DarkYellow); writer.WriteLine ("{0}. {1}", index, rule.Name); writer.WriteLine (); EndColor (); BeginColor (ConsoleColor.DarkRed); writer.Write ("Problem: "); EndColor (); writer.Write (rule.Problem); writer.WriteLine (); writer.WriteLine ("* Severity: {0}, Confidence: {1}", defect.Severity, defect.Confidence); writer.WriteLine ("* Target: {0}", defect.Target); if (defect.Location != defect.Target) writer.WriteLine ("* Location: {0}", defect.Location); string source = defect.Source; if (!String.IsNullOrEmpty (source)) writer.WriteLine ("* Source: {0}", source); if (!String.IsNullOrEmpty (defect.Text)) writer.WriteLine ("* Details: {0}", defect.Text); writer.WriteLine (); BeginColor (ConsoleColor.DarkGreen); writer.Write ("Solution: "); EndColor (); writer.Write (rule.Solution); writer.WriteLine (); writer.WriteLine ("More info available at: {0}", rule.Uri.ToString ()); writer.WriteLine (); writer.WriteLine (); }
// reports only if it was called more than one time private void DelayedReport (Defect defect) { reportCounter++; if (reportCounter > 1) { if (reportCounter == 2) Runner.Report (defectDelayed); Runner.Report (defect); } else defectDelayed = defect; }
internal GendarmeViolation (GF.Defect defect) { this.defect = defect; this.location = new CA.CodeLocation(string.Empty, 0, 0); }
void CreateElement (Defect defect) { writer.WriteStartElement ("defect"); writer.WriteAttributeString ("Severity", defect.Severity.ToString ()); writer.WriteAttributeString ("Confidence", defect.Confidence.ToString ()); writer.WriteAttributeString ("Location", defect.Location.ToString ()); writer.WriteAttributeString ("Source", defect.Source); writer.WriteString (defect.Text); writer.WriteEndElement (); }
void CreateElement (Defect defect) { writer.WriteStartElement ("defect"); writer.WriteAttributeString ("Severity", defect.Severity.ToString ()); writer.WriteAttributeString ("Confidence", defect.Confidence.ToString ()); writer.WriteAttributeString ("Location", defect.Location.ToString ()); writer.WriteAttributeString ("Source", defect.Source); String st =null; if (defect.Location is MethodDefinition) st = "Method"; else if (defect.Location is FieldDefinition) st = "Field"; else if (defect.Location is ParameterDefinition) st = "Parameter"; else if (defect.Location is TypeDefinition) st = "Type"; else if (defect.Location is MethodReturnType) st = "Result"; if (st != null) writer.WriteAttributeString ("SourceType", st); writer.WriteString (defect.Text); writer.WriteEndElement (); }
public void Report (MethodDefinition method, Instruction ins, Severity severity, Confidence confidence, string message) { // check here to avoid creating the Defect object if (!Filter (severity, confidence, method)) return; Defect defect = new Defect (currentRule, currentTarget, method, ins, severity, confidence, message); Report (defect); }
public void Report (IMetadataTokenProvider metadata, Severity severity, Confidence confidence, string message) { // check here to avoid creating the Defect object if (!Filter (severity, confidence, metadata)) return; Defect defect = new Defect (currentRule, currentTarget, metadata, severity, confidence, message); Report (defect); }
public virtual void Report (Defect defect) { if (defect == null) throw new ArgumentNullException ("defect"); if (!Filter (defect.Severity, defect.Confidence, defect.Location)) return; if (IgnoreList.IsIgnored (defect.Rule, defect.Target)) return; defect_list.Add (defect); }
internal GendarmeViolation(GF.Defect defect) { this.defect = defect; this.location = new CA.CodeLocation(string.Empty, 0, 0); }