Skip to content

Commit 14b34eb

Browse files
authored
don't fail LongModuleFileNamesAreSupported test if we can't load assembly on x86 (#57471)
1 parent ead035b commit 14b34eb

File tree

5 files changed

+172
-155
lines changed

5 files changed

+172
-155
lines changed
Lines changed: 3 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,16 +1,10 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using Microsoft.Win32.SafeHandles;
5-
using System.ComponentModel;
64
using System.Runtime.InteropServices;
7-
using System.Security.Principal;
85

9-
namespace System.Diagnostics.Tests
6+
internal static partial class Interop
107
{
11-
internal static partial class Interop
12-
{
13-
[DllImport("libc")]
14-
internal static extern int getsid(int pid);
15-
}
8+
[DllImport("libc")]
9+
internal static extern int getsid(int pid);
1610
}
Lines changed: 105 additions & 107 deletions
Original file line numberDiff line numberDiff line change
@@ -1,145 +1,143 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4+
using System;
45
using Microsoft.Win32.SafeHandles;
56
using System.ComponentModel;
67
using System.Runtime.InteropServices;
78
using System.Security.Principal;
89

9-
namespace System.Diagnostics.Tests
10+
internal static partial class Interop
1011
{
11-
internal static partial class Interop
12+
[StructLayout(LayoutKind.Sequential, Size = 40)]
13+
public struct PROCESS_MEMORY_COUNTERS
1214
{
13-
[StructLayout(LayoutKind.Sequential, Size = 40)]
14-
public struct PROCESS_MEMORY_COUNTERS
15-
{
16-
public uint cb;
17-
public uint PageFaultCount;
18-
public uint PeakWorkingSetSize;
19-
public uint WorkingSetSize;
20-
public uint QuotaPeakPagedPoolUsage;
21-
public uint QuotaPagedPoolUsage;
22-
public uint QuotaPeakNonPagedPoolUsage;
23-
public uint QuotaNonPagedPoolUsage;
24-
public uint PagefileUsage;
25-
public uint PeakPagefileUsage;
26-
}
15+
public uint cb;
16+
public uint PageFaultCount;
17+
public uint PeakWorkingSetSize;
18+
public uint WorkingSetSize;
19+
public uint QuotaPeakPagedPoolUsage;
20+
public uint QuotaPagedPoolUsage;
21+
public uint QuotaPeakNonPagedPoolUsage;
22+
public uint QuotaNonPagedPoolUsage;
23+
public uint PagefileUsage;
24+
public uint PeakPagefileUsage;
25+
}
2726

28-
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
29-
internal struct USER_INFO_1
30-
{
31-
public string usri1_name;
32-
public string usri1_password;
33-
public uint usri1_password_age;
34-
public uint usri1_priv;
35-
public string usri1_home_dir;
36-
public string usri1_comment;
37-
public uint usri1_flags;
38-
public string usri1_script_path;
39-
}
27+
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
28+
internal struct USER_INFO_1
29+
{
30+
public string usri1_name;
31+
public string usri1_password;
32+
public uint usri1_password_age;
33+
public uint usri1_priv;
34+
public string usri1_home_dir;
35+
public string usri1_comment;
36+
public uint usri1_flags;
37+
public string usri1_script_path;
38+
}
4039

41-
[StructLayout(LayoutKind.Sequential)]
42-
public struct TOKEN_USER
43-
{
44-
public SID_AND_ATTRIBUTES User;
45-
}
40+
[StructLayout(LayoutKind.Sequential)]
41+
public struct TOKEN_USER
42+
{
43+
public SID_AND_ATTRIBUTES User;
44+
}
4645

47-
[StructLayout(LayoutKind.Sequential)]
48-
public struct SID_AND_ATTRIBUTES
49-
{
50-
public IntPtr Sid;
51-
public int Attributes;
52-
}
46+
[StructLayout(LayoutKind.Sequential)]
47+
public struct SID_AND_ATTRIBUTES
48+
{
49+
public IntPtr Sid;
50+
public int Attributes;
51+
}
5352

54-
[DllImport("kernel32.dll")]
55-
public static extern bool GetProcessWorkingSetSizeEx(SafeProcessHandle hProcess, out IntPtr lpMinimumWorkingSetSize, out IntPtr lpMaximumWorkingSetSize, out uint flags);
53+
[DllImport("kernel32.dll")]
54+
public static extern bool GetProcessWorkingSetSizeEx(SafeProcessHandle hProcess, out IntPtr lpMinimumWorkingSetSize, out IntPtr lpMaximumWorkingSetSize, out uint flags);
5655

57-
[DllImport("kernel32.dll")]
58-
internal static extern bool ProcessIdToSessionId(uint dwProcessId, out uint pSessionId);
56+
[DllImport("kernel32.dll")]
57+
internal static extern bool ProcessIdToSessionId(uint dwProcessId, out uint pSessionId);
5958

60-
[DllImport("kernel32.dll")]
61-
public static extern int GetProcessId(SafeProcessHandle nativeHandle);
59+
[DllImport("kernel32.dll")]
60+
public static extern int GetProcessId(SafeProcessHandle nativeHandle);
6261

63-
[DllImport("kernel32.dll")]
64-
internal static extern int GetConsoleCP();
62+
[DllImport("kernel32.dll")]
63+
internal static extern int GetConsoleCP();
6564

66-
[DllImport("kernel32.dll")]
67-
internal static extern int GetConsoleOutputCP();
65+
[DllImport("kernel32.dll")]
66+
internal static extern int GetConsoleOutputCP();
6867

69-
[DllImport("kernel32.dll")]
70-
internal static extern int SetConsoleCP(int codePage);
68+
[DllImport("kernel32.dll")]
69+
internal static extern int SetConsoleCP(int codePage);
7170

72-
[DllImport("kernel32.dll")]
73-
internal static extern int SetConsoleOutputCP(int codePage);
71+
[DllImport("kernel32.dll")]
72+
internal static extern int SetConsoleOutputCP(int codePage);
7473

75-
[DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
76-
internal static extern uint NetUserAdd(string servername, uint level, ref USER_INFO_1 buf, out uint parm_err);
74+
[DllImport("netapi32.dll", CharSet = CharSet.Unicode, SetLastError = true)]
75+
internal static extern uint NetUserAdd(string servername, uint level, ref USER_INFO_1 buf, out uint parm_err);
7776

78-
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
79-
internal static extern uint NetUserDel(string servername, string username);
77+
[DllImport("netapi32.dll", CharSet = CharSet.Unicode)]
78+
internal static extern uint NetUserDel(string servername, string username);
8079

81-
[DllImport("advapi32.dll")]
82-
internal static extern bool OpenProcessToken(SafeProcessHandle ProcessHandle, uint DesiredAccess, out SafeProcessHandle TokenHandle);
80+
[DllImport("advapi32.dll")]
81+
internal static extern bool OpenProcessToken(SafeProcessHandle ProcessHandle, uint DesiredAccess, out SafeProcessHandle TokenHandle);
8382

84-
[DllImport("advapi32.dll")]
85-
internal static extern bool GetTokenInformation(SafeProcessHandle TokenHandle, uint TokenInformationClass, IntPtr TokenInformation, int TokenInformationLength, ref int ReturnLength);
83+
[DllImport("advapi32.dll")]
84+
internal static extern bool GetTokenInformation(SafeProcessHandle TokenHandle, uint TokenInformationClass, IntPtr TokenInformation, int TokenInformationLength, ref int ReturnLength);
8685

87-
[DllImport("shell32.dll")]
88-
internal static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
86+
[DllImport("shell32.dll")]
87+
internal static extern int SHChangeNotify(int eventId, int flags, IntPtr item1, IntPtr item2);
8988

90-
internal static void NetUserAdd(string username, string password)
91-
{
92-
USER_INFO_1 userInfo = new USER_INFO_1();
93-
userInfo.usri1_name = username;
94-
userInfo.usri1_password = password;
95-
userInfo.usri1_priv = 1;
89+
internal static void NetUserAdd(string username, string password)
90+
{
91+
USER_INFO_1 userInfo = new USER_INFO_1();
92+
userInfo.usri1_name = username;
93+
userInfo.usri1_password = password;
94+
userInfo.usri1_priv = 1;
9695

97-
uint parm_err;
98-
uint result = NetUserAdd(null, 1, ref userInfo, out parm_err);
96+
uint parm_err;
97+
uint result = NetUserAdd(null, 1, ref userInfo, out parm_err);
9998

100-
if (result != ExitCodes.NERR_Success)
101-
{
102-
// most likely result == ERROR_ACCESS_DENIED
103-
// due to running without elevated privileges
104-
throw new Win32Exception((int)result);
105-
}
99+
if (result != ExitCodes.NERR_Success)
100+
{
101+
// most likely result == ERROR_ACCESS_DENIED
102+
// due to running without elevated privileges
103+
throw new Win32Exception((int)result);
106104
}
105+
}
107106

108-
internal static bool ProcessTokenToSid(SafeProcessHandle token, out SecurityIdentifier sid)
107+
internal static bool ProcessTokenToSid(SafeProcessHandle token, out SecurityIdentifier sid)
108+
{
109+
bool ret = false;
110+
sid = null;
111+
IntPtr tu = IntPtr.Zero;
112+
try
109113
{
110-
bool ret = false;
111-
sid = null;
112-
IntPtr tu = IntPtr.Zero;
113-
try
114-
{
115-
TOKEN_USER tokUser;
116-
const int bufLength = 256;
117-
118-
tu = Marshal.AllocHGlobal(bufLength);
119-
int cb = bufLength;
120-
ret = GetTokenInformation(token, 1, tu, cb, ref cb);
121-
if (ret)
122-
{
123-
tokUser = Marshal.PtrToStructure<TOKEN_USER>(tu);
124-
sid = new SecurityIdentifier(tokUser.User.Sid);
125-
}
126-
return ret;
127-
}
128-
catch (Exception)
129-
{
130-
return false;
131-
}
132-
finally
114+
TOKEN_USER tokUser;
115+
const int bufLength = 256;
116+
117+
tu = Marshal.AllocHGlobal(bufLength);
118+
int cb = bufLength;
119+
ret = GetTokenInformation(token, 1, tu, cb, ref cb);
120+
if (ret)
133121
{
134-
if (tu != IntPtr.Zero)
135-
Marshal.FreeHGlobal(tu);
122+
tokUser = Marshal.PtrToStructure<TOKEN_USER>(tu);
123+
sid = new SecurityIdentifier(tokUser.User.Sid);
136124
}
125+
return ret;
137126
}
138-
139-
internal static class ExitCodes
127+
catch (Exception)
128+
{
129+
return false;
130+
}
131+
finally
140132
{
141-
internal const uint NERR_Success = 0;
142-
internal const uint NERR_UserNotFound = 2221;
133+
if (tu != IntPtr.Zero)
134+
Marshal.FreeHGlobal(tu);
143135
}
144136
}
137+
138+
internal static class ExitCodes
139+
{
140+
internal const uint NERR_Success = 0;
141+
internal const uint NERR_UserNotFound = 2221;
142+
}
145143
}
Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
// Licensed to the .NET Foundation under one or more agreements.
2+
// The .NET Foundation licenses this file to you under the MIT license.
3+
4+
using System.IO;
5+
using System.Linq;
6+
using System.Runtime.InteropServices;
7+
using Xunit;
8+
9+
namespace System.Diagnostics.Tests
10+
{
11+
public partial class ProcessModuleTests : ProcessTestBase
12+
{
13+
[ConditionalFact(typeof(PathFeatures), nameof(PathFeatures.AreAllLongPathsAvailable))]
14+
public void LongModuleFileNamesAreSupported()
15+
{
16+
// To be able to test Long Path support for ProcessModule.FileName we need a .dll that has a path > 260 chars.
17+
// Since Long Paths support can be disabled (see the ConditionalFact attribute usage above),
18+
// we just copy "LongName.dll" from bin to a temp directory with a long name and load it from there.
19+
// Loading from new path is possible because the type exposed by the assembly is not referenced in any explicit way.
20+
const string libraryName = "LongPath.dll";
21+
const int minPathLength = 261;
22+
23+
string testBinPath = Path.GetDirectoryName(typeof(ProcessModuleTests).Assembly.Location);
24+
string libraryToCopy = Path.Combine(testBinPath, libraryName);
25+
Assert.True(File.Exists(libraryToCopy), $"{libraryName} was not present in bin folder '{testBinPath}'");
26+
27+
string directoryWithLongName = Path.Combine(TestDirectory, new string('a', Math.Max(1, minPathLength - TestDirectory.Length)));
28+
Directory.CreateDirectory(directoryWithLongName);
29+
30+
string longNamePath = Path.Combine(directoryWithLongName, libraryName);
31+
Assert.True(longNamePath.Length > minPathLength);
32+
33+
File.Copy(libraryToCopy, longNamePath);
34+
Assert.True(File.Exists(longNamePath));
35+
36+
IntPtr moduleHandle = Interop.Kernel32.LoadLibrary(longNamePath);
37+
if (moduleHandle == IntPtr.Zero)
38+
{
39+
Assert.Equal(126, Marshal.GetLastWin32Error()); // ERROR_MOD_NOT_FOUND
40+
Assert.Equal(Architecture.X86, RuntimeInformation.ProcessArchitecture);
41+
return; // we have failed to load the module on x86, we skip the rest of the test (it's best effort)
42+
}
43+
44+
try
45+
{
46+
string[] modulePaths = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().Select(module => module.FileName).ToArray();
47+
Assert.Contains(longNamePath, modulePaths);
48+
}
49+
finally
50+
{
51+
Interop.Kernel32.FreeLibrary(moduleHandle);
52+
}
53+
}
54+
}
55+
}

src/libraries/System.Diagnostics.Process/tests/ProcessModuleTests.cs

Lines changed: 1 addition & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,13 @@
11
// Licensed to the .NET Foundation under one or more agreements.
22
// The .NET Foundation licenses this file to you under the MIT license.
33

4-
using System.IO;
54
using System.Linq;
6-
using System.Reflection;
75
using Microsoft.DotNet.RemoteExecutor;
86
using Xunit;
97

108
namespace System.Diagnostics.Tests
119
{
12-
public class ProcessModuleTests : ProcessTestBase
10+
public partial class ProcessModuleTests : ProcessTestBase
1311
{
1412
[Fact]
1513
public void TestModuleProperties()
@@ -91,40 +89,5 @@ public void ModulesAreDisposedWhenProcessIsDisposed()
9189
process.Dispose();
9290
Assert.Equal(expectedCount, disposedCount);
9391
}
94-
95-
public static bool Is_LongModuleFileNamesAreSupported_TestEnabled
96-
=> PathFeatures.AreAllLongPathsAvailable() // we want to test long paths
97-
&& !PlatformDetection.IsMonoRuntime // Assembly.LoadFile used the way this test is implemented fails on Mono
98-
&& OperatingSystem.IsWindowsVersionAtLeast(8); // it's specific to Windows and does not work on Windows 7
99-
100-
[ConditionalFact(typeof(ProcessModuleTests), nameof(Is_LongModuleFileNamesAreSupported_TestEnabled))]
101-
public void LongModuleFileNamesAreSupported()
102-
{
103-
// To be able to test Long Path support for ProcessModule.FileName we need a .dll that has a path > 260 chars.
104-
// Since Long Paths support can be disabled (see the ConditionalFact attribute usage above),
105-
// we just copy "LongName.dll" from bin to a temp directory with a long name and load it from there.
106-
// Loading from new path is possible because the type exposed by the assembly is not referenced in any explicit way.
107-
const string libraryName = "LongPath.dll";
108-
const int minPathLength = 261;
109-
110-
string testBinPath = Path.GetDirectoryName(typeof(ProcessModuleTests).Assembly.Location);
111-
string libraryToCopy = Path.Combine(testBinPath, libraryName);
112-
Assert.True(File.Exists(libraryToCopy), $"{libraryName} was not present in bin folder '{testBinPath}'");
113-
114-
string directoryWithLongName = Path.Combine(TestDirectory, new string('a', Math.Max(1, minPathLength - TestDirectory.Length)));
115-
Directory.CreateDirectory(directoryWithLongName);
116-
117-
string longNamePath = Path.Combine(directoryWithLongName, libraryName);
118-
Assert.True(longNamePath.Length > minPathLength);
119-
120-
File.Copy(libraryToCopy, longNamePath);
121-
Assert.True(File.Exists(longNamePath));
122-
123-
Assembly loaded = Assembly.LoadFile(longNamePath);
124-
Assert.Equal(longNamePath, loaded.Location);
125-
126-
string[] modulePaths = Process.GetCurrentProcess().Modules.Cast<ProcessModule>().Select(module => module.FileName).ToArray();
127-
Assert.Contains(longNamePath, modulePaths);
128-
}
12992
}
13093
}

0 commit comments

Comments
 (0)