Search code examples
delphidelphi-xe2

Why accessing out-of-bounds indices of dynamic array doesn't raise AV?


In the VCL, TByteDynArray is defined as a dynamic array:

type TByteDynArray = array of Byte;

But it seems that no index bounds checking is done:

var
  DataBytes: System.Types.TByteDynArray;
  i: Integer;
begin
  SetLength(DataBytes, 2);
  DataBytes[5] := 222; // Accessing index beyond set length.
  i := DataBytes[5]; // `i` is now set to "222".

The code above runs without errors.

Why isn't an AccessViolation raised, like with a static array? What is the point of SetLength if you can access and modify 65536 bytes of memory of the array variable regardless of the length set?


Solution

  • To detect array index out of bounds errors, set range check error on.

    Range Checking

    The $R directive enables or disables the generation of range-checking code. In the {$R+} state, all array and string-indexing expressions are verified as being within the defined bounds, and all assignments to scalar and subrange variables are checked to be within range. If a range check fails, an ERangeError exception is raised (or the program is terminated if exception handling is not enabled).

    This is default set to {$R-}, but I suggest to set it on, at least through the development phase. It adds an extra overhead to the code, so this may be the reason it is off by default.


    If you have a unit that is well tested and want to avoid range checking, add {$R-} at the top of the unit. This will override the project setting locally.

    If you want to avoid range checking in a code block, this technique could be used:

    {$IFOPT R+}
      {$DEFINE RestoreRangeCheck}
      {$R-}
    {$ENDIF}
    
    {- Some code here }
    
    {$IFDEF RestoreRangeCheck}
      {$R+}
      {$UNDEF RestoreRangeCheck}
    {$ENDIF}