Example #1
0
        protected override void CheckMethod(MethodDefinition method, bool abstractWarning)
        {
            if ((method == null) || !method.HasBody)
            {
                return;
            }

            OpCodeBitmask bitmask = OpCodeEngine.GetBitmask(method);

            // method must have a CALL[VIRT] and either STFLD or STELEM_REF
            if (!bitmask.Intersect(OpCodeBitmask.Calls) || !bitmask.Intersect(StoreFieldBitmask))
            {
                return;
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                MethodReference mr = (ins.Operand as MethodReference);
                if (mr == null || mr.DeclaringType.IsNative())
                {
                    continue;
                }

                FieldDefinition field = null;
                Instruction     next  = ins.Next;
                if (next.Is(Code.Stfld))
                {
                    field = next.Operand as FieldDefinition;
                }
                else if (next.Is(Code.Stobj) || next.Is(Code.Stind_I))
                {
                    Instruction origin = next.TraceBack(method);
                    if (origin.Is(Code.Ldelema))
                    {
                        origin = origin.TraceBack(method);
                        if (origin != null)
                        {
                            field = origin.Operand as FieldDefinition;
                        }
                    }
                }

                if (field != null && FieldCandidates.Contains(field))
                {
                    Runner.Report(field, Severity.High, Confidence.High,
                                  abstractWarning ? AbstractTypeMessage : TypeMessage);
                }
            }
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            // Rule does not apply if the method has no IL
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }
            //
            // We need to check all methods which has any of the following opcodes: call, stfld or stsfld.
            //
            OpCodeBitmask bitmask = OpCodeEngine.GetBitmask(method);

            if (!applicable_method_bitmask.Intersect(bitmask))
            {
                return(RuleResult.DoesNotApply);
            }

            /* Unfortunately it's possible to generate IL this rule will choke on, especially when
             * using non-standard compilers or obfuscators. */
            try
            {
                return(CheckMethodUnsafe(method));
            }
            catch (Exception ex)
            {
                // FIXME: This problem should be reported some other way, it's not really a failure.
                // Pending implementation of "analysis warnings", as mentioned here (post #21):
                // http://groups.google.com/group/gendarme/browse_frm/thread/c37d157ae0c9682/57f89f3abf14f2fd?tvc=1&q=Gendarme+2.6+Preview+1+is+ready+for+download#57f89f3abf14f2fd
                Runner.Report(method, Severity.Low, Confidence.Low,
                              String.Format(CultureInfo.CurrentCulture, "An exception occurred while verifying this method. " +
                                            "This failure can probably be ignored, it's most likely due to an " +
                                            "uncommon code sequence in the method the rule didn't understand. {0}", ex.Message));
                return(RuleResult.Failure);
            }
        }
Example #3
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            if (!Throwers.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            if (!HasCatchBlock(method.Body))
            {
                // default severity for (most) methods
                severity = Severity.High;
                // by default no exceptions are allowed
                allowedExceptions = null;
                // special case for Equals
                is_equals = false;

                string method_label = PreflightMethod(method);
                if (method_label.Length > 0)
                {
                    Log.WriteLine(this);
                    Log.WriteLine(this, "-------------------------------------------");
                    Log.WriteLine(this, method);

                    ProcessMethod(method, method_label);
                }
            }

            return(Runner.CurrentRuleResult);
        }
Example #4
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            // rule only applies to methods with IL and exceptions handlers
            if (!method.HasBody || !method.Body.HasExceptionHandlers)
            {
                return(RuleResult.DoesNotApply);
            }

            // and when the IL contains a Throw instruction (Rethrow is fine)
            OpCodeBitmask mask = OpCodeEngine.GetBitmask(method);

            if (!mask.Get(Code.Throw))
            {
                return(RuleResult.DoesNotApply);
            }

            // we can use a faster code path when no branches are present in the method
            if (mask.Intersect(branches))
            {
                Branches(method);
            }
            else
            {
                Branchless(method);
            }

            warned_offsets_in_method.Clear();

            return(Runner.CurrentRuleResult);
        }
Example #5
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            if (!Remainder.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                switch (ins.OpCode.Code)
                {
                case Code.Rem:
                case Code.Rem_Un:
                    if (CheckModuloOne(ins.Previous))
                    {
                        Runner.Report(method, ins, Severity.High, Confidence.Total);
                    }
                    break;
                }
            }
            return(Runner.CurrentRuleResult);
        }
Example #6
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            //is there any interesting opcode in the method?
            OpCodeBitmask calls = OpCodeBitmask.Calls;

            if (!calls.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                if (!calls.Get(ins.OpCode.Code))
                {
                    continue;
                }

                CheckCall(method, ins, (MethodReference)ins.Operand);
            }

            return(Runner.CurrentRuleResult);
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            if (!Remainder.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                Severity severity;
                // look for a remainder operation
                switch (ins.OpCode.Code)
                {
                case Code.Rem:
                    // this won't work when negative numbers are used
                    severity = Severity.High;
                    break;

                case Code.Rem_Un:
                    // this will work since it can't be a negative number
                    // but it's a coding bad (practice) example
                    severity = Severity.Low;
                    break;

                default:
                    continue;
                }

                // x % 2
                if (!IsLoadConstant(ins.Previous, 2))
                {
                    continue;
                }
                // compared to 1
                if (!IsLoadConstant(ins.Next, 1))
                {
                    continue;
                }
                // using equality
                Instruction cmp = ins.Next.Next;
                if (Conversion.Get(cmp.OpCode.Code))
                {
                    cmp = cmp.Next;
                }
                if (cmp.OpCode.Code != Code.Ceq)
                {
                    continue;
                }

                Runner.Report(method, ins, severity, Confidence.Normal);
            }
            return(Runner.CurrentRuleResult);
        }
Example #8
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            // exclude methods that don't have any conditional branches
            if (!Branches.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                switch (ins.OpCode.Code)
                {
                case Code.Brfalse:
                case Code.Brfalse_S:
                case Code.Brtrue:
                case Code.Brtrue_S:
                // BNE is used by [G]MCS
                case Code.Bne_Un:
                case Code.Bne_Un_S:
                case Code.Beq:
                case Code.Beq_S:
                    Instruction br    = (ins.Operand as Instruction);
                    int         delta = br.Offset - ins.Next.Offset;
                    if (delta == 0)
                    {
                        // Medium: since compiler already warned about this
                        Runner.Report(method, ins, Severity.Medium, Confidence.Normal);
                    }
                    else if (delta <= 2)
                    {
                        // is the block (between the jumps) small and empty ?
                        // CSC does this, probably to help the debugger.
                        // [G]MCS does not
                        while (delta > 0)
                        {
                            br = br.Previous;
                            if (br.OpCode.Code != Code.Nop)
                            {
                                break;
                            }
                            delta--;
                        }
                        if (delta == 0)
                        {
                            Runner.Report(method, ins, Severity.Low, Confidence.Normal);
                        }
                    }
                    break;
                }
            }
            return(Runner.CurrentRuleResult);
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            // rule apply only if the method has a body (e.g. p/invokes, icalls don't)
            // and was not generated by the compiler or a tool (outside of developer's control)
            if (!method.HasBody || method.IsGeneratedCode())
            {
                return(RuleResult.DoesNotApply);
            }

            // is there any IsInst or Castclass instructions in the method ?
            if (!Casts.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

//			Console.WriteLine ();
//			Console.WriteLine ("-----------------------------------------");
//			Console.WriteLine (new MethodPrinter(method));

            foreach (Instruction ins in method.Body.Instructions)
            {
                Code code = ins.OpCode.Code;
                // IsInst -> if (t is T) ...
                //        -> t = t as T; ...
                // Castclass -> t = (T) t; ...
                if ((code == Code.Isinst) || (code == Code.Castclass))
                {
                    casts.Add(ins);
                }
            }

            // if there's only one then it can't be a duplicate cast
            while (casts.Count > 1)
            {
                Instruction   ins    = casts [0];
                TypeReference type   = (ins.Operand as TypeReference);
                Instruction   origin = GetOrigin(ins);

                int count = FindDuplicates(method, type, origin);
                if (count > 1)
                {
//					Console.WriteLine ("found {0} duplicates for {1:X4}", count, ins.Offset);

                    // rare, but it's possible to cast a null value (ldnull)
                    object name = origin.GetOperand(method) ?? "Null";
                    string msg  = String.Format(CultureInfo.InvariantCulture,
                                                "'{0}' is casted {1} times for type '{2}'.", name, count, type.GetFullName());
                    Runner.Report(method, ins, Severity.Medium, Confidence.Normal, msg);
                }
                casts.RemoveAt(0);
            }
            casts.Clear();

            return(Runner.CurrentRuleResult);
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            // is there any Unbox or Unbox_Any instructions in the method ?
            if (!Unbox.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                switch (ins.OpCode.Code)
                {
                case Code.Unbox:
                case Code.Unbox_Any:
                    string previous = Previous(method, ins);
                    if (previous.Length == 0)
                    {
                        continue;
                    }

                    int num;
                    if (!unboxed.TryGetValue(previous, out num))
                    {
                        unboxed.Add(previous, 1);
                    }
                    else
                    {
                        unboxed [previous] = ++num;
                    }
                    break;
                }
            }

            // report findings (one defect per variable/parameter/field)
            foreach (KeyValuePair <string, int> kvp in unboxed)
            {
                // we can't (always) avoid unboxing one time
                if (kvp.Value < 2)
                {
                    continue;
                }
                string s = String.Format(CultureInfo.InvariantCulture, kvp.Key, kvp.Value);
                Runner.Report(method, GetSeverityFromCount(kvp.Value), Confidence.Normal, s);
            }

            unboxed.Clear();
            return(Runner.CurrentRuleResult);
        }
Example #11
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            // rule applies only if the method has a body
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            // avoid looping if we're sure there's no Call[virt] or NewObj in the method
            if (!CallsNew.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            IList <Instruction> instructions = method.Body.Instructions;

            for (int i = 0; i < instructions.Count; i++)
            {
                Instruction ins = instructions [i];

                switch (ins.OpCode.FlowControl)
                {
                case FlowControl.Call:
                    MethodReference callee = (ins.Operand as MethodReference);
                    // check type name only if the call isn't virtual
                    bool virtual_call = (ins.OpCode.Code == Code.Callvirt);
                    // continue scanning unless we're calling ourself
                    if (!CompareMethods(method, callee, virtual_call))
                    {
                        break;
                    }

                    // recursion detected! check if there a way out of it
                    if (CheckForEndlessRecursion(method, i))
                    {
                        Runner.Report(method, ins, Severity.Critical, Confidence.High);
                        return(RuleResult.Failure);
                    }
                    break;

                case FlowControl.Cond_Branch:
                case FlowControl.Return:
                case FlowControl.Throw:
                    // if there's a way to break free before a recursive call then we let it go
                    return(RuleResult.Success);
                }
            }

            // should never be reached (since there's always a RET instruction)
            return(RuleResult.Success);
        }
Example #12
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            // rule applies only if the method has a body
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            // is there any bge*, bgt*, ble* or blt* instructions in the method ?
            if (!GreaterOrLesserThan.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                // check for specific cases like: '<', '>', '<=', '>='
                if (!GreaterOrLesserThan.Get(ins.OpCode.Code))
                {
                    continue;
                }

                // find the two values on stack
                Instruction current = ins.Previous;
                string      op1     = GetPrevious(method, ref current);
                if (op1.Length == 0)
                {
                    continue;
                }
                current = current.Previous;
                string op2 = GetPrevious(method, ref current);
                if (op2.Length == 0)
                {
                    continue;
                }

                // check value used immediately on both sides on the branch
                string next   = GetNext(method, ins.Next);
                string branch = GetNext(method, ins.Operand as Instruction);

                // if value before and after the branch match then we have a candidate
                if (((op1 == next) && (op2 == branch)) || ((op2 == next) && (op1 == branch)))
                {
                    Runner.Report(method, ins, Severity.Medium, Confidence.Normal);
                }
            }

            return(Runner.CurrentRuleResult);
        }
Example #13
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            // exclude methods that don't have calls
            OpCodeBitmask mask = OpCodeEngine.GetBitmask(method);

            if (!OpCodeBitmask.Calls.Intersect(mask))
            {
                return(RuleResult.DoesNotApply);
            }
            // *and* methods that don't convert into an [u]int64
            if (!Convert8.Intersect(mask))
            {
                return(RuleResult.DoesNotApply);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                if (ins.OpCode.FlowControl != FlowControl.Call)
                {
                    continue;
                }

                if (!IsInt64BitsToDouble(ins.Operand as MethodReference))
                {
                    continue;
                }

                // if the previous call convert a value into a long (int64)
                // then it's likely that the API is being misused
                switch (ins.Previous.OpCode.Code)
                {
                case Code.Conv_I8:
                case Code.Conv_U8:
                case Code.Conv_Ovf_I8:
                case Code.Conv_Ovf_I8_Un:
                case Code.Conv_Ovf_U8:
                case Code.Conv_Ovf_U8_Un:
                    Runner.Report(method, ins, Severity.High, Confidence.High);
                    break;
                }
            }
            return(Runner.CurrentRuleResult);
        }
Example #14
0
        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);
        }
Example #15
0
        protected override void CheckMethod(MethodDefinition method, bool abstractWarning)
        {
            if ((method == null) || !method.HasBody)
            {
                return;
            }

            OpCodeBitmask bitmask = OpCodeEngine.GetBitmask(method);

            // method must have a NEWOBJ and either STFLD or STELEM_REF
            if (!bitmask.Get(Code.Newobj) || !bitmask.Intersect(StoreFieldBitmask))
            {
                return;
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                if (!ins.Is(Code.Newobj))
                {
                    continue;
                }

                FieldDefinition field = null;
                Instruction     next  = ins.Next;
                if (next.Is(Code.Stfld))
                {
                    field = next.Operand as FieldDefinition;
                }
                else if (next.Is(Code.Stelem_Ref))
                {
                    Instruction origin = next.TraceBack(method);
                    if (origin != null)
                    {
                        field = origin.Operand as FieldDefinition;
                    }
                }

                if (field != null && FieldCandidates.Contains(field))
                {
                    Runner.Report(field, Severity.High, Confidence.High,
                                  abstractWarning ? AbstractTypeMessage : TypeMessage);
                }
            }
        }
Example #16
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!IsApplicable(method))
            {
                return(RuleResult.DoesNotApply);
            }

            // extra check - rule applies only if the method contains Ldc_R4 or Ldc_R8
            if (!Ldc_R.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            IList <Instruction> il = method.Body.Instructions;

            for (int i = 0; i < il.Count; i++)
            {
                Instruction ins = il [i];
                switch (ins.OpCode.Code)
                {
                // handle == and !=
                case Code.Ceq:
                    if (!CheckPrevious(il, i - 1))
                    {
                        Runner.Report(method, ins, Severity.Critical, Confidence.Total, EqualityMessage);
                    }
                    break;

                // handle calls to [Single|Double].Equals
                case Code.Call:
                case Code.Callvirt:
                    MemberReference callee = ins.Operand as MemberReference;
                    if ((callee != null) && (callee.Name == "Equals") && callee.DeclaringType.IsFloatingPoint())
                    {
                        if (!CheckPrevious(il, i - 1))
                        {
                            Runner.Report(method, ins, Severity.Critical, Confidence.Total, EqualsMessage);
                        }
                    }
                    break;
                }
            }
            return(Runner.CurrentRuleResult);
        }
Example #17
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            // check if the method creates array (Newarr)
            OpCodeBitmask bitmask = OpCodeEngine.GetBitmask(method);

            if (!bitmask.Get(Code.Newarr))
            {
                return(RuleResult.DoesNotApply);
            }
            // check if the method loads the 0 constant
            if (!bitmask.Intersect(zero))
            {
                return(RuleResult.DoesNotApply);
            }

            // look for array of Type creation
            foreach (Instruction ins in method.Body.Instructions)
            {
                if (ins.OpCode != OpCodes.Newarr)
                {
                    continue;
                }

                if (!(ins.Operand as TypeReference).IsNamed("System", "Type"))
                {
                    continue;
                }

                if (ins.Previous.IsOperandZero())
                {
                    Runner.Report(method, ins, Severity.Medium, Confidence.High);
                }
            }

            return(Runner.CurrentRuleResult);
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody || method.IsGeneratedCode())
            {
                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);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                MethodReference calledMethod = ins.GetMethod();
                if (calledMethod == null)
                {
                    continue;
                }
                if (!calledMethod.DeclaringType.IsNamed("System", "DateTime"))
                {
                    continue;
                }
                if (!MethodSignatures.op_Subtraction.Matches(calledMethod))
                {
                    continue;
                }

                if (CheckUsage(method, ins))
                {
                    Runner.Report(method, ins, Severity.Low, Confidence.High);
                }
            }

            return(Runner.CurrentRuleResult);
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            // rule does not apply to methods without IL
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            // avoid looping if we're sure there's no call in the method
            if (!CallsNew.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                // check for calls (or newobj)
                if (ins.OpCode.FlowControl != FlowControl.Call)
                {
                    continue;
                }

                // Check for usage of Process or Ping based on their presence
                if (process_present && CheckProcessSetPriorityClass(ins))
                {
                    // code won't work with default (non-root) users == High
                    Runner.Report(method, ins, Severity.High, Confidence.High, ProcessMessage);
                }
                else if (ping_present && CheckPing(ins))
                {
                    // code won't work with default (non-root) users == High
                    Runner.Report(method, ins, Severity.High, Confidence.High, PingMessage);
                }
            }

            return(Runner.CurrentRuleResult);
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            // rule doesn't apply if method has no IL
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            // check if any instruction refers to methods or types that MoMA could track
            if (!mask.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            // rule applies

            foreach (Instruction ins in method.Body.Instructions)
            {
                // look for any instruction that could use something incomplete
                if (!mask.Get(ins.OpCode.Code))
                {
                    continue;
                }

                // filter calls to assemblies that MoMA likely does not include (e.g. your own code)
                MethodReference mr = (ins.Operand as MethodReference);
                if ((mr == null) || !Filter(mr.DeclaringType.Scope as AssemblyNameReference))
                {
                    continue;
                }

                // MethodReference.ToString is costly so we do it once for the three checks
                string callee = mr.ToString();

                // calling not implemented method is very likely not to work == High
                if ((NotImplemented != null) && NotImplementedInternal.Contains(callee))
                {
                    string message = String.Format(NotImplementedMessage, callee);
                    // confidence is Normal since we can't be sure if MoMA data is up to date
                    Runner.Report(method, ins, Severity.High, Confidence.Normal, message);
                }

                // calling missing methods can't work == Critical
                if ((Missing != null) && Missing.Contains(callee))
                {
                    string message = String.Format(MissingMessage, callee);
                    Runner.Report(method, ins, Severity.Critical, Confidence.Normal, message);
                }

                // calling todo methods migh work with some limitations == Medium
                if (ToDo != null)
                {
                    string value;
                    if (ToDo.TryGetValue(callee, out value))
                    {
                        string message = String.Format(TodoMessage, callee, value);
                        Runner.Report(method, ins, Severity.Medium, Confidence.Normal, message);
                    }
                }
            }

            return(Runner.CurrentRuleResult);
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            //is there any potential IDisposable-getting opcode in the method?
            if (!callsAndNewobjBitmask.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            // we will not report IDiposable locals that are returned from a method
            bool return_idisposable = DoesReturnDisposable(method);

            locals.ClearAll();

            foreach (Instruction ins in method.Body.Instructions)
            {
                Code code = ins.OpCode.Code;
                switch (code)
                {
                case Code.Ret:
                    if (return_idisposable)
                    {
                        CheckForReturn(method, ins.Previous);
                    }
                    continue;

                case Code.Stind_Ref:
                    CheckForOutParameters(method, ins);
                    continue;

                default:
                    if (!callsAndNewobjBitmask.Get(code))
                    {
                        continue;
                    }
                    break;
                }

                MethodReference call = (MethodReference)ins.Operand;

                if (IsDispose(call))
                {
                    CheckDisposeCalls(method, ins);
                    continue;
                }

                if (call.HasThis && (code != Code.Newobj))
                {
                    if (!CheckCallsToOtherInstances(method, ins, call))
                    {
                        continue;
                    }
                }

                if (!DoesReturnDisposable(call))
                {
                    continue;
                }

                Instruction nextInstruction = ins.Next;
                if (nextInstruction == null)
                {
                    continue;
                }

                Code nextCode = nextInstruction.OpCode.Code;
                if (nextCode == Code.Pop || OpCodeBitmask.Calls.Get(nextCode))
                {
                    // We ignore setter because it is an obvious share of the IDisposable
                    if (!IsSetter(nextInstruction.Operand as MethodReference))
                    {
                        ReportCall(method, ins, call);
                    }
                }
                else if (nextInstruction.IsStoreLocal())
                {
                    // make sure we're not re-assigning over a non-disposed IDisposable
                    CheckReassignment(method, nextInstruction);
                }
            }

            ReportNonDisposedLocals(method);

            return(Runner.CurrentRuleResult);
        }
Example #22
0
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            // no chain are possible without Call[virt] instructions within the method
            OpCodeBitmask calls = OpCodeBitmask.Calls;

            if (!calls.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            Log.WriteLine(this);
            Log.WriteLine(this, "-------------------------------------");
            Log.WriteLine(this, method);

            // walk back so we don't process very long chains multiple times
            // (we don't need to go down to zero since it would not be big enough for a chain to exists)
            IList <Instruction> ic = method.Body.Instructions;

            for (int i = ic.Count - 1; i >= MaxChainLength; i--)
            {
                Instruction ins = ic [i];
                // continue until we find a Call[virt] instruction
                if (!calls.Get(ins.OpCode.Code))
                {
                    continue;
                }

                // operators "break" chains
                MethodReference mr = (ins.Operand as MethodReference);
                if (mr.Name.StartsWith("op_", StringComparison.Ordinal))
                {
                    continue;
                }

                int counter = 1;
                // trace back every call (including new objects and arrays) and
                // check if the caller is a call (i.e. not a local)
                Instruction caller = ins.TraceBack(method);
                while ((caller != null) && ValidLink(caller))
                {
                    counter++;
                    i      = ic.IndexOf(caller);
                    caller = caller.TraceBack(method);
                }
                Log.WriteLine(this, "chain of length {0} at {1:X4}", counter, ins.Offset);

                if (counter > MaxChainLength)
                {
                    string msg = String.Format(CultureInfo.CurrentCulture,
                                               "Chain length {0} versus maximum of {1}.", counter, MaxChainLength);
                    Runner.Report(method, ins, Severity.Medium, Confidence.Normal, msg);
                }
            }

            return(Runner.CurrentRuleResult);
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody || method.IsGeneratedCode())
            {
                return(RuleResult.DoesNotApply);
            }

            // exclude methods that don't store fields or arguments
            if (!mask.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            foreach (Instruction ins in method.Body.Instructions)
            {
                Instruction next = ins.Next;
                if (next == null)
                {
                    continue;
                }

                if (next.OpCode.Code == Code.Stfld)
                {
                    // is it the same (instance) field ?
                    CheckFields(ins, next, method, false);
                }
                else if (next.OpCode.Code == Code.Stsfld)
                {
                    // is it the same (static) field ?
                    CheckFields(ins, next, method, true);
// too much false positive because compilers add their own variables
// and don't always "play well" with them
#if false
                }
                else if (ins.IsLoadLocal() && next.IsStoreLocal())
                {
                    VariableDefinition variable = next.GetVariable(method);
                    if (variable == ins.GetVariable(method))
                    {
                        // the compiler often introduce it's own variable
                        if (!variable.Name.StartsWith("V_"))
                        {
                            msg = String.Format("Variable '{0}' of type '{1}'.", variable.Name, variable.VariableType.GetFullName());
                        }
                    }
#endif
                }
                else if (ins.IsLoadArgument() && next.IsStoreArgument())
                {
                    ParameterDefinition parameter = next.GetParameter(method);
                    if (parameter == ins.GetParameter(method))
                    {
                        string msg = String.Format(CultureInfo.InvariantCulture,
                                                   "Parameter '{0}' of type '{1}'.",
                                                   parameter.Name, parameter.ParameterType.GetFullName());
                        Runner.Report(method, ins, Severity.Medium, Confidence.Normal, msg);
                    }
                }
            }
            return(Runner.CurrentRuleResult);
        }
        public RuleResult CheckMethod(MethodDefinition method)
        {
            if (!method.HasBody)
            {
                return(RuleResult.DoesNotApply);
            }

            OpCodeBitmask calls = OpCodeBitmask.Calls;

            if (!calls.Intersect(OpCodeEngine.GetBitmask(method)))
            {
                return(RuleResult.DoesNotApply);
            }

            Log.WriteLine(this, "--------------------------------------");
            Log.WriteLine(this, method);

            // Loop through each instruction,
            foreach (Instruction ins in method.Body.Instructions)
            {
                // if we're calling a method,
                if (!calls.Get(ins.OpCode.Code))
                {
                    continue;
                }

                // and the method is a System.Linq.Enumerable method then,
                var target = ins.Operand as MethodReference;
                if (!target.DeclaringType.IsNamed("System.Linq", "Enumerable"))
                {
                    continue;
                }

                string tname  = target.Name;
                int    tcount = target.HasParameters ? target.Parameters.Count : 0;
                // see if we can use a more efficient method.
                if (tname == "Count" && tcount == 1)
                {
                    TypeReference tr = ins.Previous.GetOperandType(method);
                    if (tr != null)
                    {
                        CheckForCountProperty(tr, method, ins);
                        CheckForAny(method, ins);
                    }
                }
                else if ((tname == "ElementAt" || tname == "ElementAtOrDefault") && tcount == 2)
                {
                    Instruction   arg = ins.TraceBack(method);
                    TypeReference tr  = arg.GetOperandType(method);
                    if (tr != null)
                    {
                        CheckForSubscript(tr, method, ins, tname);
                    }
                }
                else if ((tname == "Last" || tname == "LastOrDefault") && tcount == 1)
                {
                    TypeReference tr = ins.Previous.GetOperandType(method);
                    if (tr != null)
                    {
                        CheckForSubscript(tr, method, ins, tname);
                    }
                }
                else if (tname == "OrderBy" || tname == "OrderByDescending")
                {
                    Instruction   arg = ins.TraceBack(method);
                    TypeReference tr  = arg.GetOperandType(method);
                    if (tr != null)
                    {
                        CheckForSort(tr, method, ins, tname);
                    }
                }
            }

            return(Runner.CurrentRuleResult);
        }