Author: spouliot
Date: 2008-02-15 14:19:05 -0500 (Fri, 15 Feb 2008)
New Revision: 95794

Modified:
   trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/ChangeLog
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/GetLastErrorMustBeCalledRightAfterPInvokeRule.cs
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/MarshalStringsInPInvokeDeclarationsRule.cs
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/PInvokeShouldNotBeVisibleRule.cs
   
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/UseManagedAlternativesToPInvokeRule.cs
Log:
2008-02-15  Sebastien Pouliot  <[EMAIL PROTECTED]>

        * GetLastErrorMustBeCalledRightAfterPInvokeRule.cs
        * MarshalStringsInPInvokeDeclarationsRule.cs
        * PInvokeShouldNotBeVisibleRule.cs
        * UseManagedAlternativesToPInvokeRule.cs:
                Update rules wrt framework changes.



Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/ChangeLog
===================================================================
--- trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/ChangeLog   
2008-02-15 19:17:14 UTC (rev 95793)
+++ trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/ChangeLog   
2008-02-15 19:19:05 UTC (rev 95794)
@@ -1,3 +1,11 @@
+2008-02-15  Sebastien Pouliot  <[EMAIL PROTECTED]>
+
+       * GetLastErrorMustBeCalledRightAfterPInvokeRule.cs
+       * MarshalStringsInPInvokeDeclarationsRule.cs
+       * PInvokeShouldNotBeVisibleRule.cs
+       * UseManagedAlternativesToPInvokeRule.cs:
+               Update rules wrt framework changes.
+
 2008-01-30  Sebastien Pouliot  <[EMAIL PROTECTED]>
 
        * GetLastErrorMustBeCalledRightAfterPInvokeRule.cs: Changed to

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/GetLastErrorMustBeCalledRightAfterPInvokeRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/GetLastErrorMustBeCalledRightAfterPInvokeRule.cs
    2008-02-15 19:17:14 UTC (rev 95793)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/GetLastErrorMustBeCalledRightAfterPInvokeRule.cs
    2008-02-15 19:19:05 UTC (rev 95794)
@@ -26,17 +26,21 @@
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 //
 
+using System;
 using System.Collections.Generic;
 
 using Mono.Cecil;
 using Mono.Cecil.Cil;
 
 using Gendarme.Framework;
+using Gendarme.Framework.Helpers;
 using Gendarme.Framework.Rocks;
 
 namespace Gendarme.Rules.Interoperability {
 
-       public class GetLastErrorMustBeCalledRightAfterPInvokeRule : 
IMethodRule {
+       [Problem ("GetLastError() should be called immediately after this the 
P/Invoke call.")]
+       [Solution ("Move the call to GetLastError just after the P/Invoke 
call.")]
+       public class GetLastErrorMustBeCalledRightAfterPInvokeRule : Rule, 
IMethodRule {
 
                struct Branch {
                        public readonly Instruction Instruction;
@@ -49,6 +53,8 @@
                        }
                }
 
+               private const string Message = "GetLastError() should be called 
immediately after this the PInvoke call.";
+
                private const string GetLastError = "System.Int32 
System.Runtime.InteropServices.Marshal::GetLastWin32Error()";
                private List<string> AllowedCalls;
 
@@ -62,7 +68,7 @@
 
                List<Branch> branches = new List<Branch> ();
 
-               private bool CheckPInvoke (MethodDefinition pinvoke, 
Instruction startInstruction)
+               private bool CheckPInvoke (Instruction startInstruction)
                {
                        branches.Clear ();
                        branches.Add (new Branch (startInstruction.Next, 
false));
@@ -102,8 +108,9 @@
                                                break;
 
                                        if (alternatives != null) {
-                                               if (alternatives is 
Instruction) {
-                                                       branches.AddIfNew (new 
Branch ((Instruction) alternatives, dirty));
+                                               Instruction alt_ins = 
(alternatives as Instruction);
+                                               if (alt_ins != null) {
+                                                       branches.AddIfNew (new 
Branch (alt_ins, dirty));
                                                } else {
                                                        Instruction [] alts = 
(Instruction []) alternatives;
                                                        foreach (Instruction 
altIns in alts)
@@ -124,13 +131,12 @@
                        return true;
                }
 
-               public MessageCollection CheckMethod (MethodDefinition method, 
Runner runner)
+               public RuleResult CheckMethod (MethodDefinition method)
                {
+                       // rule does not apply if the method has no IL
                        if (!method.HasBody)
-                               return runner.RuleSuccess;
+                               return RuleResult.DoesNotApply;
 
-                       MessageCollection results = null;
-
                        foreach (Instruction ins in method.Body.Instructions) {
                                switch (ins.OpCode.Code) {
                                case Code.Call:
@@ -150,21 +156,18 @@
                                                break;
 
                                        // check if GetLastError is called near 
enough this pinvoke call
-                                       if (CheckPInvoke (pinvoke, ins))
+                                       if (CheckPInvoke (ins))
                                                break;
 
-                                       if (results == null)
-                                               results = new MessageCollection 
();
-                                       Location loc = new Location (method, 
ins.Offset);
-                                       Message msg = new Message 
("GetLastError() should be called immediately after this the PInvoke call.", 
loc, MessageType.Error);
-                                       results.Add (msg);
+                                       // code might not work if an error 
occurs
+                                       Runner.Report (method, ins, 
Severity.High, Confidence.High, String.Empty);
                                        break;
                                default:
                                        break;
                                }
                        }
 
-                       return results;
+                       return Runner.CurrentRuleResult;
                }
        }
 }

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/MarshalStringsInPInvokeDeclarationsRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/MarshalStringsInPInvokeDeclarationsRule.cs
  2008-02-15 19:17:14 UTC (rev 95793)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/MarshalStringsInPInvokeDeclarationsRule.cs
  2008-02-15 19:19:05 UTC (rev 95794)
@@ -33,38 +33,39 @@
 
 namespace Gendarme.Rules.Interoperability {
 
-       public class MarshalStringsInPInvokeDeclarationsRule : IMethodRule {
+       [Problem ("Marshaling information for string types is incomplete and 
what is required may be different from what you expected the default to be.")]
+       [Solution ("Add [DllImport CharSet=] on the method or [MarshalAs] on 
the parameter(s)")]
+       public class MarshalStringsInPInvokeDeclarationsRule : Rule, 
IMethodRule {
 
                private static bool IsStringOrSBuilder (TypeReference reference)
                {
-                       TypeReference original = reference.GetOriginalType ();
-                       return original.FullName == "System.String" || 
original.FullName == "System.Text.StringBuilder";
+                       switch (reference.GetOriginalType ().FullName) {
+                       case "System.String":
+                       case "System.Text.StringBuilder":
+                               return true;
+                       default:
+                               return false;
+                       }
                }
 
-               private static void AddBadParameterMessage (ref 
MessageCollection messages, ParameterDefinition param)
+               public RuleResult CheckMethod (MethodDefinition method)
                {
-                       if (messages == null)
-                               messages = new MessageCollection ();
+                       // rule does not apply to non-pinvoke methods
+                       if (!method.IsPInvokeImpl)
+                               return RuleResult.DoesNotApply;
 
-                       Location loc = new Location (param.Method as 
MethodDefinition);
-                       string text = string.Format ("Parameter '{0}', of type 
'{1}', does not have [MarshalAs] attribute, yet no [DllImport CharSet=] is set 
for the method '{2}'.", 
-                               param.Name, param.ParameterType.Name, 
param.Method.Name);
-                       Message msg = new Message (text, loc, 
MessageType.Error);
-                       messages.Add (msg);
-               }
+                       if (!method.PInvokeInfo.IsCharSetNotSpec)
+                               return RuleResult.Success;
 
-               public MessageCollection CheckMethod (MethodDefinition method, 
Runner runner)
-               {
-                       if (!method.IsPInvokeImpl || 
!method.PInvokeInfo.IsCharSetNotSpec)
-                               return runner.RuleSuccess;
-
-                       MessageCollection messages = runner.RuleSuccess;
                        foreach (ParameterDefinition parameter in 
method.Parameters) {
                                if (IsStringOrSBuilder 
(parameter.ParameterType) && (parameter.MarshalSpec == null)) {
-                                       AddBadParameterMessage (ref messages, 
parameter);
+                                       string text = string.Format ("Parameter 
'{0}', of type '{1}', does not have [MarshalAs] attribute, yet no [DllImport 
CharSet=] is set for the method '{2}'.",
+                                               parameter.Name, 
parameter.ParameterType.Name, parameter.Method.Name);
+                                       Runner.Report (parameter, 
Severity.High, Confidence.Total, text);
                                }
                        }
-                       return messages;
+
+                       return Runner.CurrentRuleResult;
                }
        }
 }

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/PInvokeShouldNotBeVisibleRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/PInvokeShouldNotBeVisibleRule.cs
    2008-02-15 19:17:14 UTC (rev 95793)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/PInvokeShouldNotBeVisibleRule.cs
    2008-02-15 19:19:05 UTC (rev 95794)
@@ -31,32 +31,30 @@
 using Mono.Cecil;
 
 using Gendarme.Framework;
+using Gendarme.Framework.Rocks;
 
 namespace Gendarme.Rules.Interoperability {
 
-       public class PInvokeShouldNotBeVisibleRule : IMethodRule {
+       [Problem ("P/Invoke declarations should not be visible outside of the 
assembly.")]
+       [Solution ("Wrap the p/invoke call into a managed class/method and 
include parameters, and result, validation(s).")]
+       public class PInvokeShouldNotBeVisibleRule : Rule, IMethodRule {
 
-               public MessageCollection CheckMethod (MethodDefinition method, 
Runner runner)
+               public RuleResult CheckMethod (MethodDefinition method)
                {
+                       // rule does not apply to non-p/invoke
                        if (!method.IsPInvokeImpl)
-                               return runner.RuleSuccess;
+                               return RuleResult.DoesNotApply;
+                       
+                       // rule applies
+                       
+                       // ok if method is not visible (this include it's 
declaring type too)
+                       if (!method.IsVisible ())
+                               return RuleResult.Success;
 
-                       if (!method.IsPublic)
-                               return runner.RuleSuccess;
-
-                       TypeDefinition type = (TypeDefinition) 
method.DeclaringType;
-
-                       while (type.IsNested) {
-                               if (!type.IsNestedPublic)
-                                       return runner.RuleSuccess;
-                               type = (TypeDefinition) type.DeclaringType;
-                       }
-                       if (!type.IsPublic)
-                               return runner.RuleSuccess;
-
-                       Location loc = new Location (method);
-                       Message msg = new Message ("P/Invoke declarations 
should not be visible outside of the assembly.", loc, MessageType.Warning);
-                       return new MessageCollection (msg);
+                       // code will work (low) but it's bad design 
(non-fx-like validations) and makes
+                       // it easier to expose security vulnerabilities
+                       Runner.Report (method, Severity.Low, Confidence.Total, 
String.Empty);
+                       return RuleResult.Failure;
                }
        }
 }

Modified: 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/UseManagedAlternativesToPInvokeRule.cs
===================================================================
--- 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/UseManagedAlternativesToPInvokeRule.cs
      2008-02-15 19:17:14 UTC (rev 95793)
+++ 
trunk/mono-tools/gendarme/rules/Gendarme.Rules.Interoperability/UseManagedAlternativesToPInvokeRule.cs
      2008-02-15 19:19:05 UTC (rev 95794)
@@ -37,7 +37,9 @@
 
 namespace Gendarme.Rules.Interoperability {
 
-       public class UseManagedAlternativesToPInvokeRule : IMethodRule {
+       [Problem ("There is a potential managed API for the p/invoke 
declaration.")]
+       [Solution ("Use the suggested managed alternative to your p/invoke call 
and remove it's declaration.")]
+       public class UseManagedAlternativesToPInvokeRule : Rule, IMethodRule {
 
                private struct PInvokeCall {
 
@@ -89,7 +91,7 @@
                        }
                }
 
-               private class ManagedAlternatives {
+               private sealed class ManagedAlternatives {
 
                        private List<string> alternatives = new List<string> ();
                        private TargetRuntime runtime;
@@ -122,59 +124,45 @@
                        }
                }
 
-               private static Dictionary<PInvokeCall, ManagedAlternatives> 
managedAlternatives;
+               private static Dictionary<PInvokeCall, ManagedAlternatives> 
managedAlternatives =
+                       new Dictionary<PInvokeCall, ManagedAlternatives> () {
+                               { new PInvokeCall ("kernel32.dll", "Sleep"), 
new ManagedAlternatives ("System.Threading.Thread::Sleep ()") },
+                               { new PInvokeCall ("kernel32.dll", 
"FindFirstFile"), new ManagedAlternatives ("System.IO.Directory::GetDirectories 
()", "System.IO.Directory::GetFiles ()", 
"System.IO.Directory::GetFileSystemEntries ()") },
+                               { new PInvokeCall ("kernel32.dll", "ReadFile"), 
new ManagedAlternatives ("System.IO.FileStream") },
+                               { new PInvokeCall ("kernel32.dll", 
"WaitForMultipleObjects"), new ManagedAlternatives 
("System.Threading.WaitHandle::WaitAny ()", 
"System.Threading.WaitHandle::WaitAll ()") },
+                               { new PInvokeCall ("kernel32.dll", 
"GetLastError"), new ManagedAlternatives 
("System.Runtime.InteropServices.Marshal::GetLastWin32Error ()") },
+                               { new PInvokeCall ("user32.dll", "MessageBox"), 
new ManagedAlternatives ("System.Windows.Forms.MessageBox::Show ()") },
+                               { new PInvokeCall ("kernel32.dll", "Beep"), new 
ManagedAlternatives (TargetRuntime.NET_2_0, "System.Console::Beep ()") },
+                               { new PInvokeCall ("winmm.dll", "PlaySound"), 
new ManagedAlternatives (TargetRuntime.NET_2_0, "System.Media.SoundPlayer") }
+                       };
 
-               static UseManagedAlternativesToPInvokeRule ()
-               {
-                       managedAlternatives = new Dictionary<PInvokeCall, 
ManagedAlternatives> ();
-                       managedAlternatives.Add (new PInvokeCall 
("kernel32.dll", "Sleep"),
-                                                new ManagedAlternatives 
("System.Threading.Thread::Sleep ()"));
-                       managedAlternatives.Add (new PInvokeCall 
("kernel32.dll", "FindFirstFile"),
-                                                new ManagedAlternatives 
("System.IO.Directory::GetDirectories ()", "System.IO.Directory::GetFiles ()", 
"System.IO.Directory::GetFileSystemEntries ()"));
-                       managedAlternatives.Add (new PInvokeCall 
("kernel32.dll", "ReadFile"),
-                                                new ManagedAlternatives 
("System.IO.FileStream"));
-                       managedAlternatives.Add (new PInvokeCall 
("kernel32.dll", "WaitForMultipleObjects"),
-                                                new ManagedAlternatives 
("System.Threading.WaitHandle::WaitAny ()", 
"System.Threading.WaitHandle::WaitAll ()"));
-                       managedAlternatives.Add (new PInvokeCall 
("kernel32.dll", "GetLastError"),
-                                                new ManagedAlternatives 
("System.Runtime.InteropServices.Marshal::GetLastWin32Error ()"));
-                       managedAlternatives.Add (new PInvokeCall ("user32.dll", 
"MessageBox"),
-                                                new ManagedAlternatives 
("System.Windows.Forms.MessageBox::Show ()"));
-                       managedAlternatives.Add (new PInvokeCall 
("kernel32.dll", "Beep"),
-                                                new ManagedAlternatives 
(TargetRuntime.NET_2_0, "System.Console::Beep ()"));
-                       managedAlternatives.Add (new PInvokeCall ("winmm.dll", 
"PlaySound"),
-                                                new ManagedAlternatives 
(TargetRuntime.NET_2_0, "System.Media.SoundPlayer"));
-               }
-
                private static ManagedAlternatives GetManagedAlternatives 
(MethodDefinition method, TargetRuntime runtime)
                {
                        string moduleName = method.PInvokeInfo.Module.Name;
                        PInvokeCall callInfo = new PInvokeCall (moduleName, 
method.Name);
                        if (managedAlternatives.ContainsKey (callInfo)) {
                                ManagedAlternatives alts = managedAlternatives 
[callInfo];
-                               if (IsRuntimeVersionGreaterOrEqual (runtime, 
alts.Runtime))
+                               if (runtime >= alts.Runtime)
                                        return alts;
                        }
                        return null;
                }
 
-               private static bool IsRuntimeVersionGreaterOrEqual 
(TargetRuntime a, TargetRuntime b)
+               public RuleResult CheckMethod (MethodDefinition method)
                {
-                       return (int) a >= (int) b; // as of now it works (and 
should work further)
-               }
-
-               public MessageCollection CheckMethod (MethodDefinition method, 
Runner runner)
-               {
+                       // rule does not apply to non-pinvoke methods
                        if (!method.IsPInvokeImpl)
-                               return runner.RuleSuccess;
+                               return RuleResult.DoesNotApply;
 
+                       // rule apply, looks for alternatives
+
                        ManagedAlternatives alternatives = 
GetManagedAlternatives (method, method.DeclaringType.Module.Assembly.Runtime);
                        if (alternatives == null)
-                               return runner.RuleSuccess;
+                               return RuleResult.Success;
 
-                       Location loc = new Location (method);
                        string message = string.Format ("Do not perform 
platform-dependent call ({0}) if it can be avoided. Use (one of) the following 
alternative(s) provided by .NET Framework: {1}.", method.Name, alternatives);
-                       Message msg = new Message (message, loc, 
MessageType.Warning);
-                       return new MessageCollection (msg);
+                       Runner.Report (method, Severity.Low, Confidence.High, 
message);
+                       return RuleResult.Failure;
                }
        }
 }

_______________________________________________
Mono-patches maillist  -  [email protected]
http://lists.ximian.com/mailman/listinfo/mono-patches

Reply via email to