5

I was unit testing in C#, and I found the following code gives an overflow exception:

using System;
                    
public class Program
{
    public static void Main()
    {
        int i = 0;
        Console.WriteLine(new float[i - 1]);
        // System.OverflowException: Arithmetic operation resulted in an overflow.
    }
}

https://dotnetfiddle.net/clbgZ3

However, if you explicitly attempt to initialize a negative array, you get the following error:

Console.WriteLine(new float[-1]);
// Compilation error: Cannot create an array with a negative size

Why does initializing a negatively-sized array cause an overflow exception, and not a different type of error?

CoderMuffin
  • 519
  • 1
  • 10
  • 21
ADAMJR
  • 1,880
  • 1
  • 14
  • 34

2 Answers2

7

It is not a stack overflow, but a numeric overflow: -1 is outside the legal values (of probably an unsigned int). See the answer of orhtej2 for the exact language specification.

The same exception would happen for this:

int i = -1;
checked
{
    uint ui = (uint)i;
    // Arithmetic operation resulted in an overflow.
}

You do need the checked context for this error to appear, otherwise the bits would just be copied (and the value would be 4294967295).

And about the different errors: the first is a runtime exception, the second is a compiler error.

Hans Kesting
  • 38,117
  • 9
  • 79
  • 111
  • 2
    This makes sense **if** signed-to-unsigned conversion happens behind the scenes, on the other hand for some reason [Ąrray.Length](https://learn.microsoft.com/en-us/dotnet/api/system.array.length?view=net-7.0) is of a signed `int` type so I'm not sure if such conversion happens. Not that I'm saying it makes sense to have an array of length `-1`. – orhtej2 Jun 02 '23 at 10:15
  • 2
    I misread 'System' in 'System.OverflowException' as 'Stack', don't ask me how. Both answers are informative. It's true that Array.Length uses a signed integer, but maybe it's to prevent having to explicitly convert between uint and int when you want to iterate arrays by length for example. – ADAMJR Jun 02 '23 at 10:52
  • 1
    @orhtej2 the "unsigned int" was a guess on my part, at least the action *acts like* it assigns to an unsigned int (in a checked context). But is could also be a simple int with an explicit check that throws that exception – Hans Kesting Jun 02 '23 at 13:36
6

This behaviour is explicitly specified in C# language specification, section 12.8.16.5

The result of evaluating an array creation expression is classified as a value, namely a reference to the newly allocated array instance. The run-time processing of an array creation expression consists of the following steps:

(...)

  • The computed values for the dimension lengths are validated, as follows: If one or more of the values are less than zero, a System.OverflowException is thrown and no further steps are executed.

(emphasis mine)

orhtej2
  • 2,133
  • 3
  • 16
  • 26
  • 3
    It's interesting that this is specified to throw a misleading error, but [`Array.CreateInstance`](https://learn.microsoft.com/en-us/dotnet/api/system.array.createinstance?view=net-7.0#system-array-createinstance(system-type-system-int32)) throws the more inutitive `ArgumentOutOfRangeException`. – spender Jun 02 '23 at 09:49
  • I was looking for an infinite loop in my code and thought 'OverflowException' meant that I had found the right error. 'ArgumentOutOfRangeException' would be seem more intuitive, since -1 is out of range of a valid array size. – ADAMJR Jun 02 '23 at 10:57
  • 1
    Also in the same section *"Since the length of an array dimension shall be nonnegative, it is a compile-time error to have a constant expression with a negative value, in the expression list."* – Charlieface Jun 02 '23 at 13:01