Почему раздел меню доработан слишком рано?

Я тестировал свое приложение с включенными FastMM и FullDebugMode, так как у меня были проблемы с завершением работы.

После решения кучи моих собственных проблем FastMM начал жаловаться на вызов виртуального метода для освобожденного объекта в TPopupList. Я пытался переместить блок меню как можно раньше при использовании, чтобы он был доработан последним, но это не помогло. Это реальная проблема, баг в vcl или ложное срабатывание FastMM?

Вот полный отчет FastMM:

FastMM has detected an attempt to call a virtual method on a freed object. An access violation will now be raised in order to abort the current operation.

Freed object class: TPopupList

Virtual method: Offset +16

Virtual method address: 4714E4

The allocation number was: 220

The object was allocated by thread 0x1CC0, and the stack trace (return addresses) at the time was:
403216 [sys\system.pas][System][System.@GetMem][2654]
404A4F [sys\system.pas][System][System.TObject.NewInstance][8807]
404E16 [sys\system.pas][System][System.@ClassCreate][9472]
404A84 [sys\system.pas][System][System.TObject.Create][8822]
7F2602 [Menus.pas][Menus][Menus.Menus][4223]
40570F [sys\system.pas][System][System.InitUnits][11397]
405777 [sys\system.pas][System][System.@StartExe][11462]
40844F [SysInit.pas][SysInit][SysInit.@InitExe][663]
7F6368 [PCCSServer.dpr][PCCSServer][PCCSServer.PCCSServer][148]
7C90DCBA [ZwSetInformationThread]
7C817077 [Unknown function at RegisterWaitForInputIdle]

The object was subsequently freed by thread 0x1CC0, and the stack trace (return addresses) at the time was:
403232 [sys\system.pas][System][System.@FreeMem][2699]
404A6D [sys\system.pas][System][System.TObject.FreeInstance][8813]
404E61 [sys\system.pas][System][System.@ClassDestroy][9513]
428D15 [common\Classes.pas][Classes][Classes.TList.Destroy][2914]
404AB3 [sys\system.pas][System][System.TObject.Free][8832]
472091 [Menus.pas][Menus][Menus.Finalization][4228]
4056A7 [sys\system.pas][System][System.FinalizeUnits][11256]
4056BF [sys\system.pas][System][System.FinalizeUnits][11261]
7C9032A8 [RtlConvertUlongToLargeInteger]
7C90327A [RtlConvertUlongToLargeInteger]
7C92AA0F [Unknown function at towlower]

The current thread ID is 0x1CC0, and the stack trace (return addresses) leading to this error is:
4714B8 [Menus.pas][Menus][Menus.TPopupList.MainWndProc][3779]
435BB2 [common\Classes.pas][Classes][Classes.StdWndProc][11583]
7E418734 [Unknown function at GetDC]
7E418816 [Unknown function at GetDC]
7E428EA0 [Unknown function at DefWindowProcW]
7E428EEC [Unknown function at DefWindowProcW]
7C90E473 [KiUserCallbackDispatcher]
7E42B1A8 [DestroyWindow]
47CE31 [Controls.pas][Controls][Controls.TWinControl.DestroyWindowHandle][6857]
493BE4 [Forms.pas][Forms][Forms.TCustomForm.DestroyWindowHandle][4564]
4906D9 [Forms.pas][Forms][Forms.TCustomForm.Destroy][2929]

Current memory dump of 256 bytes starting at pointer address 7FF9CFF0:
2C FE 82 00 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 80 C4 A3 2D 0C 00 00 00 00 B1 D0 F9 7F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C0 00 00 00 16 32 40 00 9D 5B 40 00 C8 5B 40 00
CE 82 40 00 3C 40 91 7C B0 B1 94 7C 0A 77 92 7C 84 77 92 7C 7C F0 96 7C 94 B3 94 7C 84 77 92 7C
C0 1C 00 00 32 32 40 00 12 5B 40 00 EF 69 40 00 BA 20 47 00 A7 56 40 00 BF 56 40 00 A8 32 90 7C
7A 32 90 7C 0F AA 92 7C 0A 77 92 7C 84 77 92 7C C0 1C 00 00 0E 00 00 00 00 00 00 00 C7 35 65 59
2C FE 82 00 80 80 80 80 80 80 80 80 80 80 38 CA 9A A6 80 80 80 80 80 80 00 00 00 00 51 D1 F9 7F
00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 C1 00 00 00 16 32 40 00 9D 5B 40 00 C8 5B 40 00
CE 82 40 00 3C 40 91 7C B0 B1 94 7C 0A 77 92 7C 84 77 92 7C 7C F0 96 7C 94 B3 94 7C 84 77 92 7C
,  þ  ‚  .  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  €  Ä  £  -  .  .  .  .  .  ±  Ð  ù  
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  À  .  .  .  .  2  @  .    [  @  .  È  [  @  .
Î  ‚  @  .  <  @  ‘  |  °  ±  ”  |  .  w  ’  |  „  w  ’  |  |  ð  –  |  ”  ³  ”  |  „  w  ’  |
À  .  .  .  2  2  @  .  .  [  @  .  ï  i  @  .  º     G  .  §  V  @  .  ¿  V  @  .  ¨  2    |
z  2    |  .  ª  ’  |  .  w  ’  |  „  w  ’  |  À  .  .  .  .  .  .  .  .  .  .  .  Ç  5  e  Y
,  þ  ‚  .  €  €  €  €  €  €  €  €  €  €  8  Ê  š  ¦  €  €  €  €  €  €  .  .  .  .  Q  Ñ  ù  
.  .  .  .  .  .  .  .  .  .  .  .  .  .  .  .  Á  .  .  .  .  2  @  .    [  @  .  È  [  @  .
Î  ‚  @  .  <  @  ‘  |  °  ±  ”  |  .  w  ’  |  „  w  ’  |  |  ð  –  |  ”  ³  ”  |  „  w  ’  |

Я использую Delphi 2007 и FastMM 4.97.

Edit1: Я думаю, что основная проблема здесь в том, почему Classes.StdWndProc вызывает Menus.TPopupList? Копание стека вызовов внутри отладчика показывает, что System.FinalizeUnit вызывается три раза, затем он переходит к SysUtils.ShowException, который пытается отобразить MessageBox, и после нескольких вызовов user32.dll мы переходим к classes.StdWndProc.

Edit2: у меня была проблема с интерфейсами, после ее устранения проблема исчезла. Объект с интерфейсом был освобожден, но ссылка была выпущена позже. Когда интерфейс был выпущен, произошло исключение, которое я изначально как-то проигнорировал. Освобождение интерфейса, вероятно, повредило что-то, что вызвало все другие проблемы.


person Harriv    schedule 26.03.2010    source источник


Ответы (5)


Такая ситуация может произойти, когда модуль завершается после другого модуля, от которого он косвенно зависит.

Для примера возьмем следующий блок:

unit Unit1;
interface
uses
  Contnrs;

var
  ItemHolder : TObjectList;

implementation

initialization
  ItemHolder := TObjectList.Create(True);
finalization
  ItemHolder.Free;
end.

Этот блок напрямую зависит только от Contnrs. По этой причине delphi гарантирует, что этот модуль будет завершен раньше, чем Contnrs. Если ObjectList содержит TForms, Delphi не гарантирует, что Unit1 будет завершен до unit Forms. Если при закрытии приложения остались какие-то формы, TObjectList (поскольку он владеет объектом) освободит содержащиеся в нем элементы (вызовите TForm.Free). Но поскольку Unit1 не зависит от TForm, возможно, что форма модуля уже завершена и TForm.Destroy больше не находится в памяти.

Вот почему вам нужно очень внимательно относиться к тому, что вы делаете в разделах завершения.

Я не уверен, что это источник вашей проблемы, но сначала я посмотрю туда.

person Ken Bourassa    schedule 26.03.2010

Я видел такие проблемы с Delphi 2007 раньше. Иногда компилятор запутывается и генерирует неправильный порядок инициализации или финализации. К сожалению, мне так и не удалось создать воспроизводимый тестовый пример для отправки людям из CodeGear / Embarcadero.

Когда бы это ни происходило, помогала полная перестройка.

person gabr    schedule 26.03.2010

Убедитесь, что FastMM4 является ПЕРВОЙ строкой в ​​разделе uses вашего файла проекта (проект | Просмотреть исходный код). Если его там нет, то добавьте его.

person skamradt    schedule 26.03.2010

Похоже, одна из ваших форм уничтожается после завершения работы над Menus.pas. Если в вашей форме есть меню, вероятно, в разделе интерфейса должны быть меню «Меню», что должно сделать это невозможным.

Единственный раз, когда я видел такие проблемы (без каламбура), это при использовании пакетов. Возможно, вы используете DPK с плагином, который добавляет всплывающее меню или пункты меню в вашу программу? Завершение пакета может сделать с вашей программой некоторые странные вещи, если вы не будете осторожны.

В любом случае решение, вероятно, состоит в том, чтобы избавиться от меню самостоятельно до того, как menus.pas завершит работу. Когда пришло время завершить работу программы, вызовите Free во всплывающем меню и посмотрите, решит ли это проблему.

person Mason Wheeler    schedule 26.03.2010
comment
Да, именно в этом был смысл вопроса, почему menus.pas дорабатывается слишком рано, до того, как будут завершены все формы. Насчет посылок не уверен, думаю, ничего такого быть не должно, но надо будет проверить. - person Harriv; 26.03.2010

Обновление: это только частичное решение

Решение: в основной форме вашего приложения напишите

finalization
  FreeAndNil(PopupList);
end.

этот бесплатный PopupList и установлен в ноль, поэтому PopupList.Free в menus.pas будет в порядке.

person netcodecz    schedule 06.04.2011