Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
5a76ad1
Merge in 'release/7.0' changes
dotnet-bot Mar 8, 2023
84e7e19
Merge in 'release/7.0' changes
dotnet-bot Mar 8, 2023
2c2402c
Merge in 'release/7.0' changes
dotnet-bot Mar 8, 2023
7e25da6
Merge in 'release/7.0' changes
dotnet-bot Mar 8, 2023
882512d
Merge in 'release/7.0' changes
dotnet-bot Mar 8, 2023
d46f5e5
Merge in 'release/7.0' changes
dotnet-bot Mar 8, 2023
a1a6ef3
Merge in 'release/7.0' changes
dotnet-bot Mar 8, 2023
089ea99
Merge in 'release/7.0' changes
dotnet-bot Mar 8, 2023
2f81831
Merge in 'release/7.0' changes
dotnet-bot Mar 9, 2023
21bd0a7
Merge in 'release/7.0' changes
dotnet-bot Mar 9, 2023
15f5d02
Merge in 'release/7.0' changes
dotnet-bot Mar 10, 2023
0f05efe
Merge in 'release/7.0' changes
dotnet-bot Mar 10, 2023
eaaed2a
Merge in 'release/7.0' changes
dotnet-bot Mar 10, 2023
5a1baeb
Merged PR 29231: [internal/release/7.0] Fix handling of load for msqu…
elinor-fung Mar 10, 2023
5359e8e
Merge in 'release/7.0' changes
dotnet-bot Mar 10, 2023
bfdc43b
Merge in 'release/7.0' changes
dotnet-bot Mar 11, 2023
71aa107
Merge in 'release/7.0' changes
dotnet-bot Mar 14, 2023
634640c
Merge in 'release/7.0' changes
dotnet-bot Mar 14, 2023
2c9e64f
Merge in 'release/7.0' changes
dotnet-bot Mar 15, 2023
90e3df4
Merge in 'release/7.0' changes
dotnet-bot Mar 17, 2023
fb541ff
Merge in 'release/7.0' changes
dotnet-bot Mar 20, 2023
8042d61
Merge in 'release/7.0' changes
dotnet-bot Mar 23, 2023
062f700
[release/7.0] Update dependencies from dotnet/runtime-assets (#84123)
dotnet-maestro[bot] Apr 7, 2023
a283bb9
Merge pull request #84594 from carlossanlop/release/7.0-staging
carlossanlop Apr 11, 2023
4e9cde7
Merge commit '8042d61b17540e49e53569e3728d2faa1c596583' into internal…
vseanreesermsft Apr 11, 2023
af23cd6
Merge pull request #84640 from vseanreesermsft/internal-merge-7.0-202…
carlossanlop Apr 11, 2023
d477fbf
Update dependencies from https://github.com/dotnet/arcade build 20230…
dotnet-maestro[bot] Apr 12, 2023
5266169
Update dependencies from https://github.com/dotnet/icu build 20230411…
dotnet-maestro[bot] Apr 12, 2023
43b5822
Update dependencies from https://github.com/dotnet/emsdk build 202304…
dotnet-maestro[bot] Apr 12, 2023
3de70ef
[release/7.0] Move mono.mscordbi subset off the offical buildMove mon…
steveisok Apr 17, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
using System.IO;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading;

namespace System.Resources
#if RESOURCES_EXTENSIONS
Expand Down Expand Up @@ -60,10 +61,11 @@ public sealed partial class
// it make sense to use anything less than one page?
private const int DefaultFileStreamBufferSize = 4096;

private BinaryReader _store; // backing store we're reading from.
// Used by RuntimeResourceSet and this class's enumerator. Maps
// resource name to a value, a ResourceLocator, or a
// LooselyLinkedManifestResource.
// Backing store we're reading from. Usages outside of constructor
// initialization must be protected by lock (this).
private BinaryReader _store;
// Used by RuntimeResourceSet and this class's enumerator.
// Accesses must be protected by lock(_resCache).
internal Dictionary<string, ResourceLocator>? _resCache;
private long _nameSectionOffset; // Offset to name section of file.
private long _dataSectionOffset; // Offset to Data section of file.
Expand All @@ -88,7 +90,6 @@ public sealed partial class
// Version number of .resources file, for compatibility
private int _version;


public
#if RESOURCES_EXTENSIONS
DeserializingResourceReader(string fileName)
Expand Down Expand Up @@ -169,13 +170,16 @@ private unsafe void Dispose(bool disposing)
}
}

internal static unsafe int ReadUnalignedI4(int* p)
private static unsafe int ReadUnalignedI4(int* p)
{
return BinaryPrimitives.ReadInt32LittleEndian(new ReadOnlySpan<byte>(p, sizeof(int)));
}

private void SkipString()
{
// Note: this method assumes that it is called either during object
// construction or within another method that locks on this.

int stringLength = _store.Read7BitEncodedInt();
if (stringLength < 0)
{
Expand Down Expand Up @@ -234,6 +238,7 @@ public IDictionaryEnumerator GetEnumerator()
return new ResourceEnumerator(this);
}

// Called from RuntimeResourceSet
internal ResourceEnumerator GetEnumeratorInternal()
{
return new ResourceEnumerator(this);
Expand All @@ -243,6 +248,7 @@ internal ResourceEnumerator GetEnumeratorInternal()
// To read the data, seek to _dataSectionOffset + dataPos, then
// read the resource type & data.
// This does a binary search through the names.
// Called from RuntimeResourceSet
internal int FindPosForResource(string name)
{
Debug.Assert(_store != null, "ResourceReader is closed!");
Expand Down Expand Up @@ -327,6 +333,8 @@ internal int FindPosForResource(string name)
private unsafe bool CompareStringEqualsName(string name)
{
Debug.Assert(_store != null, "ResourceReader is closed!");
Debug.Assert(Monitor.IsEntered(this)); // uses _store

int byteLen = _store.Read7BitEncodedInt();
if (byteLen < 0)
{
Expand Down Expand Up @@ -459,68 +467,74 @@ private unsafe string AllocateStringForNameIndex(int index, out int dataOffset)
}

// This takes a virtual offset into the data section and reads a String
// from that location.
// Anyone who calls LoadObject should make sure they take a lock so
// no one can cause us to do a seek in here.
// from that location. Called from RuntimeResourceSet
internal string? LoadString(int pos)
{
Debug.Assert(_store != null, "ResourceReader is closed!");
_store.BaseStream.Seek(_dataSectionOffset + pos, SeekOrigin.Begin);
string? s = null;
int typeIndex = _store.Read7BitEncodedInt();
if (_version == 1)
{
if (typeIndex == -1)
return null;
if (FindType(typeIndex) != typeof(string))
throw new InvalidOperationException(SR.Format(SR.InvalidOperation_ResourceNotString_Type, FindType(typeIndex).FullName));
s = _store.ReadString();
}
else

lock (this)
{
ResourceTypeCode typeCode = (ResourceTypeCode)typeIndex;
if (typeCode != ResourceTypeCode.String && typeCode != ResourceTypeCode.Null)
_store.BaseStream.Seek(_dataSectionOffset + pos, SeekOrigin.Begin);
string? s = null;
int typeIndex = _store.Read7BitEncodedInt();
if (_version == 1)
{
string? typeString;
if (typeCode < ResourceTypeCode.StartOfUserTypes)
typeString = typeCode.ToString();
else
typeString = FindType(typeCode - ResourceTypeCode.StartOfUserTypes).FullName;
throw new InvalidOperationException(SR.Format(SR.InvalidOperation_ResourceNotString_Type, typeString));
}
if (typeCode == ResourceTypeCode.String) // ignore Null
if (typeIndex == -1)
return null;
if (FindType(typeIndex) != typeof(string))
throw new InvalidOperationException(SR.Format(SR.InvalidOperation_ResourceNotString_Type, FindType(typeIndex).FullName));
s = _store.ReadString();
}
else
{
ResourceTypeCode typeCode = (ResourceTypeCode)typeIndex;
if (typeCode != ResourceTypeCode.String && typeCode != ResourceTypeCode.Null)
{
string? typeString;
if (typeCode < ResourceTypeCode.StartOfUserTypes)
typeString = typeCode.ToString();
else
typeString = FindType(typeCode - ResourceTypeCode.StartOfUserTypes).FullName;
throw new InvalidOperationException(SR.Format(SR.InvalidOperation_ResourceNotString_Type, typeString));
}
if (typeCode == ResourceTypeCode.String) // ignore Null
s = _store.ReadString();
}
return s;
}
return s;
}

// Called from RuntimeResourceSet
internal object? LoadObject(int pos)
{
if (_version == 1)
return LoadObjectV1(pos);
return LoadObjectV2(pos, out _);
lock (this)
{
return _version == 1 ? LoadObjectV1(pos) : LoadObjectV2(pos, out _);
}
}

// Called from RuntimeResourceSet
internal object? LoadObject(int pos, out ResourceTypeCode typeCode)
{
if (_version == 1)
lock (this)
{
object? o = LoadObjectV1(pos);
typeCode = (o is string) ? ResourceTypeCode.String : ResourceTypeCode.StartOfUserTypes;
return o;
if (_version == 1)
{
object? o = LoadObjectV1(pos);
typeCode = (o is string) ? ResourceTypeCode.String : ResourceTypeCode.StartOfUserTypes;
return o;
}
return LoadObjectV2(pos, out typeCode);
}
return LoadObjectV2(pos, out typeCode);
}

// This takes a virtual offset into the data section and reads an Object
// from that location.
// Anyone who calls LoadObject should make sure they take a lock so
// no one can cause us to do a seek in here.
internal object? LoadObjectV1(int pos)
private object? LoadObjectV1(int pos)
{
Debug.Assert(_store != null, "ResourceReader is closed!");
Debug.Assert(_version == 1, ".resources file was not a V1 .resources file!");
Debug.Assert(Monitor.IsEntered(this)); // uses _store

try
{
Expand All @@ -540,6 +554,8 @@ private unsafe string AllocateStringForNameIndex(int index, out int dataOffset)

private object? _LoadObjectV1(int pos)
{
Debug.Assert(Monitor.IsEntered(this)); // uses _store

_store.BaseStream.Seek(_dataSectionOffset + pos, SeekOrigin.Begin);
int typeIndex = _store.Read7BitEncodedInt();
if (typeIndex == -1)
Expand Down Expand Up @@ -596,10 +612,11 @@ private unsafe string AllocateStringForNameIndex(int index, out int dataOffset)
}
}

internal object? LoadObjectV2(int pos, out ResourceTypeCode typeCode)
private object? LoadObjectV2(int pos, out ResourceTypeCode typeCode)
{
Debug.Assert(_store != null, "ResourceReader is closed!");
Debug.Assert(_version >= 2, ".resources file was not a V2 (or higher) .resources file!");
Debug.Assert(Monitor.IsEntered(this)); // uses _store

try
{
Expand All @@ -619,6 +636,8 @@ private unsafe string AllocateStringForNameIndex(int index, out int dataOffset)

private object? _LoadObjectV2(int pos, out ResourceTypeCode typeCode)
{
Debug.Assert(Monitor.IsEntered(this)); // uses _store

_store.BaseStream.Seek(_dataSectionOffset + pos, SeekOrigin.Begin);
typeCode = (ResourceTypeCode)_store.Read7BitEncodedInt();

Expand Down Expand Up @@ -755,6 +774,7 @@ private unsafe string AllocateStringForNameIndex(int index, out int dataOffset)
[MemberNotNull(nameof(_typeNamePositions))]
private void ReadResources()
{
Debug.Assert(!Monitor.IsEntered(this)); // only called during init
Debug.Assert(_store != null, "ResourceReader is closed!");

try
Expand All @@ -777,6 +797,8 @@ private void ReadResources()
[MemberNotNull(nameof(_typeNamePositions))]
private void _ReadResources()
{
Debug.Assert(!Monitor.IsEntered(this)); // only called during init

// Read ResourceManager header
// Check for magic number
int magicNum = _store.ReadInt32();
Expand Down Expand Up @@ -962,6 +984,8 @@ private Type FindType(int typeIndex)
"Custom readers as well as custom objects on the resources file are not observable by the trimmer and so required assemblies, types and members may be removed.")]
private Type UseReflectionToGetType(int typeIndex)
{
Debug.Assert(Monitor.IsEntered(this)); // uses _store

long oldPos = _store.BaseStream.Position;
try
{
Expand Down Expand Up @@ -1000,6 +1024,8 @@ private Type UseReflectionToGetType(int typeIndex)
private string TypeNameFromTypeCode(ResourceTypeCode typeCode)
{
Debug.Assert(typeCode >= 0, "can't be negative");
Debug.Assert(Monitor.IsEntered(this)); // uses _store

if (typeCode < ResourceTypeCode.StartOfUserTypes)
{
Debug.Assert(!string.Equals(typeCode.ToString(), "LastPrimitive"), "Change ResourceTypeCode metadata order so LastPrimitive isn't what Enum.ToString prefers.");
Expand Down Expand Up @@ -1077,31 +1103,31 @@ public DictionaryEntry Entry
if (!_currentIsValid) throw new InvalidOperationException(SR.InvalidOperation_EnumNotStarted);
if (_reader._resCache == null) throw new InvalidOperationException(SR.ResourceReaderIsClosed);

string key;
string key = _reader.AllocateStringForNameIndex(_currentName, out _dataPosition); // AllocateStringForNameIndex could lock on _reader

object? value = null;
lock (_reader)
{ // locks should be taken in the same order as in RuntimeResourceSet.GetObject to avoid deadlock
lock (_reader._resCache)
// Lock the cache first, then the reader (in this case, we don't actually need to lock the reader and cache at the same time).
// Lock order MUST match RuntimeResourceSet.GetObject to avoid deadlock.
Debug.Assert(!Monitor.IsEntered(_reader));
lock (_reader._resCache)
{
if (_reader._resCache.TryGetValue(key, out ResourceLocator locator))
{
key = _reader.AllocateStringForNameIndex(_currentName, out _dataPosition); // AllocateStringForNameIndex could lock on _reader
if (_reader._resCache.TryGetValue(key, out ResourceLocator locator))
{
value = locator.Value;
}
if (value == null)
{
if (_dataPosition == -1)
value = _reader.GetValueForNameIndex(_currentName);
else
value = _reader.LoadObject(_dataPosition);
// If enumeration and subsequent lookups happen very
// frequently in the same process, add a ResourceLocator
// to _resCache here. But WinForms enumerates and
// just about everyone else does lookups. So caching
// here may bloat working set.
}
value = locator.Value;
}
}
if (value is null)
{
if (_dataPosition == -1)
value = _reader.GetValueForNameIndex(_currentName);
else
value = _reader.LoadObject(_dataPosition);
// If enumeration and subsequent lookups happen very
// frequently in the same process, add a ResourceLocator
// to _resCache here (we'll also need to extend the lock block!).
// But WinForms enumerates and just about everyone else does lookups.
// So caching here may bloat working set.
}
return new DictionaryEntry(key, value);
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Threading;

namespace System.Resources
#if RESOURCES_EXTENSIONS
Expand Down Expand Up @@ -283,6 +284,9 @@ private IDictionaryEnumerator GetEnumeratorHelper()
object? value;
ResourceLocator resEntry;

// Lock the cache first, then the reader (reader locks implicitly through its methods).
// Lock order MUST match ResourceReader.ResourceEnumerator.Entry to avoid deadlock.
Debug.Assert(!Monitor.IsEntered(reader));
lock (cache)
{
// Find the offset within the data section
Expand All @@ -295,7 +299,7 @@ private IDictionaryEnumerator GetEnumeratorHelper()

// When data type cannot be cached
dataPos = resEntry.DataPosition;
return isString ? reader.LoadString(dataPos) : reader.LoadObject(dataPos, out _);
return isString ? reader.LoadString(dataPos) : reader.LoadObject(dataPos);
}

dataPos = reader.FindPosForResource(key);
Expand Down Expand Up @@ -353,14 +357,11 @@ private IDictionaryEnumerator GetEnumeratorHelper()
return value;
}

private static object? ReadValue (ResourceReader reader, int dataPos, bool isString, out ResourceLocator locator)
private static object? ReadValue(ResourceReader reader, int dataPos, bool isString, out ResourceLocator locator)
{
object? value;
ResourceTypeCode typeCode;

// Normally calling LoadString or LoadObject requires
// taking a lock. Note that in this case, we took a
// lock before calling this method.
if (isString)
{
value = reader.LoadString(dataPos);
Expand Down
Loading