是否可以在未专门启用的情况下生成范围检查错误?
Can a Range check error be generated without being specifically enabled?
一位客户报告了 Range check error
在工厂中嵌入的机器 运行 较旧的 Delphi 7 应用程序。我们(尚未)能够重现该错误。他们给我们发了一张照片:
该软件可以连续几天正常运行,而我们目前只有模糊的线索来说明这个 可能 是如何生成或可靠地复制的。我的理解是这个错误发生在两种一般情况下:
(1) An array or string has been accessed outside its bounds
(2) The variable is assigned a value out-of-range for its type
如果只有 40 个元素,则 (1) 的示例是访问数组 [50]。 (2) 的示例是将值“300”分配给无符号 BYTE。
这来自SO question 1 and SO question 2。我有很多仔细的检查工作要做,试图找出有问题的行!
我的问题是这个错误最初是如何产生的。上述两个问题都涉及 {$R+}
编译器指令。在 Project Options > Compiler > Runtime errors 中,Range checking
处于关闭状态,代码中的任何地方都没有使用 {$R+}
(也没有 {$R-}
)。这个错误是怎么发生的?应用程序不应该崩溃或生成不同的异常吗?
是的,无需专门启用范围检查错误就可以引发它
例如只看TStream.SetSize函数:
procedure TStream.SetSize(const NewSize: Int64);
begin
if (NewSize < Low(Integer)) or (NewSize > High(Integer)) then
raise ERangeError.CreateRes(@SRangeError);
SetSize(LongInt(NewSize));
end;
因此无论是否启用范围检查错误都会引发异常。你有 delphi 几个这样的函数。
我来回答问题:
Can a Range check error be generated without being specifically enabled?
但是,您在客户站点遇到的问题需要进一步调查才能解决。通常这种事情需要以下组合:
- 异常日志记录:在发生异常时生成堆栈跟踪以准确确定调用了哪些代码的工具。
- Tracing:记录消息,提供有关应用程序状态的线索,以帮助您进行调查。
是的,范围检查错误可以生成而无需特别启用。
- 可以随时使用
raise ERangeError.Create(...);
引发范围检查错误。如果调用,无论 range-check 设置的状态如何,这都会引发错误。
注意代码可以如果这样写,也遵守如下设置:
{$IFOPT R+}
raise ERangeError.Create(...);
{$ENDIF}
但重点是一旦调用raise <SomeClass>.Create(...)
,就会引发异常。如果您搜索 Delphi 源代码,您会发现一些引发 ERangeError
的地方。 Loki 的回答提供了一个例子。
- 第二个需要注意的重要事项是
{$R}
设置不是全局的。如果您在关闭此设置的情况下编译项目,但在打开此选项编译的 DCU 中 link:则设置 仍将 开启 对于那些 DCU。
此外,可以针对特定代码段在本地更改设置。例如
{$IFOPT R-} {$R+} {$DEFINE TOGGLE_ROFF} {$ENDIF}
{ Ensure range-checking is on, but turn off again if it was already off.}
procedure MustUseRangeChecking(...);
begin
...
end;
{$IFDEF TOGGLE_ROFF} {$R-} {$ENDIF}
注意:您可以在自己的代码中使用 {$IFOPT}
来检查 range-checking 指令的状态。
一位客户报告了 Range check error
在工厂中嵌入的机器 运行 较旧的 Delphi 7 应用程序。我们(尚未)能够重现该错误。他们给我们发了一张照片:
该软件可以连续几天正常运行,而我们目前只有模糊的线索来说明这个 可能 是如何生成或可靠地复制的。我的理解是这个错误发生在两种一般情况下:
(1) An array or string has been accessed outside its bounds
(2) The variable is assigned a value out-of-range for its type
如果只有 40 个元素,则 (1) 的示例是访问数组 [50]。 (2) 的示例是将值“300”分配给无符号 BYTE。
这来自SO question 1 and SO question 2。我有很多仔细的检查工作要做,试图找出有问题的行!
我的问题是这个错误最初是如何产生的。上述两个问题都涉及 {$R+}
编译器指令。在 Project Options > Compiler > Runtime errors 中,Range checking
处于关闭状态,代码中的任何地方都没有使用 {$R+}
(也没有 {$R-}
)。这个错误是怎么发生的?应用程序不应该崩溃或生成不同的异常吗?
是的,无需专门启用范围检查错误就可以引发它
例如只看TStream.SetSize函数:
procedure TStream.SetSize(const NewSize: Int64);
begin
if (NewSize < Low(Integer)) or (NewSize > High(Integer)) then
raise ERangeError.CreateRes(@SRangeError);
SetSize(LongInt(NewSize));
end;
因此无论是否启用范围检查错误都会引发异常。你有 delphi 几个这样的函数。
我来回答问题:
Can a Range check error be generated without being specifically enabled?
但是,您在客户站点遇到的问题需要进一步调查才能解决。通常这种事情需要以下组合:
- 异常日志记录:在发生异常时生成堆栈跟踪以准确确定调用了哪些代码的工具。
- Tracing:记录消息,提供有关应用程序状态的线索,以帮助您进行调查。
是的,范围检查错误可以生成而无需特别启用。
- 可以随时使用
raise ERangeError.Create(...);
引发范围检查错误。如果调用,无论 range-check 设置的状态如何,这都会引发错误。
注意代码可以如果这样写,也遵守如下设置:
{$IFOPT R+}
raise ERangeError.Create(...);
{$ENDIF}
但重点是一旦调用raise <SomeClass>.Create(...)
,就会引发异常。如果您搜索 Delphi 源代码,您会发现一些引发 ERangeError
的地方。 Loki 的回答提供了一个例子。
- 第二个需要注意的重要事项是
{$R}
设置不是全局的。如果您在关闭此设置的情况下编译项目,但在打开此选项编译的 DCU 中 link:则设置 仍将 开启 对于那些 DCU。
此外,可以针对特定代码段在本地更改设置。例如
{$IFOPT R-} {$R+} {$DEFINE TOGGLE_ROFF} {$ENDIF}
{ Ensure range-checking is on, but turn off again if it was already off.}
procedure MustUseRangeChecking(...);
begin
...
end;
{$IFDEF TOGGLE_ROFF} {$R-} {$ENDIF}
注意:您可以在自己的代码中使用 {$IFOPT}
来检查 range-checking 指令的状态。