未经专门启用就可以生成范围检查错误吗?

时间:2018-03-31 10:37:08

标签: delphi delphi-7

客户在运行旧版Delphi 7应用程序的工厂中嵌入的计算机上报告Range check error。我们还没有能够重现错误。他们给我们发了一张照片:

Range check error

软件可以连续几天正常运行,我们目前只有关于如何 生成或可靠复制的模糊线索。我的理解是这个错误发生在两个一般场景中:

(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 1SO question 2。我有很多仔细的检查来尝试识别有问题的线路!

我的问题是这个错误是如何产生的。上述两个问题都涉及{$R+}编译器指令。在项目选项>编译器>运行时错误Range checking已关闭,代码中没有任何地方使用{$R+}(也不是{$R-})。这个错误是怎么发生的?应用程序不应该崩溃或生成不同的异常吗?

2 个答案:

答案 0 :(得分:4)

我将回答这个问题:

  

是否可以在未明确启用的情况下生成范围检查错误?

但是,您在客户的网站上遇到的问题需要进一步调查才能解决。通常这种事情需要结合:

  • 异常日志记录:在发生异常时生成堆栈跟踪的工具,以确切确定正在调用的代码。
  • 跟踪:记录消息,提供有关应用程序状态的线索,以协助您进行调查。

是的,未经特别启用,生成范围检查错误

  1. 可以随时使用raise ERangeError.Create(...);引发范围检查错误。如果被调用,无论范围检查设置的状态如何,都会引发错误。
  2. 注意代码可以如果这样写,也遵守以下设置:

    {$IFOPT R+}
      raise ERangeError.Create(...);
    {$ENDIF}
    

    但重点是,只要调用raise <SomeClass>.Create(...),就会引发 异常 。如果您搜索Delphi源代码,您将找到引发ERangeError的几个地方。 Loki的回答提供了一个例子。

    1. 需要注意的第二个重要事项是{$R}设置不是全局的。如果您使用此设置编译项目,请关闭,但在已打开选项的情况下编译的DCU中的链接:那么对于那些DCU仍然 。< / LI>

      此外,可以针对特定代码段本地更改设置。 E.g。

      {$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}来检查范围检查指令的状态。

答案 1 :(得分:3)

是的,可以在没有专门启用范围检查错误的情况下提升

例如只看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中有这样的几个函数。