Интересное переполнение стека! ошибка компилятора?

Интересно, нашел ли я ошибку компилятора? я удалял какой-то старый код из своего приложения, и теперь я получаю stackoverflow в "begin" (см. код и дизассемблирование ниже).

procedure TfraNewRTMDisplay.ShowMeasurement;
var
 iDummy, iDummy2, iDummy3:integer;
begin // Qaru BEFORE MY CODE STARTS
 iDummy:=0;
 iDummy2:=0;
 case iDummy2 of
 1:
 case iDummy of
 1:m_SelectedRTMMenuData.ChannelMeasSet.MeasKV.ClearMeasurementData;
 2:m_SelectedRTMMenuData.ChannelMeasSet.MeasKV.ClearMeasurementData;
 end;
 end; 
end;
NewRTMDisplay.pas.1601: begin
00983BF8 55 push ***
00983BF9 8BEC mov ***,esp
00983BFB B9D4E40400 mov ecx,$0004e4d4
00983C00 6A00 push $00 // Qaru loop
00983C02 6A00 push $00 // Qaru loop 
00983C04 49 dec ecx // Qaru loop 
00983C05 75F9 jnz $00983c00 // Qaru loop
00983C07 56 push esi
00983C08 57 push edi
00983C09 8945FC mov [***-$04],eax
00983C0C 8D856005FFFF lea eax,[***-$0000faa0]
00983C12 8B153C789A00 mov edx,[$009a783c]
00983C18 E88B35A8FF call @InitializeRecord
00983C1D 8D85D00AFEFF lea eax,[***-$0001f530]
00983C23 8B153C789A00 mov edx,[$009a783c]
00983C29 E87A35A8FF call @InitializeRecord
00983C2E 33C0 xor eax,eax
00983C30 55 push ***
00983C31 68F73C9800 push $00983cf7
00983C36 64FF30 push dword ptr fs:[eax]
00983C39 648920 mov fs:[eax],esp
NewRTMDisplay.pas.1602: iDummy:=0;
00983C3C 33C0 xor eax,eax
00983C3E 8945F8 mov [***-$08],eax
NewRTMDisplay.pas.1603: iDummy2:=0;
00983C41 33C0 xor eax,eax
00983C43 8945F4 mov [***-$0c],eax
NewRTMDisplay.pas.1605: case iDummy2 of
00983C46 8B45F4 mov eax,[***-$0c]
00983C49 48 dec eax
00983C4A 7571 jnz $00983cbd
NewRTMDisplay.pas.1607: case iDummy of
00983C4C 8B45F8 mov eax,[***-$08]
00983C4F 48 dec eax
00983C50 7405 jz $00983c57
00983C52 48 dec eax
00983C53 7436 jz $00983c8b
00983C55 **** jmp $00983cbd
NewRTMDisplay.pas.1608: 1:m_SelectedRTMMenuData.ChannelMeasSet.MeasKV.ClearMeasurementData;
00983C57 8D951872EBFF lea edx,[***-$00148de8]
00983C5D 8B45FC mov eax,[***-$04]
00983C60 8B80F0020000 mov eax,[eax+$000002f0]
00983C66 E895DBE9FF call TRTMMenuData.ChannelMeasSet
00983C6B 8DB52072EBFF lea esi,[***-$00148de0]
00983C71 8DBD6005FFFF lea edi,[***-$0000faa0]
00983C77 B9A43E0000 mov ecx,$00003ea4
00983C7C F3A5 rep movsd 
00983C7E 8D856005FFFF lea eax,[***-$0000faa0]
00983C84 E81B3F0200 call TDeviceMeas.ClearMeasurementData
00983C89 **** jmp $00983cbd
NewRTMDisplay.pas.1609: 2:m_SelectedRTMMenuData.ChannelMeasSet.MeasKV.ClearMeasurementData;
00983C8B 8D9560D9D8FF lea edx,[***-$002726a0]
00983C91 8B45FC mov eax,[***-$04]
00983C94 8B80F0020000 mov eax,[eax+$000002f0]
00983C9A E861DBE9FF call TRTMMenuData.ChannelMeasSet
00983C9F 8DB568D9D8FF lea esi,[***-$00272698]
00983CA5 8DBDD00AFEFF lea edi,[***-$0001f530]
00983CAB B9A43E0000 mov ecx,$00003ea4
00983CB0 F3A5 rep movsd 
00983CB2 8D85D00AFEFF lea eax,[***-$0001f530]
00983CB8 E8E73E0200 call TDeviceMeas.ClearMeasurementData
NewRTMDisplay.pas.1612: end;

любые идеи?

Благодарю вас! Т. пл

5 ответов

Юлий прав: буфер 320 КБ, скорее всего, является массивом [20] того, что возвращается ChannelMeasSet, - на основе размера цикла rep movsd.

Похоже, у вас есть код, который возвращает очень большую структуру данных по значению, а не просто ссылку на нее. Помимо проблемы, это может быть очень неэффективным.


Этот код выглядит следующим образом:

m_SelectedRTMMenuData.ChannelMeasSet.MeasKV.ClearMeasurementData;

Похоже, что ChannelMeasSet - это огромная структура данных, которую компилятор пытается скопировать в ваш стек по какой-то причине. Я не уверен, почему компилятор попытается это сделать, не увидев остальную часть объявления объекта. Кроме того, компилятор выделил две отдельные области временного хранения в стеке, по одной для каждой строки, где вы вызываете это (хотя только один будет использоваться в любой момент времени).

У вас есть как минимум два возможных решения:

  • Сделайте стек больше. Возможно, для этого есть директива Delphi.
  • Исправьте свои структуры данных, чтобы компилятор не захотел копировать огромные временные объекты.


Что-то создающее буфер 320 КБ. У вас есть какие-либо из этих объектов в этой цепочке вызовов, которые имеют статически распределенный огромный массив внутри них? Возможно, он пытается поместить один из возвращенных объектов в стек.


глупый сайт; он автоматически обновляется, уничтожая мой ответ. ChannelMeasSet - это рекорд, который удивил меня тем, что он занимает 1,2 МБ!

m_SelectedRTMMenuData a small object
ChannelMeasSet a record
MeasKV a record with method ClearMeasurementData( );

Странно, приложение только что удалило кучу старого кода. я никогда не видел, как этот.

Я опубликую этот комментарий, чтобы он не уничтожился, прежде чем я смогу закончить!

Благодарю вас за помощь!


Благодарю вас за ваши предложения! вот стек вызовов (из delphi 2009).

NewRTMDisplay.TfraNewRTMDisplay.ShowMeasurement
NewRTMDisplay.TfraNewRTMDisplay.DetectorSelectionChange($46552D0,drmOneAtATime)
NewRTMDisplay.TfraNewRTMDisplay.pumOnDetectorSelectionChange($46129E0)
Menus.TMenuItem.Click
Menus.TMenu.DispatchCommand(???)
Menus.TPopupList.WndProc((273, 386, 0, 0, 386, 0, 0, 0, 0, 0))
Menus.TPopupList.MainWndProc(???)
Classes.StdWndProc(15403740,273,386,0)
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e4189cd ; C:\WINDOWS\system32\USER32.dll
:7e418a10 USER32.DispatchMessageW + 0xf
Forms.TApplication.ProcessMessage(???)
:0051e31c TApplication.ProcessMessage + $F8

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

По общему признанию, существуют несколько умеренно больших структур. я сомневаюсь, что они где-то рядом с этим большим, но я скоро вернусь к вам.

licensed under cc by-sa 3.0 with attribution.