Skip to content

[fix-finder] Narrow broad catch (Exception) in AndroidBuildToolsVersion.TryParse #11660

@github-actions

Description

@github-actions

Problem

AndroidBuildToolsVersion.TryParse wraps its parse logic in a try/catch (Exception) whose body is empty and undocumented. This bare catch silently swallows every exception type — including genuinely unexpected ones (e.g. a NullReferenceException introduced by a future bug in the parse path) — making real failures invisible and indistinguishable from an expected "bad version string" result. The catch block has no comment, so it also reads like an accidental swallow.

The expected-failure exception set here is small and knowable, so this is the textbook case for narrowing to the specific expected types (per the error-handling guidance).

Location

  • File(s): src/Xamarin.AndroidTools/AndroidBuildToolsVersion.cs
  • Line(s): 47–51 (the try / catch (Exception) in TryParse)

Current Code

public static bool TryParse (string input, out AndroidBuildToolsVersion result)
{
	result = null;

	if (String.IsNullOrEmpty (input))
		return false;

	try {
		result = ParseInternal (input);
		return true;
	} catch (Exception) {
	}

	return false;
}

Suggested Fix

Narrow the catch (Exception) to the specific exception types the parse path can actually throw, each with a short comment. The return false behavior on parse failure is preserved exactly:

public static bool TryParse (string input, out AndroidBuildToolsVersion result)
{
	result = null;

	if (String.IsNullOrEmpty (input))
		return false;

	try {
		result = ParseInternal (input);
		return true;
	} catch (FormatException) {
		// Non-numeric version component
	} catch (OverflowException) {
		// Version component outside the range of Int32
	} catch (ArgumentException) {
		// Negative or otherwise invalid version component (Version constructor)
	}

	return false;
}

Why these three types are exhaustive

ParseInternal (input) (same file) only calls input.Trim (), string.IndexOf (' '), guarded Substring calls (guarded by index > 0, so they cannot throw), and MonoDroidSdk.ParseVersion (versionText). MonoDroidSdk.ParseVersion (src/Xamarin.AndroidTools/MonoDroidSdk.cs:318) does:

var split = versionString.Trim ().Split ('.');
int major = int.Parse (split [0]);
int minor = split.Length > 1 ? int.Parse (split [1]) : 0;
int build = split.Length > 2 ? int.Parse (split [2]) : 0;
return new Version (major, minor, build);
  • int.Parse (string) throws FormatException (non-numeric) or OverflowException (out of Int32 range). split [0] is never null (string.Split never yields null elements), so ArgumentNullException is not reachable.
  • new Version (major, minor, build) throws ArgumentOutOfRangeException (a subclass of ArgumentException) when a component is negative (e.g. "-1.0").

Catching FormatException, OverflowException, and ArgumentException therefore covers every failure the current implementation can produce for any input, so the change is behavior-preserving for all real version strings. Catching ArgumentException (the base type) rather than only ArgumentOutOfRangeException is intentional defensiveness.

Guidelines

  • Follow Mono formatting style: tabs, one space before ( and [.
  • The owning project src/Xamarin.AndroidTools/Xamarin.AndroidTools.csproj targets netstandard2.0 (LangVersion 12). FormatException, OverflowException, ArgumentException, and multiple catch clauses are all available there — do not introduce newer APIs.
  • Do not change the method signature or the return false semantics: TryParse must still return false (never throw) for malformed version strings.
  • Reference: [try-catch (C#)]((learn.microsoft.com/redacted)

Acceptance Criteria

  • The empty catch (Exception) in TryParse is replaced with catch (FormatException), catch (OverflowException), and catch (ArgumentException) clauses, each with an explanatory comment
  • TryParse still returns false (does not throw) for all malformed version strings such as "abc", "1.x", "-1.0", and "99999999999999999999"
  • No other files or methods are modified
  • All tests pass
  • No new warnings introduced

Fix-finder metadata

  • Script: 07-error-handling
  • Score: 27/30 (actionability: 10, safety: 7, scope: 10)

Generated by Nightly Fix Finder · 1.2K AIC · ⌖ 71.4 AIC · ⊞ 40.4K ·

  • expires on Jun 23, 2026, 2:41 AM UTC

Metadata

Metadata

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions