Функция-помощник для тестирования длинных 64-битных адресов на предмет совместимости с Integer. Творческая переработка идей gunsmoker'а и Николая Зверева.
По мотивам:
http://programmingmindstream.blogspot.ru/2016/12/1330-win64.html
http://www.delphinotes.ru/2016/10/win64-2.html
Далее протыкиваем наше приложение или запускаем автоматические тесты. И ловим Range Check'и и AV. Там где Pointer приводится к Integer и Cardinal и наоборот. В прямую сторону Range Check в обратную - скорее всего AV.
Я много чего наловил. И в чужом коде - тоже. В частности в ImageEn. Например в функции _DIBDrawTo. Но об этом в другой раз.
Этот код можно и в релизе оставить. И тренироваться "на пользователях".
У меня вызов функции в тестах вот так вставлен:
По мотивам:
http://programmingmindstream.blogspot.ru/2016/12/1330-win64.html
http://www.delphinotes.ru/2016/10/win64-2.html
unit l3DebugUtils;
interface
procedure l3ReserveMem;
implementation
uses
Windows
;
procedure l3ReserveMem;
{$IfDef Win64}
var
l_P : Pointer;
begin
while true do
begin
l_P := VirtualAlloc(nil, 1024 * 1024, MEM_RESERVE, PAGE_NOACCESS);
// - распределяем по мегабайту, пока не выберем "младшее" адресное пространство (меньше 4Гб).
if (l_P = nil) then
break;
if (NativeUInt(l_P) >= High(Cardinal{Integer})) then
break;
end;//while true
end;
{$Else Some64}
begin
end;
{$EndIf Some64}
end.
Втыкаем вызов l3ReserveMem первой строчкой в dpr и получаем, что все далее распределённые адреса будут больше $FFFFFFFF.Далее протыкиваем наше приложение или запускаем автоматические тесты. И ловим Range Check'и и AV. Там где Pointer приводится к Integer и Cardinal и наоборот. В прямую сторону Range Check в обратную - скорее всего AV.
Я много чего наловил. И в чужом коде - тоже. В частности в ImageEn. Например в функции _DIBDrawTo. Но об этом в другой раз.
Этот код можно и в релизе оставить. И тренироваться "на пользователях".
begin
{$IfDef nsTest}
g_CVSPath := 'w:\common\components\DailyTest';
{$EndIf nsTest}
//#UC START# *4B2A48AA03D4CVSPath*
l3ReserveMem;
//#UC END# *4B2A48AA03D4CVSPath*
TAutoTestsSuite.Register;
try
if KTestRunner.NeedKTestRunner([TtoK, TItsLAW, TArchi2, TtoK64, TtoKT]) then
KTestRunner.RunRegisteredTests
else
if System.IsConsole then
TextTestRunner.RunRegisteredTests
else
GUITestRunner.RunRegisteredTests;
except
on E: Exception do
begin
{$If defined(MTDORB) AND defined(NoKPageTool)}
if TKBridge.Exists then
TKBridge.Instance.Logout;
{$IfEnd}
l3System.Exception2Log(E);
TestsExitCode := 2;
end;//Exception
end;//try..except
{$IfNDef Some64}
if (TestsExitCode <> 0) then
Halt(TestsExitCode);
{$EndIf Some64}
end.
Хм... у меня тоже сначала цикл был с проверкой, очень похожей:
ОтветитьУдалитьif (NativeUInt(l_P) >= High(Cardinal{Integer})) then
break;
Но у меня (на моём ПК) выход из цикла завершался после небольшого кол-ва итераций (иногда даже после первой), а затем, по ходу работы приложения память выделялась в первых двух гигах.
Была ещё мысль подменить менеджер памяти и эту проверку делать в GetMem
Ну. Свою задачу я пока решил. И у меня явно не после первой итерации. Ну и потом - тут же VirtualAlloc, а не GetMem. Да ещё и noAccess. Что тоже полезно. Гарантирует AV. Если я правильно понимаю.
УдалитьДля "гарантии" можно насильно сделать High(Cardinal) div Size итераций.
УдалитьГлавная идея была не в этом, а именно в использовании VirtualAlloc, а не GetMem.
Да, что-то я совсем не внимательно прочитал код.
ОтветитьУдалитьОхохох - робята, вот это вы меня в грусть ввергли.
ОтветитьУдалитьУ меня падение за падением - ничего себе работки то поприбавилось.
Но за идею - респект.
;) ну я своё за пару дней разгрёб
УдалитьСпасибо за модуль! Буквально спас проект на 64х.
ОтветитьУдалитьПожалуйста.
УдалитьХоть кому-то что-то полезно.
В FastMM есть опция AlwaysAllocateTopDown (включена по умолчанию).
ОтветитьУдалитьТакже в 32-битных Windows можно включить Allocate Top Down для тестирования > 2 Гб: https://docs.microsoft.com/en-us/windows/win32/memory/4-gigabyte-tuning (см. про ключ реестра AllocationPreference).