2009-08-18 10 views
3

特定のケースでは、Delphi 5が無効なアセンブリコードを生成することがわかりました。私は一般的にどのような場合に理解できません。非常に奇妙な最適化が発生するため、以下の例ではアクセス違反が発生します。レコードまたは配列内のバイトについてDelphiは、このバイトの後にデータがある場合(正確にはdwordを3回押す必要がある)正しく動作するpush dword [...]、pop ebx、mov ..、blを生成しますが、失敗しますデータにアクセスできない場合私は具体的にエラーが発生したwin32のバーチャル*機能 Delphiの "push dword"バグを回避するにはどうすればよいですか?

とここに厳密な境界をエミュレートするときFeedBytesToClass手続きの内側にアクセスされたブロックから最後のバイト。また、remove actionFlag変数のオブジェクトプロパティの代わりにデータ配列を使用するようなものを変更しようとすると、Delphiは正しいアセンブリ命令を生成します。 IビットマップビットのRGBデータへのアクセスを使用した場合

const 
    BlockSize = 4096; 

type 
    TSomeClass = class 
    private 
    fBytes: PByteArray; 
    public 
    property Bytes: PByteArray read fBytes; 
    constructor Create; 
    destructor Destroy;override; 
    end; 

constructor TSomeClass.Create; 
begin 
    inherited Create; 
    GetMem(fBytes, BlockSize); 
end; 

destructor TSomeClass.Destroy; 
begin 
    FreeMem(fBytes); 
    inherited; 
end; 

procedure FeedBytesToClass(SrcDataBytes: PByteArray; Count: integer); 
var 
    j: integer; 
    Ofs: integer; 
    actionFlag: boolean; 
    AClass: TSomeClass; 
begin 
    AClass:=TSomeClass.Create; 
    try 
    actionFlag:=true; 

    for j:=0 to Count-1 do 
    begin 
     Ofs:=j; 
     if actionFlag then 
     begin 
     AClass.Bytes[Ofs]:=SrcDataBytes[j]; 
     end; 
    end; 
    finally 
    AClass.Free; 
    end; 
end; 

procedure TForm31.Button1Click(Sender: TObject); 
var 
    SrcDataBytes: PByteArray; 
begin 
    SrcDataBytes:=VirtualAlloc(Nil, BlockSize, MEM_COMMIT, PAGE_READWRITE); 
    try 
    if VirtualLock(SrcDataBytes, BlockSize) then 
     try 
     FeedBytesToClass(SrcDataBytes, BlockSize); 
     finally 
     VirtualUnLock(SrcDataBytes, BlockSize); 
     end; 
    finally 
    VirtualFree(SrcDataBytes, MEM_DECOMMIT, BlockSize); 
    end; 
end; 

は、最初にエラーが発生しましたが、コードは複雑すぎあるので、私はこの断片にそれを狭く。

そこで問題は、ここではそのDelphiの農産物プッシュを作る具体的な、ポップ、MOVの最適化は何かということです。私はこのような副作用を一般的に避けるためにこれを知る必要があります。

+0

Delphi5のすべてのアップグレードをインストールしましたか? – smok1

+0

はい、あります。実際、このバグは依然としてDelphiに存在する可能性があります。これは、globalallocは後で余分なバイトと内部getmemを頻繁に割り当てるためです。 – Maksee

+2

QCにこのバグはありますか?これは、それが新しいバージョンで修正されているかどうか、また回避策があるかもしれないことを教えてくれます。 –

答えて

3

アップグレード。 Delphi 5は10年前にリリースされました。

+2

Bruce、一部の人(私のような人)は、従来のアプリケーションを維持するためにDelphi 5を使用しています。 – smok1

+0

それは頬の発言の舌であると考えてください。 –

3

知らんまさに問題は、あなたの質問ではなく、とらえどころのないですようです...しかし、いくつかの発言:

  • は、なぜあなたはGetMemを使用しての代わりに、されている、特にためには小さすぎるブロックサイズと新、 ByteArray。私はD5を持っているが、D2007ではありません

    PByteArray =^TByteArray。
    TByteArray =バイトの配列[0 .. ]。

  • FastMM4を使用してメモリを割り当てます。それは何が起こっているのかを見て問題を見つけるのが簡単です。

ところで、D2007にコンパイラによって生成されたASMは何Paul-Jan postedの違い:

Unit7.pas.67: AClass.Bytes[Ofs]:=SrcDataBytes[j]; 
     mov ebx,[ebp-$04] 
     movzx ebx,[ebx+eax] 
     push ebx 
     mov ebx,[ebp-$08] 
     mov ebx,[ebx+$04] 
     lea esi,[ebx+esi] 
     pop ebx 
     mov [esi],bl 
Unit7.pas.69: end; 
     inc eax 
+0

ええ、Paul-JanはおそらくD6でバグが修正されたと言っていたので、D2007でそのようなコードが生成されたのは興味深いことです。それはまだデルファイがdwordとしてデータにアクセスしようとしているようです – Maksee

10

確かに痛い、痛い問題。一定のactionFlag(4の倍数の定数カウントと組み合わされた)が存在すると、データを処理するプッシュ/ポップスタイルがトリガされます。実際のアセンブラに興味のある人、(手動バックとして以上の型指定された日で、CPUビューは、コピー/ペーストを提供していませんでした)の場合:

AClass.Bytes[Ofs] := SrcDataBytes[j]; 
    mov exc,[ebp-$04] 
    push dword ptr [ecx+eax] <- ouch 
    mov ecx,[ebp-$08] 
    mov ecx,[exc+04] 
    lea esi,[exc+esi] 
    pop ecx 
    mov [esi],cl 
end; 
    inc eax 

それは、この4096回を行います。私はチェックし、Delphi 6にはこの動作がありません。私はそれが後のバージョンでも修正されていると思っても安全だと思います。

回避策として、私は単純に加えることをお勧めしたい{$ O - }/{$のOの+を}メソッドに。私は、正確な法医学にはあまりにも多くのことをやっていません。この誤った最適化を実行するためにDelphiを起動させる条件はまれであるようですが、Delphiのバージョンはむしろ古くからあります。

定数のフラグは、通常、内部ループの一部ではない、と私はあなたのカウントが正常にもダイナミックになります疑い。しかし、あなたは本番のコードでこの問題にぶつかりました。おそらくそれはそうであるようにまれではありません。私が言うことができるのは、です。を実行したことは一度もありません。私たちはDelphi 5でプロダクションコードの90%を書いています。おそらくデフォルトメモリ割り当ての安全性だけです。

+0

Paul-Jan、私はFrançoisのポストから見ると、D2007は依然としてデータをdwordとしてアクセスしようとしています。あなたはDelphi 6をお持ちですか? – Maksee

関連する問題