Delphi TLanguages 工具中的访问冲突问题

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

有没有人能解释一下这个技巧是如何工作的并告诉我为什么它不能按预期工作?


请[编辑]以包括实际的错误消息(包括地址),并提供TLanguages.Create;行的一些上下文。那行代码是在你自己的代码中还是其他地方?发布一个没有上下文的单独行通常对除你以外的任何人都没有意义,如果这是它的全部内容,那么你发布的这行代码确实应该导致后续失败。谢谢。 - Ken White
@KenWhite:错误已经存在,但X是变化的(可能取决于堆状态)。此外,上下文不是问题。同样的问题在任何情况下都会发生(包括一个完全空的程序)。这也已经澄清了。 - Orwell
请提供一个简短、自包含、正确(可编译)的示例,因为目前我对你在问题中所断言的情况持有异议。 - David Heffernan
好的,这里给您解释一下。在它失败的机器上强制执行了强制性 DEP。但这很不可能是原因。但我们除了猜测之外不能做更多的事情! - David Heffernan
@Orwell,这个技巧被称为“stdcall方法thunk”,允许将方法指针作为通用函数指针传递,绕过隐式的Self参数。 - OnTheFly
显示剩余3条评论
1个回答

4
这似乎是旧版Delphi的已知问题,与DEP有关,正如我在问题的评论中猜测的那样。很明显,在启用DEP时,RTL中的代码无法正常工作。
这里有一个链接确认了这个理论:http://codecentral.embarcadero.com/Item/23411 虽然该CodeCentral文章包括修复Delphi 5问题的代码,但看起来它也适用于Delphi 7。该修复程序通过hook SysUtils.Languages函数来解决问题。因此,出于明显的原因,请确保始终使用它,而不是自己调用TLanguages.Create。

1
没错,DEP就是问题所在。当将代码分发给大量人群时,会遇到各种随机原因,这真是令人惊讶。 - Orwell
@Orwell,这不是随机的,你的thunk不驻留在可执行内存区域。一旦你传递它的指针进行执行,DEP就会启动。 - OnTheFly
+1 - 神奇的超能力!(楼主本可以创建一个小案例来复现问题!) - Leonardo Herrera

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接