public RuleResult CheckMethod (MethodDefinition method) { // we only check non static, non virtual methods and not constructors if (method.IsStatic || method.IsVirtual || method.IsConstructor) return RuleResult.DoesNotApply; // we only check methods with a body if (!method.HasBody) return RuleResult.DoesNotApply; // we also don't check event callbacks, as they usually bring a lot of false positive, // and that developers are tied to their signature if (method.IsEventCallback ()) return RuleResult.DoesNotApply; // that aren't compiler generated (e.g. anonymous methods) or generated by a tool (e.g. web services) if (method.IsGeneratedCode ()) return RuleResult.DoesNotApply; // methods with [Conditional] can be empty (not using 'this') IL-wise but not source-wise, ignore them if (method.HasCustomAttributes) { if (method.HasAttribute ("System.Diagnostics", "ConditionalAttribute")) return RuleResult.DoesNotApply; } // rule applies // if we find a use of the "this" reference, it's ok // in most (all?) case "this" is used with the ldarg_0 instruction if (OpCodeEngine.GetBitmask (method).Get (Code.Ldarg_0)) return RuleResult.Success; // but it's also valid to have an ldarg with a 0 value operand foreach (Instruction instr in method.Body.Instructions) { if (instr.OpCode.Code == Code.Ldarg) { ParameterDefinition pd = (instr.Operand as ParameterDefinition); if (pd.Index == -1) return RuleResult.Success; } } Runner.Report (method, Severity.Low, Confidence.Total); return RuleResult.Failure; }
// Method Visible Non-Visible // ------------------------------------------------ // Parameters High Medium // ReturnType High Medium // Variables Low Low // Method calls Medium* Low* // Fields access Medium* Low* // * target visibility public RuleResult CheckMethod(MethodDefinition method) { // [Obsolete] cannot be applied to property or event accessors if (method.IsProperty () || method.IsAddOn || method.IsRemoveOn || method.IsFire) return RuleResult.DoesNotApply; // if the method is obsolete (directly or because it's type is) if (method.HasAttribute ("System", "ObsoleteAttribute") || method.DeclaringType.HasAttribute ("System", "ObsoleteAttribute")) return RuleResult.DoesNotApply; // check method signature (parameters, return value) if (method.HasParameters) CheckParameters (method); CheckReturnType (method); // then check what the IL calls/access if (method.HasBody) { MethodBody body = method.Body; if (body.HasVariables) CheckVariables (method); foreach (Instruction ins in body.Instructions) { switch (ins.OpCode.Code) { case Code.Newarr: case Code.Newobj: case Code.Call: case Code.Callvirt: CheckMethodCall (method, ins, (ins.Operand as MethodReference)); break; case Code.Initobj: CheckTypeCreation (method, ins, (ins.Operand as TypeReference)); break; case Code.Ldfld: case Code.Ldflda: case Code.Ldsfld: case Code.Ldsflda: case Code.Stfld: case Code.Stsfld: CheckFieldAccess (method, ins, (ins.Operand as FieldReference)); break; } } } return Runner.CurrentRuleResult; }
public RuleResult CheckMethod (MethodDefinition method) { if (!method.HasAttribute (SUCS)) return RuleResult.Success; Runner.Report (method, Severity.Audit, Confidence.Total); return RuleResult.Failure; }
public RuleResult CheckMethod(MethodDefinition method) { // catch abstract, pinvoke and icalls - where rule does not apply if (!method.HasBody) return RuleResult.DoesNotApply; // skip methods without parameters if (!method.HasParameters) return RuleResult.DoesNotApply; // rule doesn't apply to virtual, overrides or generated code // doesn't apply to code referenced by delegates (note: more complex check moved last) if (method.IsVirtual || method.HasOverrides || method.IsGeneratedCode ()) return RuleResult.DoesNotApply; // Also EventArgs parameters are often required in method signatures, // but often not required. Reduce "false positives"(*) for GUI apps // (*) it's more a "don't report things outside developer's control" if (method.IsEventCallback () || IsReferencedByDelegate (method)) return RuleResult.DoesNotApply; // methods with [Conditional] can be empty (not using any parameter) IL-wise but not source-wise, ignore them if (method.HasAttribute ("System.Diagnostics", "ConditionalAttribute")) return RuleResult.DoesNotApply; // rule applies // we limit ourselves to the first 64 parameters (so we can use a bitmask) IList<ParameterDefinition> pdc = method.Parameters; int pcount = pdc.Count; if (pcount > 64) pcount = 64; ulong mask = 0; // scan IL to see which parameter is being used foreach (Instruction ins in method.Body.Instructions) { ParameterDefinition parameter = ins.GetParameter (method); if (parameter == null) continue; mask |= ((ulong)1 << parameter.Index); } // quick out based on value - i.e. every parameter is being used int shift = 64 - pcount; if ((mask << shift) == (UInt64.MaxValue << shift)) return RuleResult.Success; for (int i = 0; i < pcount; i++) { if ((mask & ((ulong) 1 << i)) == 0) { ParameterDefinition parameter = pdc [i]; string text = String.Format (CultureInfo.InvariantCulture, "Parameter '{0}' of type '{1}' is never used in the method.", parameter.Name, parameter.ParameterType); Runner.Report (parameter, Severity.Medium, Confidence.Normal, text); } } return Runner.CurrentRuleResult; }
// rock-ify // not 100% bullet-proof against buggy compilers (or IL) static bool IsExtension (MethodDefinition method) { if (!method.IsStatic) return false; if (!method.HasParameters) return false; return method.HasAttribute ("System.Runtime.CompilerServices.ExtensionAttribute"); }
public RuleResult CheckMethod (MethodDefinition method) { if (!method.HasAttribute ("System.Security", "SuppressUnmanagedCodeSecurityAttribute")) return RuleResult.Success; Runner.Report (method, Severity.Audit, Confidence.Total); return RuleResult.Failure; }