// small patterns that highly suggest they were compiler generated bool ComputeUnlikelyUserPatterns() { bool call = false; for (int i = 0; i < Count; i++) { Instruction ins = instructions [i]; // foreach if (ins.OpCode.Code == Code.Callvirt) { MethodReference mr = (ins.Operand as MethodReference); if (mr.IsNamed("System.Collections", "IEnumerator", "get_Current")) { return(true); } if (mr.IsNamed("System.Collections", "IEnumerator", "MoveNext")) { return(!call); } } // if there's a unknown call then it's likely not (totally) compiler generated call |= (ins.OpCode.FlowControl == FlowControl.Call); // foreach if (IsInstanceOfIDisposable(ins)) { return(true); } // foreach, using if (IsIDisposableDisposePattern(ins)) { return(true); } } return(false); }
public RuleResult CheckMethod(MethodDefinition method) { // rule doesn't apply if the method has no IL if (!method.HasBody) { return(RuleResult.DoesNotApply); } // avoid looping if we're sure there's no call in the method if (!OpCodeBitmask.Calls.Intersect(OpCodeEngine.GetBitmask(method))) { return(RuleResult.DoesNotApply); } int enter = 0; int exit = 0; foreach (Instruction ins in method.Body.Instructions) { if (ins.OpCode.FlowControl != FlowControl.Call) { continue; } MethodReference m = (ins.Operand as MethodReference); if (m == null) { continue; } if (m.IsNamed("System.Threading", "Monitor", "Enter")) { enter++; } else if (m.IsNamed("System.Threading", "Monitor", "Exit")) { exit++; } } if (enter == exit) { return(RuleResult.Success); } Runner.Report(method, Severity.High, Confidence.Normal); return(RuleResult.Failure); }
private static bool IsGetNow(Instruction ins) { if (ins.OpCode.Code != Code.Call) { return(false); } MethodReference calledMethod = (MethodReference)ins.Operand; return(calledMethod.IsNamed("System", "DateTime", "get_Now")); }
public RuleResult CheckMethod(MethodDefinition method) { if (!method.HasBody) { return(RuleResult.DoesNotApply); } // is there any Newobj instructions in this method if (!OpCodeEngine.GetBitmask(method).Get(Code.Newobj)) { return(RuleResult.DoesNotApply); } StackEntryAnalysis sea = null; foreach (Instruction ins in method.Body.Instructions) { if (ins.OpCode.Code != Code.Newobj) { continue; } MethodReference constructor = (MethodReference)ins.Operand; if (!constructor.DeclaringType.IsNamed("System.Threading", "Thread")) { continue; } if (ins.Next != null && (ins.Next.OpCode.Code == Code.Call || ins.Next.OpCode.Code == Code.Callvirt)) //quick check to safe resources { MethodReference calledMethod = (MethodReference)ins.Next.Operand; if (calledMethod.IsNamed("System.Threading", "Thread", "Start")) { continue; } } if (sea == null) { sea = new StackEntryAnalysis(method); } StackEntryUsageResult [] usageResults = sea.GetStackEntryUsage(ins); if (!CheckUsage(usageResults)) { // Critical because code cannot work as intented Runner.Report(method, ins, Severity.Critical, Confidence.High, String.Empty); } } return(Runner.CurrentRuleResult); }
public RuleResult CheckMethod(MethodDefinition method) { // rule apply only if the method has a body (e.g. p/invokes, icalls don't) if (!method.HasBody) { return(RuleResult.DoesNotApply); } // is there any Call or Callvirt instructions in the method ? if (!OpCodeBitmask.Calls.Intersect(OpCodeEngine.GetBitmask(method))) { return(RuleResult.DoesNotApply); } foreach (Instruction ins in method.Body.Instructions) { if ((ins.OpCode.Code != Code.Call) && (ins.OpCode.Code != Code.Callvirt)) { continue; } // look for String.Concat overloads using System.Object MethodReference mr = (ins.Operand as MethodReference); if (!mr.HasParameters || !mr.IsNamed("System", "String", "Concat")) { continue; } TypeReference ptype = mr.Parameters [0].ParameterType; if (ptype.Namespace != "System") { continue; // very unlikely } switch (ptype.Name) { case "Object": CheckParameters(mr, method, ins); break; case "Object[]": if ((ins.Previous.OpCode.Code == Code.Stelem_Ref) || ins.Previous.IsLoadLocal()) { ScanArray(method, ins.Previous); } break; } } return(Runner.CurrentRuleResult); }
public RuleResult CheckMethod(MethodDefinition method) { // rule doesn't not apply to methods without code (e.g. p/invokes) if (!method.HasBody) { return(RuleResult.DoesNotApply); } // is there any Call or Callvirt instructions in the method OpCodeBitmask calls = OpCodeBitmask.Calls; if (!calls.Intersect(OpCodeEngine.GetBitmask(method))) { return(RuleResult.DoesNotApply); } // go! // we look for a call to String.Length property (since it's much easier // than checking a string being compared to null) foreach (Instruction current in method.Body.Instructions) { if (!calls.Get(current.OpCode.Code)) { continue; } MethodReference mr = (current.Operand as MethodReference); if (mr.IsNamed("System", "String", "get_Length")) { // now that we found it we check that // 1 - we previously did a check null on the same value (that we already know is a string) Instruction branch = PreLengthCheck(method, current.Previous); if (branch == null) { continue; } // 2 - we compare the return value (length) with 0 if (PostLengthCheck(current.Next, branch)) { Runner.Report(method, current, Severity.Medium, Confidence.High); } } } return(Runner.CurrentRuleResult); }
protected override bool IsSpecialCase(MethodReference method) { if ((method == null) || method.IsNamed("System", "Activator", "CreateInstance")) { return(true); } TypeReference type = method.DeclaringType; if (!type.IsNamed("System.Resources", "ResourceManager")) { return(false); } string name = method.Name; return(name == "GetObject" || name == "GetString"); }
static bool IsMonitorEnter(Instruction ins, int parametersCount) { // VS2008 like to includes a few NOP while (ins != null && ins.OpCode.Code == Code.Nop) { ins = ins.Previous; } if (ins == null) { return(false); } MethodReference method = (ins.Operand as MethodReference); if (!method.IsNamed("System.Threading", "Monitor", "Enter")) { return(false); } return(parametersCount == method.Parameters.Count); }
private bool Recurse(MethodDefinition method, int level) { // some methods have no body (e.g. p/invokes, icalls) if ((method == null) || !method.HasBody) { return(false); } // don't iterate the IL unless we know there are some call[virt] inside them if (!OpCodeBitmask.Calls.Intersect(OpCodeEngine.GetBitmask(method))) { return(false); } foreach (Instruction ins in method.Body.Instructions) { switch (ins.OpCode.Code) { case Code.Call: case Code.Callvirt: // are we calling GC.SuppressFinalize ? MethodReference callee = (ins.Operand as MethodReference); if (callee.IsNamed("System", "GC", "SuppressFinalize")) { return(true); } else if (level < 3) { if (Recurse(callee.Resolve(), level + 1)) { return(true); } } break; } } return(false); }
public RuleResult CheckMethod(MethodDefinition method) { if (!method.HasBody) { return(RuleResult.DoesNotApply); } // avoid looping if we're sure there's no call in the method if (!OpCodeBitmask.Calls.Intersect(OpCodeEngine.GetBitmask(method))) { return(RuleResult.DoesNotApply); } foreach (Instruction ins in method.Body.Instructions) { MethodReference mr = ins.GetMethod(); if (mr.IsNamed("System.Threading", "Monitor", "Enter")) { Analyze(method, mr, ins); } } return(Runner.CurrentRuleResult); }
// the rule idea came from // http://lists.ximian.com/archives/public/mono-patches/2008-June/121564.html public RuleResult CheckMethod(MethodDefinition method) { // rule apply only if the method has a body (e.g. p/invokes, icalls don't) if (!method.HasBody) { return(RuleResult.DoesNotApply); } // is there any Call or Callvirt instructions in the method ? OpCodeBitmask bitmask = OpCodeEngine.GetBitmask(method); if (!OpCodeBitmask.Calls.Intersect(bitmask)) { return(RuleResult.DoesNotApply); } // and a call to Ldstr ? if (!bitmask.Get(Code.Ldstr)) { return(RuleResult.DoesNotApply); } foreach (Instruction ins in method.Body.Instructions) { if (ins.OpCode.FlowControl != FlowControl.Call) { continue; } // look for calls to: static Type System.Type.GetType(string...) MethodReference mr = (ins.Operand as MethodReference); if ((mr == null) || !mr.HasParameters) { continue; } if (!mr.IsNamed("System", "Type", "GetType")) { continue; } if (ins.Previous.OpCode.Code != Code.Ldstr) { continue; } string type_name = (ins.Previous.Operand as string); // one good reason to use this (besides non-visible types) is get a type from an unreferenced assembly if ((type_name == null) || type_name.Contains(", ")) { continue; } // another good reason is the supported way to detect if running on mono runtime if (type_name == "Mono.Runtime") { continue; } string msg = String.Format(CultureInfo.InvariantCulture, "Replace call to Type.GetType(\"{0}\") into typeof({0}).", type_name); Runner.Report(method, ins, Severity.Medium, Confidence.Normal, msg); } return(Runner.CurrentRuleResult); }