有趣的堆栈问题?

发布于 2024-09-06 13:11:48 字数 6423 浏览 5 评论 0原文

我的 delphi 2009 应用程序中有一个有趣的问题。当在调试器中运行时,我在子例程的 Begin 关键字和第一个语句之间得到一个 AV。我相信那是它设置局部变量的时候。这是调试器中显示的信息:

uDeviceModule.pas.940: begin  // _GetMeasurementsForChannel
00AF24C8 55               push ebp
00AF24C9 8BEC             mov ebp,esp
00AF24CB 51               push ecx
00AF24CC B9E9A90100       mov ecx,$0001a9e9    // isn't this a lot for the stack?

// error happens in here
00AF24D1 6A00             push $00
00AF24D3 6A00             push $00
00AF24D5 49               dec ecx
00AF24D6 75F9             jnz $00af24d1

00AF24D8 874DFC           xchg [ebp-$04],ecx
00AF24DB 53               push ebx
00AF24DC 894DF4           mov [ebp-$0c],ecx
00AF24DF 8955FC           mov [ebp-$04],edx
00AF24E2 8945F8           mov [ebp-$08],eax
00AF24E5 33C0             xor eax,eax
00AF24E7 55               push ebp
00AF24E8 687D2FAF00       push $00af2f7d
00AF24ED 64FF30           push dword ptr fs:[eax]
00AF24F0 648920           mov fs:[eax],esp
uDeviceModule.pas.941: SelectChannel(eChannelNum);       // first statement

这是此嵌套子例程的简化版本(见下文)。

procedure TDeviceModule.GetMeasurements(ExpInfo:TExpInfo;
  _DisplayList:TMeasDisplayListAncestor; eExposureStatus:TExposureStatus;
  bActiveErrorEnabled:boolean);

  procedure _GetMeasurementsForChannel(_DisplayList:TObjectList;
    eChannelNum:TDeviceChannelNum; eExposureStatus:TMyEnum;
    bActiveErrorEnabled:boolean);
  var
    // these are all objects (not records)
    selChannel:TDeviceChannel;
    det:TDeviceDetector;
    shoKVMeas:TStoMeasurement;
  begin  // ********************* error happens on this line
    SelectChannel(eChannelNum);

    _GetMeasurement(ExpInfo, _DisplayList, eChannelNum, eExposureStatus, ctdVal1);
    _GetMeasurement(ExpInfo, _DisplayList, eChannelNum, eExposureStatus, ctdVal2);
    _GetMeasurement(ExpInfo, _DisplayList, eChannelNum, eExposureStatus, ctdVal3);
  end;  // _GetMeasurementsForChannel

begin
  // blah blah blah

      _GetMeasurementsForChannel(_DisplayList,
                                 eChannelNum,
                                 eExposureStatus,
                                 bActiveErrorEnabled);

  // blah blah blah
end;

它是一个单线程应用程序。

你建议我如何找到这个问题的原因?我的第一个想法是:

1)增加最大堆栈大小——我做到了,但它没有改变任何东西。现在是 160000 美元(1441792),但在此之前我认为是 150000 美元。 2)这个对象仍然有效吗?似乎......它正确响应 ClassName 方法 & FastMM 不会警告我任何问题。

有趣的是,堆栈跟踪没有提及引起问题的例程。

:7e42b35c USER32.MoveWindow + 0xbe
:7e4565b7 USER32.GetRawInputDeviceInfoW + 0x5f
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
ActnMenus.CallWindowHook(???,0,$31104)
:7e42b372 USER32.MoveWindow + 0xd4
:7e4565b7 USER32.GetRawInputDeviceInfoW + 0x5f
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:007b882d aqDockingWndProcHook + $1D
:7e42b372 USER32.MoveWindow + 0xd4
:7e4565b7 USER32.GetRawInputDeviceInfoW + 0x5f
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
Controls.TWinControl.DefaultHandler(???)
:0050fac8 TWinControl.DefaultHandler + $DC
:0050b4b9 TControl.WndProc + $2D5
:0050f9cc TWinControl.WndProc + $518
:0050f0e3 TWinControl.MainWndProc + $2F
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
:0050fac8 TWinControl.DefaultHandler + $DC
:0050f9cc TWinControl.WndProc + $518
:0050f0e3 TWinControl.MainWndProc + $2F
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
:0050fac8 TWinControl.DefaultHandler + $DC
:0050f9cc TWinControl.WndProc + $518
:0050f0e3 TWinControl.MainWndProc + $2F
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
:0050fac8 TWinControl.DefaultHandler + $DC
:0050f9cc TWinControl.WndProc + $518
:0065279d TcxControl.WndProc + $121
:0070b38d TcxCustomGrid.WndProc + $5
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
:0050fac8 TWinControl.DefaultHandler + $DC
:0050f9cc TWinControl.WndProc + $518
:0065279d TcxControl.WndProc + $121
:0075bbc4 TcxGridSite.WndProc + $20
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:0044c91e HandleException + $22A
:004539af InterceptAHandleExcept + $3F
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e4189cd ; C:\WINDOWS\system32\USER32.dll
:7e418a10 USER32.DispatchMessageW + 0xf

这对我来说表明问题是某种堆栈溢出——攻击消息处理所使用的东西。

建议???谢谢你!

i have an interesting problem in my delphi 2009 app. when run in the debugger, i get an AV between the subroutine's Begin keyword and the first statement. i believe that's when it's setting up local variables. here's the information shown in the debugger:

uDeviceModule.pas.940: begin  // _GetMeasurementsForChannel
00AF24C8 55               push ebp
00AF24C9 8BEC             mov ebp,esp
00AF24CB 51               push ecx
00AF24CC B9E9A90100       mov ecx,$0001a9e9    // isn't this a lot for the stack?

// error happens in here
00AF24D1 6A00             push $00
00AF24D3 6A00             push $00
00AF24D5 49               dec ecx
00AF24D6 75F9             jnz $00af24d1

00AF24D8 874DFC           xchg [ebp-$04],ecx
00AF24DB 53               push ebx
00AF24DC 894DF4           mov [ebp-$0c],ecx
00AF24DF 8955FC           mov [ebp-$04],edx
00AF24E2 8945F8           mov [ebp-$08],eax
00AF24E5 33C0             xor eax,eax
00AF24E7 55               push ebp
00AF24E8 687D2FAF00       push $00af2f7d
00AF24ED 64FF30           push dword ptr fs:[eax]
00AF24F0 648920           mov fs:[eax],esp
uDeviceModule.pas.941: SelectChannel(eChannelNum);       // first statement

this is a simplified version of this nested subroutine (see below).

procedure TDeviceModule.GetMeasurements(ExpInfo:TExpInfo;
  _DisplayList:TMeasDisplayListAncestor; eExposureStatus:TExposureStatus;
  bActiveErrorEnabled:boolean);

  procedure _GetMeasurementsForChannel(_DisplayList:TObjectList;
    eChannelNum:TDeviceChannelNum; eExposureStatus:TMyEnum;
    bActiveErrorEnabled:boolean);
  var
    // these are all objects (not records)
    selChannel:TDeviceChannel;
    det:TDeviceDetector;
    shoKVMeas:TStoMeasurement;
  begin  // ********************* error happens on this line
    SelectChannel(eChannelNum);

    _GetMeasurement(ExpInfo, _DisplayList, eChannelNum, eExposureStatus, ctdVal1);
    _GetMeasurement(ExpInfo, _DisplayList, eChannelNum, eExposureStatus, ctdVal2);
    _GetMeasurement(ExpInfo, _DisplayList, eChannelNum, eExposureStatus, ctdVal3);
  end;  // _GetMeasurementsForChannel

begin
  // blah blah blah

      _GetMeasurementsForChannel(_DisplayList,
                                 eChannelNum,
                                 eExposureStatus,
                                 bActiveErrorEnabled);

  // blah blah blah
end;

it is a single-threaded app.

how would you suggest i go about finding the cause of this problem? my first thoughts were:

1) increase max stack size--i did but it didn't change anything. now it's $160000 (1441792) but before this i think it was $150000.
2) is this object still valid? seems to be...it responds to the ClassName method correctly & FastMM doesn't warn me about any problems.

interestingly, the stack trace makes no mention of the routine where the problem is caused.

:7e42b35c USER32.MoveWindow + 0xbe
:7e4565b7 USER32.GetRawInputDeviceInfoW + 0x5f
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
ActnMenus.CallWindowHook(???,0,$31104)
:7e42b372 USER32.MoveWindow + 0xd4
:7e4565b7 USER32.GetRawInputDeviceInfoW + 0x5f
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:007b882d aqDockingWndProcHook + $1D
:7e42b372 USER32.MoveWindow + 0xd4
:7e4565b7 USER32.GetRawInputDeviceInfoW + 0x5f
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
Controls.TWinControl.DefaultHandler(???)
:0050fac8 TWinControl.DefaultHandler + $DC
:0050b4b9 TControl.WndProc + $2D5
:0050f9cc TWinControl.WndProc + $518
:0050f0e3 TWinControl.MainWndProc + $2F
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
:0050fac8 TWinControl.DefaultHandler + $DC
:0050f9cc TWinControl.WndProc + $518
:0050f0e3 TWinControl.MainWndProc + $2F
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
:0050fac8 TWinControl.DefaultHandler + $DC
:0050f9cc TWinControl.WndProc + $518
:0050f0e3 TWinControl.MainWndProc + $2F
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
:0050fac8 TWinControl.DefaultHandler + $DC
:0050f9cc TWinControl.WndProc + $518
:0065279d TcxControl.WndProc + $121
:0070b38d TcxCustomGrid.WndProc + $5
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:7e428dd9 USER32.DefWindowProcW + 0xb9
:7e428d77 USER32.DefWindowProcW + 0x57
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e42a013 USER32.IsWindowUnicode + 0xa1
:7e42a039 USER32.CallWindowProcW + 0x1b
:0050fac8 TWinControl.DefaultHandler + $DC
:0050f9cc TWinControl.WndProc + $518
:0065279d TcxControl.WndProc + $121
:0075bbc4 TcxGridSite.WndProc + $20
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e428ea0 ; C:\WINDOWS\system32\USER32.dll
:7e428eec ; C:\WINDOWS\system32\USER32.dll
:7c90e473 ntdll.KiUserCallbackDispatcher + 0x13
:0044c91e HandleException + $22A
:004539af InterceptAHandleExcept + $3F
:0048874e StdWndProc + $16
:7e418734 USER32.GetDC + 0x6d
:7e418816 ; C:\WINDOWS\system32\USER32.dll
:7e4189cd ; C:\WINDOWS\system32\USER32.dll
:7e418a10 USER32.DispatchMessageW + 0xf

this suggests to me that the problem is stack overrun of some kind--bashing things used by message handling.

suggestions??? THANK YOU!

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(7

小兔几 2024-09-13 13:11:48

我强烈怀疑涉及的 TDeviceModule 引用无效。在以某种方式进入方法主体之前,您不会总是看到对错误对象引用调用方法的任何不良影响,除非该方法是虚拟的,在这种情况下,方法本身的调用通常(总是?)会产生 AV。

I strongly suspect that the TDeviceModule reference involved is invalid. You won't always see any ill effects of calling a method on a bad object reference until some way into the method body unless the method is virtual in which case the invocation of the method itself will typically (always?) yield an AV.

亢潮 2024-09-13 13:11:48

根据您的评论(“错误发生在这里”),您的错误会在设置堆栈空间的循环中弹出,全部 212 Kb!它与您传递给过程的参数绝对无关,也与您作为参数传递的对象的可行性无关(那里没有 CALL,它只是一个循环到 PUSH $00 的 JNZ直到 DEC ECX 操作标记 ZERO 标志,即 $1a9e9 次)。

由于您正在处理一个使用 212Kb 堆栈空间的过程,也许您应该尝试增加更多堆栈空间!更好的是,弄清楚为什么您的过程使用了这么多空间,并弄清楚其他过程是否处于相同的情况(注意用作局部变量的大记录)。

From your comment ("error happens here") your error pops up in the loop that sets up stack space, all 212 Kb of it! It has absolutely nothing to do with the parameters you're passing to the procedure and nothing to do with the viability of the object you're passing as a parameter (there's no CALL over there, it's just an JNZ that loops to the PUSH $00 thing until the DEC ECX operation marks the ZERO flag, that is, $1a9e9 times).

Since you're dealing with a procedure that uses 212Kb of stack space maybe you should try increasing the stack space by a lot more! Even better, figure out why your procedure is using up that much space and figure out if other procedures are in the same situation (look out for large Records used as local variables).

任性一次 2024-09-13 13:11:48

看到这个问题: Guard page excepts in Delphi?

通常,你应该得到堆栈溢出异常,当你的堆栈用完时。但是如果你的保护页面被其他人触及并且异常在没有扩展堆栈的情况下被默默地吃掉 - 那么当你扩展堆栈时你的代码将因 AV 崩溃。

这正是您的代码中发生的情况:扩展堆栈并获得 AV。该汇编器周期旨在触摸堆栈以通过保护页触发堆栈扩展。由于 guarg 页面消失了,但是堆栈没有扩展 - 你在这里得到了简单的 AV。

请注意,增加堆栈大小不会有帮助,因为堆栈根本不会增长。

你需要找到谁在玩你的筹码。

See this question: Guard page exceptions in Delphi?

Normally, you should get stack overflow exception, when you're running out of your stack. But if your guard page was touched by someone else and exception was eaten silently without expanding stack - then your code will crash with AV when you will expand your stack.

This isexactly what happening in your code: you expand stack and you got the AV. This assembler cycle is designed to touch stack to trigger stack expansion by guard page. Since guarg page is gone, but stack was not expanded - you got simple AV here.

Note, that increasing stack size will not help, since stack doesn't grow at all.

You need to find who plays with your stack.

空宴 2024-09-13 13:11:48

我会注释掉这 3 个变量中的每一个,然后一次取消注释一个,看看其中是否有某个特定的变量发生了爆炸。
如果是这样,您的问题就减少了 2/3。

I'd comment out each of the 3 variables, then un-comment one at a time to see if any particular one of them is blowing up.
If so, you've just cut your problem by 2/3.

零時差 2024-09-13 13:11:48

一种可能性是 3 个局部变量(堆栈变量)的增长超出预期。我想如果对象在另一个 BPL 中包含的单元中声明并且未正确重建(即您的程序认为它比实际大小小),则可能会发生这种情况。
无论是什么原因,您都可以进行实验并查明是否发生了这种情况。
将“缓冲区”变量放在 3 个变量之间和之后。

ex: 
  var 
    selChannel:TDeviceChannel; 
    Buff1 : array[1..1024] of AnsiChar;
    det:TDeviceDetector; 
    Buff2 : array[1..1024] of AnsiChar;
    shoKVMeas:TStoMeasurement; 
    Buff3 : array[1..1024] of AnsiChar;

这应该为您做两件事。 1)它应该阻止A/V,假设1024就足够了。 2)通过检查数组,您应该能够看到是否出现垃圾。这表明它们正在被上面的声明覆盖。

One possibility would be that the 3 local variables (stack variables) are growing larger than expected. I suppose this could happen if the objects are declared in a unit that is contained in another BPL and it's not rebuilt correctly (i.e. your program thinks it's smaller than it really is).
Whatever the reason, you can experiment and find out if that's happening.
Place "buffer" variables between and after your 3 vars.

ex: 
  var 
    selChannel:TDeviceChannel; 
    Buff1 : array[1..1024] of AnsiChar;
    det:TDeviceDetector; 
    Buff2 : array[1..1024] of AnsiChar;
    shoKVMeas:TStoMeasurement; 
    Buff3 : array[1..1024] of AnsiChar;

This should do two things for you. 1) it should prevent the A/V, assuming that 1024 is enough. 2) by examining the arrays, you should be able to see if garbage appears. That would indicate that they're being overwritten by the declaration directly above.

望她远 2024-09-13 13:11:48

这是我学到的:

通过锻炼这个物体,我发现它是健康的。

通过将东西转储到堆栈上,我确定它确实耗尽了堆栈空间。

procedure TDeviceModule.Validate;
const
  icTestSize=400000;
var
  i:integer;
begin
  // ask the object stuff to try to see if it's healthy

  SelectChannel(dcCh1);

  ClassName;

  for eChannelNum:=low(TDeviceChannelNum) to high(TDeviceChannelNum) do
    if HasChannel(eChannelNum) then
      m_aChannels[eChannelNum].Validate;

  // exercise the stack to see if loading on extra stuff is a problem...it is

  i:=0;
  while i<icTestSize do
    begin
      asm
        push 00
      end;
      inc(i);
    end;

  i:=0;
  while i<icTestSize do
    begin
      asm
        pop ecx
      end;
      inc(i);
    end;
end;

有一些嵌套函数(它的使用和声明都不是问题的一部分,因为我没有意识到它们在多大程度上是问题的一部分)返回了一条记录,我称之为 TBigRecord...它是 32 KB 。不仅如此,它还被使用了很多次。

procedure TDeviceModule.GetMeasurements(blah blah blah);

  function _DoSomething1(blah blah blah):TBigRecord;
  begin
  end;

  function _DoSomething2(blah blah blah):TBigRecord;
  begin
  end;

  function _DoSomething3(blah blah blah):TBigRecord;
  begin
  end;

begin
  _DoSomething1(blah blah blah);
  _DoSomething2(blah blah blah);
  _DoSomething3(blah blah blah);
end;

每次我使用它时(即使我不使用结果),我都会为结果值分配堆栈空间。

我现在使用的解决方案是将这些函数更改为过程,因为我无论如何都没有使用返回值。

我增加了堆栈空间,但不足以防止这个问题。

在这种情况下我可以期望报告堆栈溢出吗?

感谢大家的宝贵帮助!这个问题让我很担心...

here's what i learned:

by exercising the object, i found it was healthy.

by dumping stuff on the stack i determined it really was running out of stack space.

procedure TDeviceModule.Validate;
const
  icTestSize=400000;
var
  i:integer;
begin
  // ask the object stuff to try to see if it's healthy

  SelectChannel(dcCh1);

  ClassName;

  for eChannelNum:=low(TDeviceChannelNum) to high(TDeviceChannelNum) do
    if HasChannel(eChannelNum) then
      m_aChannels[eChannelNum].Validate;

  // exercise the stack to see if loading on extra stuff is a problem...it is

  i:=0;
  while i<icTestSize do
    begin
      asm
        push 00
      end;
      inc(i);
    end;

  i:=0;
  while i<icTestSize do
    begin
      asm
        pop ecx
      end;
      inc(i);
    end;
end;

there were a few nested functions (neither it's use nor it's declaration were part of the question because i didn't realize how much they were a part of the problem) who returned a record i'll call TBigRecord...it is 32 KB. not just that but it was used quite a few times.

procedure TDeviceModule.GetMeasurements(blah blah blah);

  function _DoSomething1(blah blah blah):TBigRecord;
  begin
  end;

  function _DoSomething2(blah blah blah):TBigRecord;
  begin
  end;

  function _DoSomething3(blah blah blah):TBigRecord;
  begin
  end;

begin
  _DoSomething1(blah blah blah);
  _DoSomething2(blah blah blah);
  _DoSomething3(blah blah blah);
end;

each time i use it (and even if i don't use the result), i get stack space allocated for the result value.

the solution i used for now was to change those functions to procedures since i wasn't using the return value anyway.

i had increased the stack space but not enough to prevent this problem.

can i expect stack overflow to be reported in such a case?

thank you all for your valuable assistance! this problem had me worried...

淡写薰衣草的香 2024-09-13 13:11:48

抱歉,过于简单化了,但是...

_DisplayList:TMeasDisplayListAncestor 和 _DisplayList: TObjectList 同时在范围内。

两个不同类型的 eExposureStatus 和两个布尔值的 bActiveErrorEnabled 也是如此。

当您在本地过程中调用 _GetMeasurement(ExpInfo, _DisplayList, eChannelNum, eExposureStatus, ctdVal1) 时,它使用哪个变量和类型? TobjectList 或 TTMeasDisplayListAncestor ?

除非我比我想象的更醉......:)

Sorry to be simplistic but...

_DisplayList:TMeasDisplayListAncestor AND _DisplayList: TObjectList are both in scope simultaneously.

So are two eExposureStatus of differing types and two bActiveErrorEnabled of Boolean.

when you call _GetMeasurement(ExpInfo, _DisplayList, eChannelNum, eExposureStatus, ctdVal1) in the local procedure which variable and Type is it using? TobjectList or TTMeasDisplayListAncestor ?

Unless I'm just more drunk than I think... :)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文