[w32handle] Stop returning 0 in every cases for locking/unlocking (#3926)
[mono.git] / mcs / tools / tuner / Mono.Tuner / InjectSecurityAttributes.cs
index 215d450a3412c2cb8a0013a450ecb1df486c4b68..9489876ae97ecf057ef636e6b7072f3d174ef0a0 100644 (file)
 using System;
 using System.Collections;
 using System.IO;
+using System.Linq;
 using System.Text;
 
 using Mono.Linker;
 using Mono.Linker.Steps;
 
 using Mono.Cecil;
+using Mono.Cecil.Cil;
 
 namespace Mono.Tuner {
 
@@ -45,13 +47,14 @@ namespace Mono.Tuner {
                        Method,
                }
 
-               enum AttributeType {
+               protected enum AttributeType {
                        Critical,
                        SafeCritical,
                }
 
                const string _safe_critical = "System.Security.SecuritySafeCriticalAttribute";
                const string _critical = "System.Security.SecurityCriticalAttribute";
+               const string _system_void = "System.Void";
 
                const string sec_attr_folder = "secattrs";
 
@@ -59,6 +62,7 @@ namespace Mono.Tuner {
 
                MethodDefinition _safe_critical_ctor;
                MethodDefinition _critical_ctor;
+               TypeDefinition _void_type;
 
                string data_folder;
 
@@ -99,39 +103,40 @@ namespace Mono.Tuner {
                protected void RemoveSecurityAttributes ()
                {
                        foreach (TypeDefinition type in _assembly.MainModule.Types) {
-                               RemoveSecurityAttributes (type);
-
-                               if (type.HasConstructors)
-                                       foreach (MethodDefinition ctor in type.Constructors)
-                                               RemoveSecurityAttributes (ctor);
-
-                               if (type.HasMethods)
-                                       foreach (MethodDefinition method in type.Methods)
-                                               RemoveSecurityAttributes (method);
+                               if (RemoveSecurityAttributes (type))
+                                       type.HasSecurity = false;
+
+                               if (type.HasMethods) {
+                                       foreach (MethodDefinition method in type.Methods) {
+                                               if (RemoveSecurityAttributes (method))
+                                                       method.HasSecurity = false;
+                                       }
+                               }
                        }
                }
 
-               static void RemoveSecurityDeclarations (IHasSecurity provider)
+               static bool RemoveSecurityDeclarations (ISecurityDeclarationProvider provider)
                {
                        // also remove already existing CAS security declarations
 
                        if (provider == null)
-                               return;
+                               return false;
 
                        if (!provider.HasSecurityDeclarations)
-                               return;
+                               return false;
 
                        provider.SecurityDeclarations.Clear ();
+                       return true;
                }
 
-               static void RemoveSecurityAttributes (ICustomAttributeProvider provider)
+               static bool RemoveSecurityAttributes (ICustomAttributeProvider provider)
                {
-                       RemoveSecurityDeclarations (provider as IHasSecurity);
+                       bool result = RemoveSecurityDeclarations (provider as ISecurityDeclarationProvider);
 
                        if (!provider.HasCustomAttributes)
-                               return;
+                               return result;
 
-                       CustomAttributeCollection attributes = provider.CustomAttributes;
+                       var attributes = provider.CustomAttributes;
                        for (int i = 0; i < attributes.Count; i++) {
                                CustomAttribute attribute = attributes [i];
                                switch (attribute.Constructor.DeclaringType.FullName) {
@@ -141,6 +146,7 @@ namespace Mono.Tuner {
                                        break;
                                }
                        }
+                       return result;
                }
 
                void ProcessSecurityAttributeFile (string file)
@@ -154,7 +160,7 @@ namespace Mono.Tuner {
 
                void ProcessLine (string line)
                {
-                       if (line == null || line.Length < 6)
+                       if (line == null || line.Length < 6 || line [0] == '#')
                                return;
 
                        int sep = line.IndexOf (": ");
@@ -192,11 +198,75 @@ namespace Mono.Tuner {
                        }
                }
 
+               public static bool NeedsDefaultConstructor (TypeDefinition type)
+               {
+                       if (type.IsInterface)
+                               return false;
+
+                       TypeReference base_type = type.BaseType;
+                       if ((base_type == null) || (base_type.Namespace != "System"))
+                               return true;
+
+                       return ((base_type.Name != "Delegate") && (base_type.Name != "MulticastDelegate"));
+               }
+
                void ProcessSecurityAttributeEntry (AttributeType type, TargetKind kind, string target)
                {
                        ICustomAttributeProvider provider = GetTarget (kind, target);
-                       if (provider == null)
+                       if (provider == null) {
+                               Console.Error.WriteLine ("Warning: entry '{0}' could not be found", target);
                                return;
+                       }
+
+                       // we need to be smarter when applying the attributes (mostly SC) to types
+                       if (kind == TargetKind.Type) {
+                               TypeDefinition td = (provider as TypeDefinition);
+                               // ensure [SecurityCritical] types (well most) have a default constructor
+                               if ((type == AttributeType.Critical) && NeedsDefaultConstructor (td)) {
+                                       if (GetDefaultConstructor (td) == null) {
+                                               // Console.Error.WriteLine ("Info: adding default ctor for '{0}'", td);
+                                               td.Methods.Add (CreateDefaultConstructor ());
+                                       }
+                               }
+
+                               // it's easier for some tools (e.g. less false positives in fxcop) 
+                               // and also quicker for the runtime (one less lookup) if all methods gets decorated
+                               foreach (MethodDefinition method in td.Methods) {
+                                       bool skip = false;
+
+                                       AttributeType mtype = type;
+                                       // there are cases where an SC cannot be applied to some methods
+                                       switch (method.Name) {
+                                       // e.g. everything we override from System.Object (which is transparent)
+                                       case "Equals":
+                                               skip = method.Parameters.Count == 1 && method.Parameters [0].ParameterType.FullName == "System.Object";
+                                               break;
+                                       case "Finalize":
+                                       case "GetHashCode":
+                                       case "ToString":
+                                               skip = !method.HasParameters;
+                                               break;
+                                       // e.g. some transparent interfaces, like IDisposable (implicit or explicit)
+                                       // downgrade some SC into SSC to respect the override/inheritance rules
+                                       case "System.IDisposable.Dispose":
+                                       case "Dispose":
+                                               skip = !method.HasParameters;
+                                               break;
+                                       }
+
+                                       if (skip)
+                                               continue;
+
+                                       switch (mtype) {
+                                       case AttributeType.Critical:
+                                               AddCriticalAttribute (method);
+                                               break;
+                                       case AttributeType.SafeCritical:
+                                               AddSafeCriticalAttribute (method);
+                                               break;
+                                       }
+                               }
+                       }
 
                        switch (type) {
                        case AttributeType.Critical:
@@ -231,7 +301,7 @@ namespace Mono.Tuner {
                        if (HasSecurityAttribute (provider, type))
                                return;
 
-                       CustomAttributeCollection attributes = provider.CustomAttributes;
+                       var attributes = provider.CustomAttributes;
                        switch (type) {
                        case AttributeType.Critical:
                                attributes.Add (CreateCriticalAttribute ());
@@ -242,7 +312,7 @@ namespace Mono.Tuner {
                        }
                }
 
-               static bool HasSecurityAttribute (ICustomAttributeProvider provider, AttributeType type)
+               protected static bool HasSecurityAttribute (ICustomAttributeProvider provider, AttributeType type)
                {
                        if (!provider.HasCustomAttributes)
                                return false;
@@ -279,7 +349,7 @@ namespace Mono.Tuner {
 
                TypeDefinition GetType (string fullname)
                {
-                       return _assembly.MainModule.Types [fullname];
+                       return _assembly.MainModule.GetType (fullname);
                }
 
                MethodDefinition GetMethod (string signature)
@@ -306,9 +376,7 @@ namespace Mono.Tuner {
                        if (type == null)
                                return null;
 
-                       return method_name.StartsWith (".c") ?
-                               GetMethod (type.Constructors, signature) :
-                               GetMethod (type.Methods, signature);
+                       return GetMethod (type.Methods, signature);
                }
 
                static MethodDefinition GetMethod (IEnumerable methods, string signature)
@@ -322,10 +390,13 @@ namespace Mono.Tuner {
 
                static string GetFullName (MethodReference method)
                {
-                       int sentinel = method.GetSentinel ();
+                       var sentinel = method.Parameters.FirstOrDefault (p => p.ParameterType.IsSentinel);
+                       var sentinel_pos = -1;
+                       if (sentinel != null)
+                               sentinel_pos = method.Parameters.IndexOf (sentinel);
 
                        StringBuilder sb = new StringBuilder ();
-                       sb.Append (method.ReturnType.ReturnType.FullName);
+                       sb.Append (method.ReturnType.FullName);
                        sb.Append (" ");
                        sb.Append (method.DeclaringType.FullName);
                        sb.Append ("::");
@@ -345,7 +416,7 @@ namespace Mono.Tuner {
                                        if (i > 0)
                                                sb.Append (",");
 
-                                       if (i == sentinel)
+                                       if (i == sentinel_pos)
                                                sb.Append ("...,");
 
                                        sb.Append (method.Parameters [i].ParameterType.FullName);
@@ -357,8 +428,8 @@ namespace Mono.Tuner {
 
                static MethodDefinition GetDefaultConstructor (TypeDefinition type)
                {
-                       foreach (MethodDefinition ctor in type.Constructors)
-                               if (ctor.Parameters.Count == 0)
+                       foreach (MethodDefinition ctor in type.Methods.Where (m => m.IsConstructor))
+                               if (!ctor.IsStatic && !ctor.HasParameters)
                                        return ctor;
 
                        return null;
@@ -372,7 +443,7 @@ namespace Mono.Tuner {
                        TypeDefinition safe_critical_type = Context.GetType (_safe_critical);
                        if (safe_critical_type == null)
                                throw new InvalidOperationException (String.Format ("{0} type not found", _safe_critical));
-                       
+
                        _safe_critical_ctor = GetDefaultConstructor (safe_critical_type);
                        return _safe_critical_ctor;
                }
@@ -385,11 +456,23 @@ namespace Mono.Tuner {
                        TypeDefinition critical_type = Context.GetType (_critical);
                        if (critical_type == null)
                                throw new InvalidOperationException (String.Format ("{0} type not found", _critical));
-                       
+
                        _critical_ctor = GetDefaultConstructor (critical_type);
                        return _critical_ctor;
                }
 
+               TypeDefinition GetSystemVoid ()
+               {
+                       if (_void_type != null)
+                               return _void_type;
+
+                       _void_type = Context.GetType (_system_void);
+                       if (_void_type == null)
+                               throw new InvalidOperationException (String.Format ("{0} type not found", _system_void));
+
+                       return _void_type;
+               }
+
                MethodReference Import (MethodDefinition method)
                {
                        return _assembly.MainModule.Import (method);
@@ -404,5 +487,14 @@ namespace Mono.Tuner {
                {
                        return new CustomAttribute (Import (GetCriticalCtor ()));
                }
+
+               MethodDefinition CreateDefaultConstructor ()
+               {
+                       MethodDefinition method = new MethodDefinition (".ctor", 
+                               MethodAttributes.HideBySig | MethodAttributes.SpecialName | MethodAttributes.RTSpecialName, 
+                               GetSystemVoid ());
+                       method.Body.Instructions.Add (Instruction.Create (OpCodes.Ret));
+                       return method;
+               }
        }
 }