为什么访问动态数组的越界索引不会引起AV?

DBe*_*nko 3 delphi delphi-xe2

在VCL中,TByteDynArray被定义为动态数组:

type TByteDynArray = array of Byte;
Run Code Online (Sandbox Code Playgroud)

但似乎没有完成索引边界检查:

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".
Run Code Online (Sandbox Code Playgroud)

上面的代码运行没有错误.

为什么AccessViolation不像一个静态数组一样被提升?什么是点SetLength,如果你可以访问和修改65536个字节数组变量的内存,无论长度设定的?

LU *_* RD 6

要检测数组索引超出范围错误,请设置范围检查错误.

范围检查

$ R指令启用或禁用范围检查代码的生成.在{$ R +}状态中,所有数组和字符串索引表达式都被验证为在定义的范围内,并且所有对标量和子范围变量的赋值都被检查在范围内.如果范围检查失败,则引发ERangeError异常(或者如果未启用异常处理,则终止程序).

这默认设置为{$ R-},但我建议将其设置为开启,至少在开发阶段.它为代码增加了额外的开销,因此这可能是它默认关闭的原因.


如果您的设备经过良好测试并希望避免范围检查,请在设备顶部添加{$ R-}.这将在本地覆盖项目设置.

如果要避免代码块中的范围检查,可以使用以下技术:

{$IFOPT R+}
  {$DEFINE RestoreRangeCheck}
  {$R-}
{$ENDIF}

{- Some code here }

{$IFDEF RestoreRangeCheck}
  {$R+}
  {$UNDEF RestoreRangeCheck}
{$ENDIF}
Run Code Online (Sandbox Code Playgroud)

  • @NewWorld你应该*总是*运行范围检查和溢出检查开启(至少在你的调试配置中).将其设为IDE的默认值.为什么默认情况下没有打开,打败了我.一个愚蠢的设计决定IMO (2认同)