Skip to content

RangeAttribute throws exception if value is outside range of type #115982

Open
@BillVanArk

Description

@BillVanArk

Description

You use RangeAttribute like this, to indicate a minimum and maximum value for data annotation:

    [Range(-50, 50)]
    public string Value { get; set; }

If you try to pass a value that is not an integer, or doesn’t fall between [-50, 50], IsValid() correctly returns false.

However, if you pass a numerical value that falls outside the bounds of the type (e.g. 2147483648L which exceeds the maximum value of int), then you get an uncaught exception:

System.OverflowException: Value was either too large or too small for an Int32.
   at System.Number.ThrowOverflowException[TInteger]()
   at System.String.System.IConvertible.ToInt32(IFormatProvider provider)
   at System.ComponentModel.DataAnnotations.RangeAttribute.<>c.<SetupConversion>b__37_0(Object v)
   at System.ComponentModel.DataAnnotations.RangeAttribute.IsValid(Object value)
   at System.ComponentModel.DataAnnotations.ValidationAttribute.IsValid(Object value, ValidationContext validationContext)

The try/catch block in RangeAttribute:IsValid() should handle all exceptions by returning false, not just a selected few exception types.

Reproduction Steps

var rangeAttribute = new RangeAttribute(-50, 50);
rangeAttribute.IsValid(2147483648L); // throws OverflowException instead of returning false

Expected behavior

Any failure in IsValid() should return false.

Actual behavior

Some failures in IsValid() result in an unhandled exception.

Regression?

Unknown

Known Workarounds

You can subclass RangeAttribute, override IsValid(), and wrap the call to base.IsValid() in an exception handler:

public class CorrectedRangeAttribute : RangeAttribute
{
    public CorrectedRangeAttribute(double minimum, double maximum) : base(minimum, maximum)
    {
    }

    public CorrectedRangeAttribute(int minimum, int maximum) : base(minimum, maximum)
    {
    }

    public CorrectedRangeAttribute(Type type, string minimum, string maximum) : base(type, minimum, maximum)
    {
    }

    public override bool IsValid(object value)
    {
        try
        {
            return base.IsValid(value);
        }
        catch
        {
            return false;
        }
    }
}

Configuration

  • net8.0, net9.0
  • Windows 11 Enterprise 23H2
  • x64
  • This is a code problem, not an execution environment problem
  • N/A

Other information

The problem is in runtime/src/libraries/System.ComponentModel.Annotations/src/System/ComponentModel/DataAnnotations /RangeAttribute.cs in the function public override bool IsValid(object? value) where there is no final catch in the try/catch block.

This allows uncaught exceptions to flow out of a function which should always return either true or false.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions