Skip to content

Commit e618e00

Browse files
[Xamarin.Android.Tools.AndroidSdk] Fix quotes in %PATH% or %PATHEXT% (#112)
Fixes: https://developercommunity.visualstudio.com/t/illegal-character-exception-in-xamarinandroid-afte/1363149 In 16.9 we are getting some reports of: (_ResolveSdks target) -> error XARSD7004: System.ArgumentException: Illegal characters in path. error XARSD7004: at System.IO.Path.CheckInvalidPathChars(String path, Boolean checkAdditional) error XARSD7004: at System.IO.Path.Combine(String path1, String path2) error XARSD7004: at Xamarin.Android.Tools.ProcessUtils.<FindExecutablesInDirectory>d__9.MoveNext() error XARSD7004: at Xamarin.Android.Tools.ProcessUtils.<FindExecutablesInPath>d__8.MoveNext() error XARSD7004: at Xamarin.Android.Tools.AndroidSdkBase.<GetAllAvailableAndroidNdks>d__73.MoveNext() error XARSD7004: at Xamarin.Android.Tools.AndroidSdkWindows.<GetAllAvailableAndroidNdks>d__43.MoveNext() error XARSD7004: at Xamarin.Android.Tools.AndroidSdkBase.GetValidNdkPath(String ctorParam) error XARSD7004: at Xamarin.Android.Tools.AndroidSdkBase.Initialize(String androidSdkPath, String androidNdkPath, String javaSdkPath) error XARSD7004: at Xamarin.Android.Tools.AndroidSdkWindows.Initialize(String androidSdkPath, String androidNdkPath, String javaSdkPath) error XARSD7004: at Xamarin.Android.Tools.AndroidSdkInfo..ctor(Action`2 logger, String androidSdkPath, String androidNdkPath, String javaSdkPath) error XARSD7004: at Xamarin.Android.Tasks.MonoAndroidHelper.RefreshAndroidSdk(String sdkPath, String ndkPath, String javaPath, TaskLoggingHelper logHelper) error XARSD7004: at Xamarin.Android.Tasks.ResolveSdks.RunTask() error XARSD7004: at Xamarin.Android.Tasks.AndroidTask.Execute() It appears this is simply a call like this failing: Path.Combine ("foo", "\"") Path.Combine ("\"", "foo") The most likely reason for certain customers to get this exception is because an environment variable contains quotes, e.g. rem Windows CMD.EXE set PATH='…' On Windows+CMD.EXE, the `'` (or `"`) is *not* needed, even if the value has spaces: rem Can cause Pain and Suffering™ set PATH="C:\This Directory Has Spaces;%PATH%" rem Good and Proper™ set PATH=C:\This Directory Has Spaces;%PATH% I could reproduce this in a test by setting `%PATH%` or `%PATHEXT%` to invalid names. For `%PATH%`, I could simply add a `Directory.Exists()` check in the place that makes sense. However, I think a `try`/`catch` of `ArgumentException` is the only way to handle `%PATHEXT%`? I had to put this in two places where the new test found an issue.
1 parent 554d45a commit e618e00

File tree

3 files changed

+60
-4
lines changed

3 files changed

+60
-4
lines changed

src/Xamarin.Android.Tools.AndroidSdk/ProcessUtils.cs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -173,8 +173,15 @@ internal static IEnumerable<string> FindExecutablesInPath (string executable)
173173

174174
internal static IEnumerable<string> FindExecutablesInDirectory (string dir, string executable)
175175
{
176+
if (!Directory.Exists (dir))
177+
yield break;
176178
foreach (var exe in ExecutableFiles (executable)) {
177-
var exePath = Path.Combine (dir, exe);
179+
string exePath;
180+
try {
181+
exePath = Path.Combine (dir, exe);
182+
} catch (ArgumentException) {
183+
continue;
184+
}
178185
if (File.Exists (exePath))
179186
yield return exePath;
180187
}

src/Xamarin.Android.Tools.AndroidSdk/Sdks/AndroidSdkBase.cs

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -292,9 +292,14 @@ static string GetExecutablePath (string? dir, string exe)
292292
if (string.IsNullOrEmpty (dir))
293293
return exe;
294294

295-
foreach (var e in ProcessUtils.ExecutableFiles (exe))
296-
if (File.Exists (Path.Combine (dir, e)))
297-
return e;
295+
foreach (var e in ProcessUtils.ExecutableFiles (exe)) {
296+
try {
297+
if (File.Exists (Path.Combine (dir, e)))
298+
return e;
299+
} catch (ArgumentException) {
300+
continue;
301+
}
302+
}
298303
return exe;
299304
}
300305
}

tests/Xamarin.Android.Tools.AndroidSdk-Tests/AndroidSdkInfoTests.cs

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,50 @@ public void Ndk_PathInSdk()
146146
}
147147
}
148148

149+
[Test]
150+
public void Ndk_Path_InvalidChars ()
151+
{
152+
CreateSdks (out string root, out string jdk, out string ndk, out string sdk);
153+
154+
Action<TraceLevel, string> logger = (level, message) => {
155+
Console.WriteLine ($"[{level}] {message}");
156+
if (level == TraceLevel.Error)
157+
Assert.Fail (message);
158+
};
159+
160+
var oldPath = Environment.GetEnvironmentVariable ("PATH");
161+
try {
162+
Environment.SetEnvironmentVariable ("PATH", "\"C:\\IHAVEQUOTES\\\"");
163+
// Check that this doesn't throw
164+
new AndroidSdkInfo (logger, androidSdkPath: sdk, androidNdkPath: null, javaSdkPath: jdk);
165+
} finally {
166+
Environment.SetEnvironmentVariable ("PATH", oldPath);
167+
Directory.Delete (root, recursive: true);
168+
}
169+
}
170+
171+
[Test]
172+
public void Ndk_PathExt_InvalidChars ()
173+
{
174+
CreateSdks (out string root, out string jdk, out string ndk, out string sdk);
175+
176+
Action<TraceLevel, string> logger = (level, message) => {
177+
Console.WriteLine ($"[{level}] {message}");
178+
if (level == TraceLevel.Error)
179+
Assert.Fail (message);
180+
};
181+
182+
var oldPathExt = Environment.GetEnvironmentVariable ("PATHEXT");
183+
try {
184+
Environment.SetEnvironmentVariable ("PATHEXT", string.Join (Path.PathSeparator.ToString (), "\"", ".EXE", ".BAT"));
185+
// Check that this doesn't throw
186+
new AndroidSdkInfo (logger, androidSdkPath: sdk, androidNdkPath: null, javaSdkPath: jdk);
187+
} finally {
188+
Environment.SetEnvironmentVariable ("PATHEXT", oldPathExt);
189+
Directory.Delete (root, recursive: true);
190+
}
191+
}
192+
149193
[Test]
150194
public void Ndk_AndroidSdkDoesNotExist ()
151195
{

0 commit comments

Comments
 (0)