For some reason, trying to create a TLanguages object provided by the SysUtils header by using the singleton or by calling the constructor directly is causing trouble in the wild, where some users report this error (X varies):
Access violation at address X. Write of address X (at address X)
... when the following seemingly innocent line of code is executed:
TLanguages.Create;
To clarify, this is not related to context. I can put this line in any place I like (as the only line of code of an empty program for example), but the problem remains.
The weird part is that this class is part of Delphi's standard headers, which should not fail (right?).
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;
The constructor attempts to use a member function as the EnumSystemLocales callback, which seems to be causing the crashes, because copying the TLanguages.LocalesCallback function to global scope and passing that to EnumSystemLocales works perfectly fine.
The struct contains the following Intel x86 assembly, where each item is given by its opcode:
pop edx
mov eax Self
push eax
push edx
jmp JmpOffset
Can anyone explain how the trick works and tell me why it's not working as expected?
It appears to be a known issue with older Delphi versions, related to DEP, as I guessed in comments to the question. It's clear that the code in the RTL cannot work when DEP is enabled.
Here's a link to confirm the theory: http://codecentral.embarcadero.com/Item/23411
Although that CodeCentral article includes code to fix the problem in Delphi 5, it looks like it will work in Delphi 7 too. The fix works by hooking the SysUtils.Languages
function. So make sure you always use that rather than calling TLanguages.Create
yourself, for obvious reasons.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With