为什么访问动态数组的越界索引不会提高 AV?
Why accessing out-of-bounds indices of dynamic array doesn't raise AV?
在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[5]; // `i` is now set to "222".
上面的代码运行没有错误。
为什么不像静态数组那样引发 AccessViolation
?如果无论长度设置如何都可以访问和修改数组变量的 65536 字节内存,SetLength
有什么意义?
要检测数组索引越界错误,请将范围检查错误设置为开。
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).
默认设置为 {$R-},但我建议至少在开发阶段启用它。
它给代码增加了额外的开销,所以这可能是它默认关闭的原因。
如果您有一个经过良好测试的单元并希望避免范围检查,请在单元顶部添加 {$R-}。这将在本地覆盖项目设置。
如果您想避免在代码块中进行范围检查,可以使用以下技术:
{$IFOPT R+}
{$DEFINE RestoreRangeCheck}
{$R-}
{$ENDIF}
{- Some code here }
{$IFDEF RestoreRangeCheck}
{$R+}
{$UNDEF RestoreRangeCheck}
{$ENDIF}
在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[5]; // `i` is now set to "222".
上面的代码运行没有错误。
为什么不像静态数组那样引发 AccessViolation
?如果无论长度设置如何都可以访问和修改数组变量的 65536 字节内存,SetLength
有什么意义?
要检测数组索引越界错误,请将范围检查错误设置为开。
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).
默认设置为 {$R-},但我建议至少在开发阶段启用它。 它给代码增加了额外的开销,所以这可能是它默认关闭的原因。
如果您有一个经过良好测试的单元并希望避免范围检查,请在单元顶部添加 {$R-}。这将在本地覆盖项目设置。
如果您想避免在代码块中进行范围检查,可以使用以下技术:
{$IFOPT R+}
{$DEFINE RestoreRangeCheck}
{$R-}
{$ENDIF}
{- Some code here }
{$IFDEF RestoreRangeCheck}
{$R+}
{$UNDEF RestoreRangeCheck}
{$ENDIF}