예제 #1
0
        public static string GetFileDistinctPath(string folderPath, string fileName)
        {
            if (string.IsNullOrWhiteSpace(folderPath) || !Directory.Exists(folderPath))
            {
                return(null);
            }
            fileName = DumpFileMoniker.GetValidFileName(fileName);
            string path = folderPath;

            if (folderPath[folderPath.Length - 1] != System.IO.Path.DirectorySeparatorChar)
            {
                path = path + System.IO.Path.DirectorySeparatorChar;
            }
            path = path + fileName;
            var orgPath = string.Copy(path);
            var dotPos  = path.LastIndexOf('.');

            Debug.Assert(dotPos > 0); // we should use kind of standard file names
            int ndx = 1;

            while (File.Exists(path))
            {
                string num = "(" + ndx + ")";
                ++ndx;
                path = orgPath.Insert(dotPos, num);
            }
            return(path);
        }
예제 #2
0
        public static ClrtRootInfo Load(int rtm, DumpFileMoniker fileMoniker, out string error)
        {
            error = null;
            BinaryReader bw = null;

            try
            {
                var path = fileMoniker.GetFilePath(rtm, Constants.MapRootsInfoFilePostfix);
                bw = new BinaryReader(File.Open(path, FileMode.Open));

                // root details
                //
                int          count = bw.ReadInt32();
                ClrtRoot[][] roots = new ClrtRoot[count][];
                for (int i = 0; i < count; ++i)
                {
                    int kindCount = bw.ReadInt32();
                    roots[i] = new ClrtRoot[kindCount];
                    for (int j = 0; j < kindCount; ++j)
                    {
                        roots[i][j] = ClrtRoot.Load(bw);
                    }
                }
                return(new ClrtRootInfo(roots));
            }
            catch (Exception ex)
            {
                error = Utils.GetExceptionErrorString(ex);
                return(null);
            }
            finally
            {
                bw?.Close();
            }
        }
예제 #3
0
        public static bool Save(int rtm, List <ClrtRoot>[] ourRoots, DumpFileMoniker fileMoniker, out string error)
        {
            error = null;
            BinaryWriter bw = null;

            try
            {
                var path = fileMoniker.GetFilePath(rtm, Constants.MapRootsInfoFilePostfix);
                bw = new BinaryWriter(File.Open(path, FileMode.Create));

                // root details by kind
                //
                bw.Write(ourRoots.Length);
                for (int i = 0, icnt = ourRoots.Length; i < icnt; ++i)
                {
                    var kindRoots = ourRoots[i];
                    bw.Write(kindRoots.Count);
                    for (int j = 0, jcnt = kindRoots.Count; j < jcnt; ++j)
                    {
                        kindRoots[j].Dump(bw);
                    }
                }
                return(true);
            }
            catch (Exception ex)
            {
                error = Utils.GetExceptionErrorString(ex);
                return(false);
            }
            finally
            {
                bw?.Close();
            }
        }
예제 #4
0
        public static bool InstanceReferenceFilesAvailable(int runtmNdx, DumpFileMoniker moniker, out string error)
        {
            error = null;
            try
            {
                string[] fileList = new string[(int)RefFile.Count];
                fileList[0] = moniker.GetFilePath(runtmNdx, Constants.MapRefFwdOffsetsFilePostfix);
                fileList[1] = moniker.GetFilePath(runtmNdx, Constants.MapFwdRefsFilePostfix);
                fileList[2] = moniker.GetFilePath(runtmNdx, Constants.MapRefBwdOffsetsFilePostfix);
                fileList[3] = moniker.GetFilePath(runtmNdx, Constants.MapBwdRefsFilePostfix);

                for (int i = 0, icnt = fileList.Length; i < icnt; ++i)
                {
                    if (!File.Exists(fileList[i]))
                    {
                        return(false);
                    }
                }

                return(true);
            }
            catch (Exception ex)
            {
                error = Utils.GetExceptionErrorString(ex);
                return(false);
            }
        }
예제 #5
0
 public IndexProxy(ClrtDump dump, ulong[] instances, int[] instanceTypes, string[] typeNames, ClrElementKind[] typeKinds, ClrtRootInfo roots, DumpFileMoniker fileMoniker)
 {
     Dump          = dump;
     Instances     = instances;
     InstanceTypes = instanceTypes;
     TypeNames     = typeNames;
     TypeKinds     = typeKinds;
     Roots         = roots;
     FileMoniker   = fileMoniker;
 }
예제 #6
0
 public InstanceReferences(ulong[] instances, int runtmNdx, DumpFileMoniker moniker)
 {
     _instances   = instances;
     _fileList    = new string[(int)RefFile.Count];
     _fileList[0] = moniker.GetFilePath(runtmNdx, Constants.MapRefFwdOffsetsFilePostfix);
     _fileList[1] = moniker.GetFilePath(runtmNdx, Constants.MapFwdRefsFilePostfix);
     _fileList[2] = moniker.GetFilePath(runtmNdx, Constants.MapRefBwdOffsetsFilePostfix);
     _fileList[3] = moniker.GetFilePath(runtmNdx, Constants.MapBwdRefsFilePostfix);
     _maps        = new MemoryMappedFile[(int)RefFile.Count];
     _views       = new MemoryMappedViewAccessor[(int)RefFile.Count];
     _readers     = new BinaryReader[(int)RefFile.Count];
     _readers     = new BinaryReader[(int)RefFile.Count];
 }
예제 #7
0
        /// <summary>
        ///
        /// </summary>
        /// <param name="rtmNdx"></param>
        /// <param name="segments"></param>
        /// <param name="instances"></param>
        /// <param name="sizes"></param>
        /// <param name="fileMoniker"></param>
        /// <param name="hasUnrootedInfo"></param>
        /// <returns></returns>
        public static Tuple <int[], ulong[], int[], ulong[], int[], ulong[]> GetTotalGenerationDistributions(int rtmNdx, ClrtSegment[] segments, ulong[] instances, uint[] sizes, DumpFileMoniker fileMoniker, bool hasUnrootedInfo)
        {
            var genTotalCount         = new int[4];
            var genTotalSize          = new ulong[4];
            var genTotalUnrootedCount = new int[4];
            var genTotalUnrootedSize  = new ulong[4];
            var freeTotalGenCount     = new int[4];
            var freeTotalGenSize      = new ulong[4];

            // check unrooted
//			if (!hasUnrootedInfo)
            {
                for (int i = 0, icnt = instances.Length; i < icnt; ++i)
                {
                    if (!Utils.IsRooted(instances[i]))
                    {
                        var addr = instances[i];
                        var seg  = ClrtSegment.FindSegment(segments, addr);
                        if (seg == null)
                        {
                            continue;
                        }
                        var gen = seg.GetGeneration(addr);
                        if (gen == Generation.Uknown)
                        {
                            continue;
                        }
                        seg.IncUnrooted(gen, sizes[i]);
                    }
                }
                string error;
                ClrtSegment.DumpSegments(fileMoniker.GetFilePath(rtmNdx, Constants.MapSegmentInfoFilePostfix), segments,
                                         out error, true);
            }

            for (int i = 0, icnt = segments.Length; i < icnt; ++i)
            {
                var seg = segments[i];
                if (seg.Large)
                {
                    genTotalCount[(int)Generation.Large]         += seg.Gen0Count;
                    genTotalSize[(int)Generation.Large]          += seg.Gen0Size;
                    freeTotalGenCount[(int)Generation.Large]     += seg.Gen0FreeCount;
                    freeTotalGenSize[(int)Generation.Large]      += seg.Gen0FreeSize;
                    genTotalUnrootedCount[(int)Generation.Large] += seg.Gen0UnrootedCount;
                    genTotalSize[(int)Generation.Large]          += seg.Gen0UnrootedSize;
                    continue;
                }
                genTotalCount[(int)Generation.Gen0]         += seg.Gen0Count;
                genTotalSize[(int)Generation.Gen0]          += seg.Gen0Size;
                genTotalUnrootedCount[(int)Generation.Gen0] += seg.Gen0UnrootedCount;
                genTotalUnrootedSize[(int)Generation.Gen0]  += seg.Gen0UnrootedSize;
                freeTotalGenCount[(int)Generation.Gen0]     += seg.Gen0FreeCount;
                freeTotalGenSize[(int)Generation.Gen0]      += seg.Gen0FreeSize;

                genTotalCount[(int)Generation.Gen1]         += seg.Gen1Count;
                genTotalSize[(int)Generation.Gen1]          += seg.Gen1Size;
                genTotalUnrootedCount[(int)Generation.Gen1] += seg.Gen1UnrootedCount;
                genTotalUnrootedSize[(int)Generation.Gen1]  += seg.Gen1UnrootedSize;
                freeTotalGenCount[(int)Generation.Gen1]     += seg.Gen1FreeCount;
                freeTotalGenSize[(int)Generation.Gen1]      += seg.Gen1FreeSize;

                genTotalCount[(int)Generation.Gen2]         += seg.Gen2Count;
                genTotalSize[(int)Generation.Gen2]          += seg.Gen2Size;
                genTotalUnrootedCount[(int)Generation.Gen2] += seg.Gen2UnrootedCount;
                genTotalUnrootedSize[(int)Generation.Gen2]  += seg.Gen2UnrootedSize;
                freeTotalGenCount[(int)Generation.Gen2]     += seg.Gen2FreeCount;
                freeTotalGenSize[(int)Generation.Gen2]      += seg.Gen2FreeSize;
            }

            return(Tuple.Create(genTotalCount, genTotalSize, freeTotalGenCount, freeTotalGenSize, genTotalUnrootedCount, genTotalUnrootedSize));
        }
예제 #8
0
        public static bool FinalyzerAddressFixup(int rtm, ulong[] finalyzerAddresses, DumpFileMoniker fileMoniker, out string error)
        {
            error = null;
            FileWriter fw = null;

            try
            {
                var path = fileMoniker.GetFilePath(rtm, Constants.MapRootsInfoFilePostfix);
                fw = new FileWriter(path, FileMode.Open, FileAccess.Write, FileShare.None);
                fw.Seek(sizeof(int), SeekOrigin.Begin);

                for (int i = 0, icnt = finalyzerAddresses.Length; i < icnt; ++i)
                {
                    fw.Write(finalyzerAddresses[i]);
                }
                return(true);
            }
            catch (Exception ex)
            {
                error = Utils.GetExceptionErrorString(ex);
                return(false);
            }
            finally
            {
                fw?.Dispose();
            }
        }
예제 #9
0
        public static ValueTuple <ulong[], ulong[]> SetupRootAddresses(int rtm, ClrHeap heap, string[] typeNames, StringIdDct strIds, DumpFileMoniker fileMoniker, out string error)
        {
            error = null;
            try
            {
                var roots   = heap.EnumerateRoots(true);
                var objSet  = new HashSet <ulong>(new Utils.AddressEqualityComparer());
                var finlSet = new HashSet <ulong>(new Utils.AddressEqualityComparer());
                List <ClrtRoot>[] ourRoots = new List <ClrtRoot> [(int)GCRootKind.Max + 1];
                for (int i = 0, icnt = (int)GCRootKind.Max + 1; i < icnt; ++i)
                {
                    ourRoots[i] = new List <ClrtRoot>(256);
                }

                foreach (var root in roots)
                {
                    ulong  rootAddr = root.Address;
                    ulong  objAddr  = root.Object;
                    int    typeId;
                    string typeName;
                    if (root.Type == null)
                    {
                        var clrType = heap.GetObjectType(objAddr);
                        typeName = clrType == null ? Constants.UnknownName : clrType.Name;
                    }
                    else
                    {
                        typeName = root.Type.Name;
                    }

                    typeId = Array.BinarySearch(typeNames, typeName, StringComparer.Ordinal);
                    if (typeId < 0)
                    {
                        typeId = Constants.InvalidIndex;
                    }
                    string rootName = root.Name == null ? Constants.UnknownName : root.Name;

                    var nameId   = strIds.JustGetId(rootName);
                    var clrtRoot = new ClrtRoot(root, typeId, nameId);

                    ourRoots[(int)root.Kind].Add(clrtRoot);

                    if (objAddr != 0UL)
                    {
                        if (root.Kind == GCRootKind.Finalizer)
                        {
                            objAddr = Utils.SetAsFinalizer(objAddr);
                            finlSet.Add(objAddr);
                        }
                        else
                        {
                            objAddr = Utils.SetRooted(objAddr);
                            objSet.Add(objAddr);
                        }
                    }
                    if (rootAddr != 0UL)
                    {
                        if (root.Kind == GCRootKind.Finalizer)
                        {
                            rootAddr = Utils.SetAsFinalizer(rootAddr);
                            finlSet.Add(rootAddr);
                        }
                        else
                        {
                            rootAddr = Utils.SetRooted(rootAddr);
                            objSet.Add(rootAddr);
                        }
                    }
                }

                // root infos TODO JRD -- Fix this
                //
                var rootCmp = new ClrtRootObjCmp();
                for (int i = 0, icnt = (int)GCRootKind.Max + 1; i < icnt; ++i)
                {
                    ourRoots[i].Sort(rootCmp);
                }

                // unique addresses
                //
                var addrAry = objSet.ToArray();
                Array.Sort(addrAry, new Utils.AddressComparison());

                var finlAry = finlSet.ToArray();
                Array.Sort(finlAry, new Utils.AddressComparison());

                if (!ClrtRootInfo.Save(rtm, ourRoots, fileMoniker, out error))
                {
                    return(new ValueTuple <ulong[], ulong[]>(null, null));
                }
                return(new ValueTuple <ulong[], ulong[]>(addrAry, finlAry));
            }
            catch (Exception ex)
            {
                error = Utils.GetExceptionErrorString(ex);
                return(new ValueTuple <ulong[], ulong[]>(null, null));
            }
        }
예제 #10
0
        ///// <summary>
        ///// We are persisting string statistics (System.String) when they are asked for,
        ///// so second request might be served faster.
        ///// </summary>
        ///// <param name="runtimeIndex">Mostly we have just one runtime [0].</param>
        ///// <param name="dumpPath">Process dump file.</param>
        ///// <returns>True if we have files with string information.</returns>
        //public static bool StringStatsFilesExist(int runtimeIndex, string dumpPath)
        //{
        //	var strDatPath = DumpFileMoniker.GetRuntimeFilePath(runtimeIndex, dumpPath, Constants.MapDumpStringsInfoPostfix);
        //	if (!File.Exists(strDatPath)) return false;
        //	return true;
        //}


        public static StringStats GetStringsInfoFromFiles(int runtimeIndex, string dumpPath, out string error)
        {
            error = null;
            string[]     strings  = null;
            StringStats  strStats = null;
            BinaryReader br       = null;

            try
            {
                string dataPath = DumpFileMoniker.GetRuntimeFilePath(runtimeIndex, dumpPath, Constants.MapDumpStringsInfoPostfix);
                br = new BinaryReader(File.Open(dataPath, FileMode.Open));
                int  totalStringCount = br.ReadInt32();
                long totalStringSize  = br.ReadInt64();
                long totalUniqueSize  = br.ReadInt64();
                long strOffsetOffset  = br.ReadInt64();
                int  uniqueStrCount   = br.ReadInt32();

                uint[]    sizes      = new uint[uniqueStrCount];
                int[]     counts     = new int[uniqueStrCount];
                ulong[][] adddresses = new ulong[uniqueStrCount][];

                for (int i = 0; i < uniqueStrCount; ++i)
                {
                    int  strInstCount = br.ReadInt32();
                    uint strSize      = br.ReadUInt32();
                    counts[i]     = strInstCount;
                    sizes[i]      = strSize;
                    adddresses[i] = new ulong[strInstCount];
                    for (int j = 0; j < strInstCount; ++j)
                    {
                        adddresses[i][j] = br.ReadUInt64();
                    }
                }
                strings = new string[uniqueStrCount];
                long[] addroffs = new long[uniqueStrCount];
                for (int i = 0; i < uniqueStrCount; ++i)
                {
                    addroffs[i] = br.ReadInt64();
                    strings[i]  = br.ReadString();
                }
                br.Close();
                br = null;

                strStats = new StringStats()
                {
                    _strings         = strings,
                    _sizes           = sizes,
                    _counts          = counts,
                    _adddresses      = adddresses,
                    _totalSize       = totalStringSize,
                    _totalUniqueSize = totalUniqueSize,
                    _totalCount      = totalStringCount
                };
            }
            catch (Exception ex)
            {
                error = Utils.GetExceptionErrorString(ex);
                return(null);
            }
            finally
            {
                br?.Close();
            }

            return(strStats);
        }
예제 #11
0
        public static DisplayableFinalizerQueue GetDisplayableFinalizerQueue(ulong[] heapInstances, ClrtRoot[] data, ulong[] instances, string[] typeNames, DumpFileMoniker fileMoniker)
        {
            if (data == null || data.Length < 1)
            {
                return(new DisplayableFinalizerQueue());                                             // empty
            }
            int prevTypeId = data[0].TypeId;
            List <FinalizerQueueDisplayableItem> items = new List <FinalizerQueueDisplayableItem>(1024);
            List <KeyValuePair <int, int> >      lst   = new List <KeyValuePair <int, int> >(256);
            List <ulong> typeAddresses      = new List <ulong>(1024);
            int          totalCount         = 0;
            int          totalUnrootedCount = 0;
            int          typeCount          = 0;
            int          notRooted          = 0;

            for (int i = 0, icnt = data.Length; i < icnt; ++i)
            {
                if (prevTypeId != data[i].TypeId)
                {
                    string typeName = prevTypeId < 0 ? Constants.UnknownTypeName : typeNames[prevTypeId];
                    var    item     = new FinalizerQueueDisplayableItem(typeCount, notRooted, typeName, typeAddresses.ToArray());
                    items.Add(item);
                    typeCount = 0;
                    notRooted = 0;
                    lst.Clear();
                    typeAddresses.Clear();
                    prevTypeId = data[i].TypeId;
                }
                int   instNdx  = Utils.AddressSearch(instances, data[i].Object);
                ulong addr     = instNdx < 0 ? data[i].Object : instances[instNdx];
                int   heapIndx = Utils.AddressSearch(heapInstances, addr);
                if (heapIndx >= 0)
                {
                    addr = heapInstances[heapIndx];
                }
                typeAddresses.Add(addr);
                ++typeCount;
                ++totalCount;
                if (!Utils.IsRooted(addr))
                {
                    ++notRooted;
                    ++totalUnrootedCount;
                }
            }
            if (typeCount > 0)
            {
                string typeName = prevTypeId < 0 ? Constants.UnknownTypeName : typeNames[prevTypeId];
                var    item     = new FinalizerQueueDisplayableItem(typeCount, notRooted, typeName, typeAddresses.ToArray());
                items.Add(item);
            }
            var itemsAry = items.ToArray();

            Array.Sort(itemsAry, new FinalizerQueueDisplayableItemCmp(2, true));
            return(new DisplayableFinalizerQueue(items.ToArray(), totalCount, totalUnrootedCount, fileMoniker));
        }
예제 #12
0
 public DisplayableFinalizerQueue(FinalizerQueueDisplayableItem[] items, int totalCount, int totalUnrootedCount, DumpFileMoniker fileMoniker)
 {
     Items              = items;
     TotalCount         = totalCount;
     TotalUnrootedCount = totalUnrootedCount;
     Information        = "Crash dump: " + fileMoniker.DumpFileName
                          + Environment.NewLine + "Total count: " + Utils.CountString(totalCount)
                          + Environment.NewLine + "Total unrooted count: " + Utils.CountString(totalUnrootedCount);
 }
예제 #13
0
 public static string GetOutputPathWithDumpPrefix(DumpFileMoniker monkr, string fileName)
 {
     return(GetOuputFolder(monkr.Path) + System.IO.Path.DirectorySeparatorChar + monkr.FileName + "." + fileName);
 }
예제 #14
0
        public static bool GetConfigSettings(out string error)
        {
            error           = null;
            DacFolder       = string.Empty;
            DumpsFolder     = string.Empty;
            ProcDumpFolder  = string.Empty;
            RecentIndexList = new List <string>();
            RecentAdhocList = new List <string>();
            StringBuilder errors = StringBuilderCache.Acquire(256);

            try
            {
#if DEBUG
                //string myfolder = @"D:\Jerzy\WinDbgStuff\MDRDesk\";
                string myfolder = @"C:\WinDbgStuff\MDRDesk\";
#else
                string myfolder = DumpFileMoniker.MyFolder;
#endif
                string installFolder = DumpFileMoniker.GetParentFolder(myfolder);
                var    config        = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
                var    appSettings   = (AppSettingsSection)config.GetSection("appSettings");
                if (appSettings.Settings.Count != 0)
                {
                    foreach (string key in appSettings.Settings.AllKeys)
                    {
                        var ky = key.ToLower();
                        if (Utils.SameStrings(ky, "dacfolder"))
                        {
                            var folder = appSettings.Settings[key].Value.Trim();
                            if (Directory.Exists(folder))
                            {
                                DacFolder = folder;
                            }
                            string path = installFolder + @"mscordacwks";
                            if (Directory.Exists(path))
                            {
                                DacFolder = path;
                            }
                            else
                            {
                                errors.AppendLine("Dac folder does not exist: " + folder);
                            }
                        }
                        else if (Utils.SameStrings(ky, "mapfolder"))
                        {
                            var folder = appSettings.Settings[key].Value.Trim();
                            if (Directory.Exists(folder))
                            {
                                DumpsFolder = folder;
                            }
                            else
                            {
                                // if dumps folder exists, add it to config
                                string path = installFolder + @"dumps";
                                if (Directory.Exists(path))
                                {
                                    DumpsFolder = path;
                                }
                                else
                                {
                                    errors.AppendLine("Dumps folder does not exist: " + folder);
                                }
                            }
                        }
                        else if (Utils.SameStrings(ky, "procdumpfolder"))
                        {
                            var folder = appSettings.Settings[key].Value.Trim();
                            if (Directory.Exists(folder))
                            {
                                ProcDumpFolder = folder;
                            }
                            else
                            {
                                ProcDumpFolder = "";
                            }
//                            else errors.AppendLine("procdum.exe folder does not exist: " + folder);
                        }
                        else if (Utils.SameStrings(ky, "helpfolder"))
                        {
                            var folder = appSettings.Settings[key].Value.Trim();
                            if (Directory.Exists(folder))
                            {
                                HelpFolder = folder;
                            }
                            else
                            {
                                string path = myfolder + @"Documentation";
                                if (Directory.Exists(path))
                                {
                                    HelpFolder = myfolder;
                                }
                                else
                                {
                                    errors.AppendLine("Documentation folder does not exist: " + folder);
                                }
                            }
                        }
                        else if (Utils.SameStrings(ky, "refbuilder"))
                        {
                            var val = appSettings.Settings[key].Value.Trim();
                            CppRefBuilder = string.Compare(val, "c++", StringComparison.OrdinalIgnoreCase) == 0;
                        }
                        else if (Utils.SameStrings(ky, "refreader"))
                        {
                            var val = appSettings.Settings[key].Value.Trim();
                            MapRefReader = string.Compare(val, "map", StringComparison.OrdinalIgnoreCase) == 0;
                        }
                        else if (Utils.SameStrings(ky, "wnddbgfolder"))
                        {
                            var folder = appSettings.Settings[key].Value.Trim();
                            if (Directory.Exists(folder))
                            {
                                WndDbgFolder = folder;
                            }
                            //else errors.AppendLine("help folder does not exist: " + folder);
                        }
                        else if (Utils.SameStrings(ky, "graphproxy"))
                        {
                            GraphDbJar = appSettings.Settings[key].Value.Trim();
                        }
                        else if (Utils.SameStrings(ky, "graphport"))
                        {
                            GraphPort = Int32.Parse(appSettings.Settings[key].Value.Trim());
                        }
                        else if (Utils.SameStrings(ky, "recentindices"))
                        {
                            GetSemicolonDelimitedFolderPaths(RecentIndexList, appSettings.Settings[key].Value);
                        }
                        else if (Utils.SameStrings(ky, "recentadhocs"))
                        {
                            GetSemicolonDelimitedFilePaths(RecentAdhocList, appSettings.Settings[key].Value);
                        }
                        else if (Utils.SameStrings(ky, "typedisplaymode"))
                        {
                            TypesDisplayMode = appSettings.Settings[key].Value.Trim();
                        }
                    }
                }
                else
                {
                    error = "The appSettings section is empty.";
                }
                if (errors.Length > 0)
                {
                    return(false);
                }
                return(true);
            }
            catch (Exception ex)
            {
                error = Utils.GetExceptionErrorString(ex);
                return(false);
            }
            finally
            {
                if (errors.Length > 0)
                {
                    error = "Initialization Failed" + Constants.HeavyGreekCrossPadded
                            + "Setup.GetConfigSettings()" + Constants.HeavyGreekCrossPadded
                            + "MDRDesk application config file is invalid." + Environment.NewLine + "See details." +
                            Constants.HeavyGreekCrossPadded
                            + StringBuilderCache.GetStringAndRelease(errors);
                }
                else
                {
                    StringBuilderCache.Release(errors);
                }
            }
        }