public RuleResult CheckMethod(MethodDefinition method) { // rule does not apply to method without IL (e.g. p/invoke) or generated code (e.g. compiler or tools) if (!method.HasBody || method.IsGeneratedCode()) { 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) { if ((ins.OpCode.Code != Code.Callvirt) && (ins.OpCode.Code != Code.Call)) { continue; } // look for calls to .Invoke MethodReference mr = (ins.Operand as MethodReference); if (!MethodSignatures.Invoke.Matches(mr)) { continue; } // limit ourself to events if (!mr.IsEventCallback()) { continue; } // first check if we're looking from a variable or directly from // the field (bad, it could be null) Instruction caller = ins.TraceBack(method); FieldDefinition field = caller.GetField(); if (field != null) { string msg = String.Format(CultureInfo.InvariantCulture, "Possible race condition since field '{0}' is accessed directly.", field.Name); Runner.Report(method, ins, Severity.High, Confidence.High, msg); } else { // look for the variable, if it's not then stop analysis VariableDefinition load = caller.GetVariable(method); if ((load != null) && !CheckVariable(method, caller, load)) { string name = String.Empty; // load.Name is not valid since Cecil 0.10 string msg = String.Format(CultureInfo.InvariantCulture, "Variable '{0}' does not seems to be checked against null.", name); Runner.Report(method, ins, Severity.High, Confidence.Normal, msg); } } } return(Runner.CurrentRuleResult); }