Search code examples
c#deterministicnon-deterministic

Ensure that c# Assemby are deterministic


It is possible to restrict specific classes, such as Random or DateTime, or the use of float in an AppDomain. Is it possible to detect it by reflection if you use them? or should we look at the IL code?

I would like to make a plugin system, but I have to make sure that the executed code is deterministic. Any other ideas on how to deal with it?

Thanks.


Solution

  • Creating Type white list is possible to do that job

     readonly static List<string> WhiteList = new List<string>()
        {
            #region Basics
            typeof(Boolean).FullName,
            typeof(Char).FullName,
            typeof(String).FullName,
            typeof(Byte).FullName,
            typeof(SByte).FullName,
            typeof(UInt16).FullName,
            typeof(Int16).FullName,
            typeof(UInt32).FullName,
            typeof(Int32).FullName,
            typeof(UInt64).FullName,
            typeof(Int64).FullName,
            typeof(Decimal).FullName,
            typeof(Double).FullName,
            typeof(Single).FullName,
            typeof(TimeSpan).FullName,
    
            typeof(Array).FullName,
            typeof(Enum).FullName,
            #endregion
    
            #region Exceptions
            typeof(Exception).FullName,
            typeof(NotImplementedException).FullName,
            typeof(IOException).FullName,
            #endregion
    
            #region Delegates
            typeof(Delegate).FullName,
            #endregion
    
            #region Parallel
            typeof(Parallel).FullName,
            #endregion
    
            #region Conversions
            typeof(Convert).FullName,
            typeof(BitConverter).FullName,
            #endregion
    
            #region Streams
            typeof(Stream).FullName,
            typeof(MemoryStream).FullName,
            typeof(BinaryReader).FullName,
            typeof(BinaryWriter).FullName,
            #endregion
    
            #region Interfaces
            typeof(IDisposable).FullName,
            typeof(IComparable).FullName,
            typeof(IConvertible).FullName,
            typeof(IFormatProvider).FullName,
            typeof(IFormattable).FullName,
            typeof(IOrderedQueryable).FullName,
            #endregion
    
            #region Attributes
            typeof(Attribute).FullName,
    
            // Compilation JIT
            typeof(CompilationRelaxationsAttribute).FullName,
            typeof(RuntimeCompatibilityAttribute).FullName,
            typeof(CompilerGeneratedAttribute).FullName,
            #endregion
    
            #region Generic Types
            typeof(IDictionary<object,object>).Namespace+"."+typeof(IDictionary<object,object>).Name,
            typeof(Dictionary<object,object>).Namespace+"."+typeof(Dictionary<object,object>).Name,
            typeof(List<object>).Namespace+"."+typeof(List<object>).Name,
            typeof(IList<object>).Namespace+"."+typeof(IList<object>).Name,
            typeof(IEnumerable<object>).Namespace+"."+typeof(IEnumerable<object>).Name,
            typeof(IEnumerator<object>).Namespace+"."+typeof(IEnumerator<object>).Name,
            typeof(IOrderedEnumerable<object>).Namespace+"."+typeof(IOrderedEnumerable<object>).Name,
            typeof(IOrderedQueryable<object>).Namespace+"."+typeof(IOrderedQueryable<object>).Name,
            typeof(ICollection<object>).Namespace+"."+typeof(ICollection<object>).Name,
            typeof(IComparable<object>).Namespace+"."+typeof(IComparable<object>).Name,
            typeof(IEquatable<object>).Namespace+"."+typeof(IEquatable<object>).Name,
            typeof(IObservable<object>).Namespace+"."+typeof(IObservable<object>).Name,
            #endregion
        };
    
        const string WhiteListedNamespace = "XX.XXXXXXXXXX.";
    
        /// <summary>
        /// Check white list
        /// </summary>
        /// <param name="binary">Binary</param>
        public static void CheckWhiteList(byte[] binary)
        {
            using (MemoryStream ms = new MemoryStream(binary))
            {
                AssemblyDefinition def = AssemblyDefinition.ReadAssembly(ms, new ReaderParameters(ReadingMode.Immediate));
    
                List<string> ls = new List<string>();
                foreach (ModuleDefinition mdef in def.Modules)
                    foreach (TypeReference tdef in mdef.GetTypeReferences())
                    {
                        if (!WhiteList.Contains(tdef.FullName) &&
                            !tdef.FullName.StartsWith(WhiteListedNamespace, StringComparison.InvariantCulture))
                            ls.Add(tdef.FullName);
                    }
    
                if (ls.Count > 0)
                    throw (new TypeNotAllowedException(ls.ToArray()));
            }
        }