Skip to content
This repository was archived by the owner on Jan 23, 2023. It is now read-only.

Commit 20582c3

Browse files
committed
PR Feedback
Minimize string creation Remove unnecessary if null checks Eliminate corner cases by only allowing one case insensitive matching directory.
1 parent cdc06e2 commit 20582c3

File tree

2 files changed

+65
-40
lines changed

2 files changed

+65
-40
lines changed

src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.Unix.cs

Lines changed: 64 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -11,59 +11,90 @@ namespace System.Runtime.Loader
1111
{
1212
public partial class AssemblyLoadContext
1313
{
14+
internal struct OrdinalIgnoreCaseCultureComparer
15+
{
16+
public readonly string _cultureNameUpper;
17+
public OrdinalIgnoreCaseCultureComparer(string cultureName)
18+
{
19+
_cultureNameUpper = cultureName.ToUpperInvariant();
20+
}
21+
22+
public bool Equals(ref ReadOnlySpan<char> entryName)
23+
{
24+
if (_cultureNameUpper.Length != entryName.Length)
25+
return false;
26+
27+
for (int i = 0; i < _cultureNameUpper.Length; ++i)
28+
{
29+
if (_cultureNameUpper[i] != char.ToUpperInvariant(entryName[i]))
30+
return false;
31+
}
32+
return true;
33+
}
34+
}
35+
1436
// Find satellite path using case insensitive culture name
15-
internal static unsafe string? FindCaseInsensitiveSatellitePath(string parentDirectory, string cultureName, string assembly)
37+
internal static unsafe string? FindCaseInsensitiveCultureName(string parentDirectory, string cultureName, string assembly)
1638
{
1739
int bufferSize = Interop.Sys.GetReadDirRBufferSize();
18-
byte[]? dirBuffer = null;
40+
41+
byte[] dirBuffer = ArrayPool<byte>.Shared.Rent(bufferSize);
42+
IntPtr dirHandle = Interop.Sys.OpenDir(parentDirectory);
43+
44+
string? result = null;
45+
1946
try
2047
{
21-
dirBuffer = ArrayPool<byte>.Shared.Rent(bufferSize);
22-
23-
fixed (byte* dirBufferPtr = dirBuffer)
48+
if (dirHandle != IntPtr.Zero)
2449
{
25-
IntPtr dirHandle = Interop.Sys.OpenDir(parentDirectory);
26-
if (dirHandle != IntPtr.Zero)
50+
try
2751
{
28-
try
52+
fixed (byte* dirBufferPtr = dirBuffer)
2953
{
54+
Span<char> nameBuffer = stackalloc char[Interop.Sys.DirectoryEntry.NameBufferSize];
55+
OrdinalIgnoreCaseCultureComparer cultureNameComparer = new OrdinalIgnoreCaseCultureComparer(cultureName);
56+
3057
Interop.Sys.DirectoryEntry dirent;
3158
while (Interop.Sys.ReadDirR(dirHandle, dirBufferPtr, bufferSize, out dirent) == 0)
3259
{
3360
if (dirent.InodeType != Interop.Sys.NodeType.DT_DIR)
3461
continue;
3562

36-
Span<char> nameBuffer = stackalloc char[Interop.Sys.DirectoryEntry.NameBufferSize];
3763
ReadOnlySpan<char> entryName = dirent.GetName(nameBuffer);
3864

39-
if (cultureName.Length != entryName.Length)
65+
if (!cultureNameComparer.Equals(ref entryName))
4066
continue;
4167

42-
string entryNameString = entryName.ToString();
43-
44-
if (!cultureName.Equals(entryNameString, StringComparison.InvariantCultureIgnoreCase))
45-
continue;
46-
47-
string assemblyPath = $"{parentDirectory}/{entryNameString}/{assembly}.dll";
48-
49-
if (Internal.IO.File.InternalExists(assemblyPath))
50-
return assemblyPath;
68+
if (result == null)
69+
{
70+
// Convert to string because we will overwrite the backing buffer next loop
71+
result = entryName.ToString();
72+
// We do not return here because we do not want to debug/allow cases where
73+
// there are multiple directories which match case insensitive cultureName
74+
//
75+
// Do an exhaustive search
76+
}
77+
else
78+
{
79+
// We found more than one directory with the same case insensitive name
80+
// return null to make this case predicatably fail.
81+
return null;
82+
}
5183
}
5284
}
53-
finally
54-
{
55-
if (dirHandle != IntPtr.Zero)
56-
Interop.Sys.CloseDir(dirHandle);
57-
}
85+
}
86+
finally
87+
{
88+
Interop.Sys.CloseDir(dirHandle);
5889
}
5990
}
6091
}
6192
finally
6293
{
63-
if (dirBuffer != null)
64-
ArrayPool<byte>.Shared.Return(dirBuffer);
94+
ArrayPool<byte>.Shared.Return(dirBuffer);
6595
}
66-
return null;
96+
97+
return result;
6798
}
6899

69100
private Assembly? ResolveSatelliteAssembly(AssemblyName assemblyName)
@@ -93,20 +124,17 @@ public partial class AssemblyLoadContext
93124
string assemblyPath = $"{parentDirectory}/{cultureName}/{assemblyName.Name}.dll";
94125
if (Internal.IO.File.InternalExists(assemblyPath))
95126
{
96-
Assembly satelliteAssembly = parentAlc.LoadFromAssemblyPath(assemblyPath);
97-
98-
if (satelliteAssembly != null)
99-
return satelliteAssembly;
127+
return parentAlc.LoadFromAssemblyPath(assemblyPath);
100128
}
101129
else if (Path.IsCaseSensitive)
102130
{
103-
string? caseInsensitiveAssemblyPath = FindCaseInsensitiveSatellitePath(parentDirectory, cultureName, assemblyName.Name);
131+
string? caseInsensitiveCultureName = FindCaseInsensitiveCultureName(parentDirectory, cultureName, assemblyName.Name);
104132

105-
if (caseInsensitiveAssemblyPath != null)
133+
if (caseInsensitiveCultureName != null)
106134
{
107-
Assembly satelliteAssembly = parentAlc.LoadFromAssemblyPath(caseInsensitiveAssemblyPath);
108-
109-
return satelliteAssembly;
135+
assemblyPath = $"{parentDirectory}/{caseInsensitiveCultureName}/{assemblyName.Name}.dll";
136+
if (Internal.IO.File.InternalExists(assemblyPath))
137+
return parentAlc.LoadFromAssemblyPath(assemblyPath);
110138
}
111139
}
112140
return null;

src/System.Private.CoreLib/shared/System/Runtime/Loader/AssemblyLoadContext.Windows.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -37,10 +37,7 @@ public partial class AssemblyLoadContext
3737
string assemblyPath = Path.Combine(parentDirectory, dir, $"{assemblyName.Name}.dll");
3838
if (Internal.IO.File.InternalExists(assemblyPath))
3939
{
40-
Assembly satelliteAssembly = parentAlc.LoadFromAssemblyPath(assemblyPath);
41-
42-
if (satelliteAssembly != null)
43-
return satelliteAssembly;
40+
return parentAlc.LoadFromAssemblyPath(assemblyPath);
4441
}
4542

4643
return null;

0 commit comments

Comments
 (0)