5

何らかの理由で、sysUtils ヘッダーによって提供される TLanguages オブジェクトをシングルトンを使用するか、コンストラクターを直接呼び出して作成しようとすると、実際に問題が発生し、一部のユーザーがこのエラーを報告します (X は異なります)。

Access violation at address X. Write of address X (at address X)

...次の一見無害なコード行が実行されると:

TLanguages.Create;

明確にするために、これはコンテキストとは関係ありません。この行を好きな場所 (たとえば、空のプログラムの唯一のコード行) に配置できますが、問題は残ります。

奇妙な点は、このクラスが失敗しないはずの Delphi の標準ヘッダーの一部であることです (そうですか?)。

constructor TLanguages.Create;
type
  TCallbackThunk = packed record
    POPEDX: Byte;
    MOVEAX: Byte;
    SelfPtr: Pointer;
    PUSHEAX: Byte;
    PUSHEDX: Byte;
    JMP: Byte;
    JmpOffset: Integer;
  end;
var
  Callback: TCallbackThunk;
begin
  inherited Create;
  Callback.POPEDX := $5A;
  Callback.MOVEAX := $B8;
  Callback.SelfPtr := Self;
  Callback.PUSHEAX := $50;
  Callback.PUSHEDX := $52;
  Callback.JMP     := $E9;
  Callback.JmpOffset := Integer(@TLanguages.LocalesCallback) - Integer(@Callback.JMP) - 5;
  EnumSystemLocales(TFNLocaleEnumProc(@Callback), LCID_SUPPORTED);
end;

コンストラクターはメンバー関数を EnumSystemLocales コールバックとして使用しようとしますが、これがクラッシュの原因になっているようです。これは、TLanguages.LocalesCallback関数をグローバル スコープにコピーし、それを EnumSystemLocales に渡すと問題なく動作するためです。

構造体には次の Intel x86 アセンブリが含まれており、各項目はオペコードによって指定されます。

pop  edx
mov  eax Self
push eax
push edx
jmp  JmpOffset

トリックがどのように機能するかを説明し、期待どおりに機能しない理由を教えてもらえますか?

4

1 に答える 1