Delphi 为什么访问动态数组的越界索引不';你不能提高AV吗?
在VCL中,Delphi 为什么访问动态数组的越界索引不';你不能提高AV吗?,delphi,delphi-xe2,Delphi,Delphi Xe2,在VCL中,TByteDynArray被定义为动态数组: type TByteDynArray = array of Byte; 但似乎没有进行索引边界检查: var DataBytes: System.Types.TByteDynArray; i: Integer; begin SetLength(DataBytes, 2); DataBytes[5] := 222; // Accessing index beyond set length. i := DataBytes
TByteDynArray
被定义为动态数组:
type TByteDynArray = array of Byte;
但似乎没有进行索引边界检查:
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".
上面的代码运行时没有错误
为什么不像静态数组那样引发
AccessViolation
?如果可以访问和修改数组变量的65536字节内存,而不考虑设置的长度,那么设置长度有什么意义?要检测数组索引越界错误,请启用范围检查错误
$R指令启用或禁用范围检查代码的生成。在{$R+}状态下,验证所有数组和字符串索引表达式是否在定义的范围内,并检查标量和子范围变量的所有赋值是否在范围内。如果范围检查失败,将引发ERangeError异常(如果未启用异常处理,则程序将终止)
这是默认设置为{$R-},但我建议至少在开发阶段设置它。
它会给代码增加额外的开销,因此这可能是它默认关闭的原因
如果您有一个经过良好测试的单元,并且希望避免范围检查,请在单元顶部添加{$R-}。这将在本地覆盖项目设置 如果要避免代码块中的范围检查,可以使用以下技术:
{$IFOPT R+}
{$DEFINE RestoreRangeCheck}
{$R-}
{$ENDIF}
{- Some code here }
{$IFDEF RestoreRangeCheck}
{$R+}
{$UNDEF RestoreRangeCheck}
{$ENDIF}
默认情况下禁用范围检查;使用
$r+
启用它上面的代码运行时不会出错。大概也许不是。是否存在错误是不可预测的。您永远无法预测被覆盖的内容。有时这是一场灾难,有时它会带来一些微妙的错误。你只是运气不好,没有出现错误。另一次,你会写一些重要的东西,并在其他地方使用。你使用了很多不正确的假设作为基础,你的问题在结果上没有多大意义。静态数组可能不会导致A/V假定超出绑定的内存分配给其他对象。如果在最后一页边界下紧密分配,动态数组可能会导致A/V。然而,我确信,使用默认的FastMM对齐方式,访问2字节数组边界以上3字节的内容永远不会崩溃。因此,您的答案是-您正在以填充字节的形式存储值222。感谢您提供了有用的答案。您能给我一些指导,我是否应该打开它(而不是在代码中进行显式范围检查)?为什么默认情况下不启用此选项?@NewWorld您应该始终在启用范围检查和溢出检查的情况下运行(至少在调试配置中)。将其作为IDE的默认设置。我不明白为什么默认情况下不打开。一个愚蠢的设计决策,因为人们通常将数组定义为整数的A=array[0..0],然后动态地为它分配(一大块)内存。看了很多VCL。在这种情况下,您不需要{$R+}
。不过,默认情况下它应该是开着的。@Johan,这并不能解释任何事情。VCL代码可以很容易地使用$R,甚至更好地避免这种构造。如果Emba在意,他们将默认启用范围和溢出检查。有些VCL代码很差,这很难成为让新手没有安全网的理由。@Johan,通常当你有意放弃控制时,你要确保代码块周围有范围检查。