2012-01-16 8 views
7

スレッドからXE/XE2でSOAPを使用する際に問題が発生しています。 (私は古いDelphisでテストしませんでした)Invalid pointer operationでTHTTPReqRespインスタンスを破棄している間に、メインスレッドで動作する単純なコードがクラッシュします。スレッド内のTHTTPReqRespコンポーネントを破棄できません。

これは完全なプログラムです。例外が_FreeMem呼び出しでTObject.FreeInstanceに発生し

unit Unit79; 

interface 

uses 
    SysUtils, Forms, Classes, Controls, StdCtrls, ComObj, 
    ActiveX, InvokeRegistry, SOAPHTTPTrans, Rio, SOAPHTTPClient; 

type 
    TForm79 = class(TForm) 
    btnTest: TButton; 
    procedure btnTestClick(Sender: TObject); 
    private 
    { Private declarations } 
    public 
    { Public declarations } 
    end; 

var 
    Form79: TForm79; 

implementation 

{$R *.dfm} 

procedure TForm79.btnTestClick(Sender: TObject); 
begin 
    TThread.CreateAnonymousThread(
    procedure 
    var 
     FHTTPReqResp: THTTPReqResp; 
     FHTTPRIO: THTTPRIO; 
    begin 
     if CoInitializeEx(NIL, COINIT_MULTITHREADED or COINIT_SPEED_OVER_MEMORY) = S_OK then try 
     FHTTPReqResp := THTTPReqResp.Create(nil); 
     with FHTTPReqResp do begin 
      Name := 'HTTPReqResp1'; 
      UseUTF8InHeader := True; 
      InvokeOptions := [soIgnoreInvalidCerts, soAutoCheckAccessPointViaUDDI]; 
      WebNodeOptions := []; 
     end; 
     FHTTPRIO := THTTPRIO.Create(nil); 
     with FHTTPRIO do begin 
      Name := 'HTTPRIO1'; 
      HTTPWebNode := FHTTPReqResp; 
     end; 
     // 
     FreeAndNil(FHTTPRIO); 
     FreeAndNil(FHTTPReqResp); //<-- crashes here 
     finally CoUninitialize; end; 
    end 
).Start; 
end; 

end. 

:フォームはbtnTestClickイベントをトリガーする唯一のボタンが含まれています。

procedure TObject.FreeInstance; 
begin 
    CleanupInstance; 
    _FreeMem(Self); 
end; 

この問題につながるコールスタックは_ClassDestroyがすべてで呼び出され、コードがクラッシュした理由:(誰かことができる理由、私は何が起こっている全く見当がつかない

:75bab9bc KERNELBASE.RaiseException + 0x58 System.TObject.FreeInstance 
System.ErrorAt(2,$4052E1) System.Error(reInvalidPtr) 
System.TObject.FreeInstance System._ClassDestroy(???) 
Soap.SOAPHTTPTrans.THTTPReqResp.Destroy System.TObject.Free 
frmMain.TMainForm.btnTestClick$4934$ActRec.$0$Body 
System.Classes.TAnonymousThread.Execute 
System.Classes.ThreadProc($F83530) System.ThreadWrapper($F51050) 
:76a4339a kernel32.BaseThreadInitThunk + 0x12 :77b59ef2 
ntdll.RtlInitializeExceptionChain + 0x63 :77b59ec5 
ntdll.RtlInitializeExceptionChain + 0x36 

ですa)私が間違っていることを説明し、b)自分のコードを修正してください。

+0

D2010にはまだCreateAnonymousThreadがありません。今すぐ非匿名で試してみてください。非匿名のスレッドではクラッシュしません。 –

+0

スレッディングは問題ではない(私は思う)。それはOmniThreadLibrary(これは私がこの問題を見つけた方法でした)と同じクラッシュします。 – gabr

+3

THttprioのドキュメントから、「nil(Delphi)またはNULL(C++)パラメータで作成すると、参照カウントがゼロになると自動的に破棄されます」。明示的に解放しています。 –

答えて

8

"無効なポインタ操作"は、有効なメモリを示さないものを解放していることを意味します。スタックやヒープの破損を示すことがありますが、すでに解放されているものを解放している可能性があります。

_ClassDestroyが呼び出されるのは驚くことではありません。 FHTTPReqRespはnullではないため、FreeAndNilFreeを呼び出すと、FreeDestroyとなります。

THTTPRIOオブジェクトは、あなたがそれを与えるTHTTPReqRespの所有権を取得しているようです。その場合、解決策は簡単です。自分で解放しないでください。

+3

あなたは正しいです。 FHTTPRIOだけを解放すると、FastMM4 FullDebugModeの確認が破棄されます。愚かなコードのアーキテクチャ、私はそれを考えることはありません! – gabr

+0

SOAPアーキテクチャは、「Yuck!瞬間私はそれを使って1年を過ごしました。私の最も好きな点は、通常はWinInetに依存する方法です。これはバグで、一部のWindowsシステムではタイムアウト/フリーズアップが発生します。インディベースのHTTPRIOトランスポートに切り替えると、ランダムなフリーズはなくなりますが、パフォーマンスの全体的な低下は約40%になります。良い選択。 –

+0

この回答に感謝します。私はメモリリークの問題を抱えています。うまくいけば、これで解決します。 –