summaryrefslogtreecommitdiff
path: root/src/mscorlib/Common/System/SR.cs
diff options
context:
space:
mode:
Diffstat (limited to 'src/mscorlib/Common/System/SR.cs')
-rw-r--r--src/mscorlib/Common/System/SR.cs197
1 files changed, 197 insertions, 0 deletions
diff --git a/src/mscorlib/Common/System/SR.cs b/src/mscorlib/Common/System/SR.cs
new file mode 100644
index 0000000000..29f3970633
--- /dev/null
+++ b/src/mscorlib/Common/System/SR.cs
@@ -0,0 +1,197 @@
+// Licensed to the .NET Foundation under one or more agreements.
+// The .NET Foundation licenses this file to you under the MIT license.
+// See the LICENSE file in the project root for more information.
+
+using System.Collections.Generic;
+using System.Diagnostics;
+using System.IO;
+using System.Resources;
+using System.Runtime.CompilerServices;
+using System.Threading;
+
+namespace System
+{
+ internal static partial class SR
+ {
+ private static ResourceManager ResourceManager
+ {
+ get;
+ set;
+ }
+
+ // This method is used to decide if we need to append the exception message parameters to the message when calling SR.Format.
+ // by default it returns false.
+ [MethodImpl(MethodImplOptions.NoInlining)]
+ private static bool UsingResourceKeys()
+ {
+ return false;
+ }
+
+ // Needed for debugger integration
+ internal static string GetResourceString(string resourceKey)
+ {
+ return GetResourceString(resourceKey, String.Empty);
+ }
+
+ internal static string GetResourceString(string resourceKey, string defaultString)
+ {
+ string resourceString = null;
+ try { resourceString = InternalGetResourceString(resourceKey); }
+ catch (MissingManifestResourceException) { }
+
+ if (defaultString != null && resourceKey.Equals(resourceString, StringComparison.Ordinal))
+ {
+ return defaultString;
+ }
+
+ return resourceString;
+ }
+
+ private static object _lock = new object();
+ private static List<string> _currentlyLoading;
+ private static int _infinitelyRecursingCount;
+ private static bool _resourceManagerInited = false;
+
+ private static string InternalGetResourceString(string key)
+ {
+ if (key == null || key.Length == 0)
+ {
+ Debug.Assert(false, "SR::GetResourceString with null or empty key. Bug in caller, or weird recursive loading problem?");
+ return key;
+ }
+
+ // We have a somewhat common potential for infinite
+ // loops with mscorlib's ResourceManager. If "potentially dangerous"
+ // code throws an exception, we will get into an infinite loop
+ // inside the ResourceManager and this "potentially dangerous" code.
+ // Potentially dangerous code includes the IO package, CultureInfo,
+ // parts of the loader, some parts of Reflection, Security (including
+ // custom user-written permissions that may parse an XML file at
+ // class load time), assembly load event handlers, etc. Essentially,
+ // this is not a bounded set of code, and we need to fix the problem.
+ // Fortunately, this is limited to mscorlib's error lookups and is NOT
+ // a general problem for all user code using the ResourceManager.
+
+ // The solution is to make sure only one thread at a time can call
+ // GetResourceString. Also, since resource lookups can be
+ // reentrant, if the same thread comes into GetResourceString
+ // twice looking for the exact same resource name before
+ // returning, we're going into an infinite loop and we should
+ // return a bogus string.
+
+ bool lockTaken = false;
+ try
+ {
+ Monitor.Enter(_lock, ref lockTaken);
+
+ // Are we recursively looking up the same resource? Note - our backout code will set
+ // the ResourceHelper's currentlyLoading stack to null if an exception occurs.
+ if (_currentlyLoading != null && _currentlyLoading.Count > 0 && _currentlyLoading.LastIndexOf(key) != -1)
+ {
+ // We can start infinitely recursing for one resource lookup,
+ // then during our failure reporting, start infinitely recursing again.
+ // avoid that.
+ if (_infinitelyRecursingCount > 0)
+ {
+ return key;
+ }
+ _infinitelyRecursingCount++;
+
+ // Note: our infrastructure for reporting this exception will again cause resource lookup.
+ // This is the most direct way of dealing with that problem.
+ string message = $"Infinite recursion during resource lookup within {System.CoreLib.Name}. This may be a bug in {System.CoreLib.Name}, or potentially in certain extensibility points such as assembly resolve events or CultureInfo names. Resource name: {key}";
+ Assert.Fail("[Recursive resource lookup bug]", message, Assert.COR_E_FAILFAST, System.Diagnostics.StackTrace.TraceFormat.NoResourceLookup);
+ Environment.FailFast(message);
+ }
+ if (_currentlyLoading == null)
+ _currentlyLoading = new List<string>();
+
+ // Call class constructors preemptively, so that we cannot get into an infinite
+ // loop constructing a TypeInitializationException. If this were omitted,
+ // we could get the Infinite recursion assert above by failing type initialization
+ // between the Push and Pop calls below.
+ if (!_resourceManagerInited)
+ {
+ RuntimeHelpers.RunClassConstructor(typeof(ResourceManager).TypeHandle);
+ RuntimeHelpers.RunClassConstructor(typeof(ResourceReader).TypeHandle);
+ RuntimeHelpers.RunClassConstructor(typeof(RuntimeResourceSet).TypeHandle);
+ RuntimeHelpers.RunClassConstructor(typeof(BinaryReader).TypeHandle);
+ _resourceManagerInited = true;
+ }
+
+ _currentlyLoading.Add(key); // Push
+
+ if (ResourceManager == null)
+ {
+ ResourceManager = new ResourceManager(SR.ResourceType);
+ }
+ string s = ResourceManager.GetString(key, null);
+ _currentlyLoading.RemoveAt(_currentlyLoading.Count - 1); // Pop
+
+ Debug.Assert(s != null, "Managed resource string lookup failed. Was your resource name misspelled? Did you rebuild mscorlib after adding a resource to resources.txt? Debug this w/ cordbg and bug whoever owns the code that called SR.GetResourceString. Resource name was: \"" + key + "\"");
+ return s ?? key;
+ }
+ catch
+ {
+ if (lockTaken)
+ {
+ // Backout code - throw away potentially corrupt state
+ ResourceManager = null;
+ _currentlyLoading = null;
+ }
+ throw;
+ }
+ finally
+ {
+ if (lockTaken)
+ {
+ Monitor.Exit(_lock);
+ }
+ }
+ }
+
+ internal static string Format(string resourceFormat, params object[] args)
+ {
+ if (args != null)
+ {
+ if (UsingResourceKeys())
+ {
+ return resourceFormat + String.Join(", ", args);
+ }
+
+ return String.Format(resourceFormat, args);
+ }
+
+ return resourceFormat;
+ }
+
+ internal static string Format(string resourceFormat, object p1)
+ {
+ if (UsingResourceKeys())
+ {
+ return String.Join(", ", resourceFormat, p1);
+ }
+
+ return String.Format(resourceFormat, p1);
+ }
+
+ internal static string Format(string resourceFormat, object p1, object p2)
+ {
+ if (UsingResourceKeys())
+ {
+ return String.Join(", ", resourceFormat, p1, p2);
+ }
+
+ return String.Format(resourceFormat, p1, p2);
+ }
+
+ internal static string Format(string resourceFormat, object p1, object p2, object p3)
+ {
+ if (UsingResourceKeys())
+ {
+ return String.Join(", ", resourceFormat, p1, p2, p3);
+ }
+ return String.Format(resourceFormat, p1, p2, p3);
+ }
+ }
+}