Reported by Hallvard Vassbotn; checked by Rune Moberg
以下の3つのファイルでこの問題を明らかにします:
LOCBUG.DPR:
program LocBug;
uses
LocBugA;
begin
end.
LOCBUGA.PAS:
unit LocBugA;
interface
{$HINTS OFF} {$WARNINGS OFF} {$ALIGN OFF}
type
TObjectA = class
private
UnusedA: integer; // ヒントが出るべきではなく、実際出ない
public
procedure Destroy; // 警告が出るべきではなく、実際出ない
end;
TRecA = record // SizeOf(TRecA) は 5 であるべきで、実際そうである
A: char;
L: longint;
end;
implementation
uses
LocBugB;
{.$HINTS OFF} // バグを回避するにはドットを取り除く
{.$WARNINGS OFF}
type
TObjectB = class
private
UnusedB: integer; // ヒントが出るべきではないが、D3 では(時々)出る
public
procedure Destroy; // 警告が出るべきではないが、D3 では(時々)出る
end;
{.$ALIGN ON} // ドットを取り除くと、下で無効なキャストになる
TRecB = record // SizeOf(TRecA) は 5 であるべきで、実際そうである
A: char;
L: longint;
end;
procedure TObjectA.Destroy; begin end;
procedure TObjectB.Destroy;
var
A: TRecA;
begin
TRecB(A).L := 123; // SizeOf(TRecA) = SizeOf(TRecB) なので、これは正しい
end;
end.
LOCBUGB.PAS:
unit LocBugB;
interface
implementation
{$HINTS ON} {$WARNINGS ON} {$ALIGN ON}
end.
問題は、コンパイラがユニット LocBugB を再コンパイルするとき、常に HINTS と WARNINGS をオンにし、このユニットが他のユニットで使用されている場所以降で有効である続けることです。コンパイラ指令子 ALIGN ではこの現象は発生しません。上のコメントの"(時々)"というのは、LocBugB が再コンパイルされるときは常に、ということに言及しているのです。
この意味するところは、あるユニットで HINTS と WARNINGS を確実にオフにするには、interface セクションの uses 節の後と、さらに implementation セクションの uses 節の後の両方に、{$HINTS OFF} と {$WARNINGS OFF} を加えなければならないということです。
このバグは無害のように見えますが、以前に私が書いた the very dangerous hints-bug (これは D3 を終了しなければならないアクセス違反を起こします)と組み合わされると、この新しいバグはとても面倒です。以前のバグに対する回避方法のひとつでは、全てのコードにおいてヒントをオフにしました。この新しいバグは、これが単純なものではないということを意味しています。
|