Delphi中的堆栈溢出

问题描述 投票:6回答:3

我正在StackOverflow.com上发布我的Stack Overflow问题。具有讽刺意味的是!

反正我正在我的SkypeReply事件处理程序上调用此过程,该事件处理程序被激发很多:

  Procedure OnCategoryRename;
  Var
    CategoryID : Integer;
    sCtgName : String;
  Begin
    if (AnsiContainsStr(pCommand.Reply,'GROUP')) and (AnsiContainsStr(pCommand.Reply,'DISPLAYNAME')) then
      begin
         sCtgName := pCommand.Reply;
         Delete(sCtgName,1,Pos('GROUP',sCtgName)+5);
         CategoryID := StrToInt(Trim(LeftStr(sCtgName,Pos(' ',sCtgName))));
         sCtgName := GetCategoryByID(CategoryID).DisplayName; // Removing THIS line does not produce a Stack Overflow!
         ShowMessage(sCtgName); 
      end;

的想法是循环浏览我的Skype组列表,以查看已重命名的组。 AFAIK并不重要,因为我的S.O已被追踪显示为here

Function GetCategoryByID(ID : Integer):IGroup;
Var
  I : Integer;
  Category : IGroup;
Begin
  // Make the default result nil
  Result := nil;

  // Loop thru the CUSTOM CATEGORIES of the ONLY SKYPE CONTROL used in this project
  // (which 100% positive IS attached ;) )
  for I := 1 to frmMain.Skype.CustomGroups.Count do
    Begin
      // The Category Variable
      Category := frmMain.Skype.CustomGroups.Item[I];
      // If the current category ID returned by the loop matches the passed ID
      if Category.Id = ID then
        begin
          // Return the Category as Result (IGroup)
          Result := Category;
          // Exit the function.
          Exit;
        end;
    End;
End;

当我在Result:= Category处设置断点时;和“单步通过”,那两条线会一遍又一遍地执行!

并且当我在第一个代码段中注释掉sCtgName := GetCategoryByID(CategoryID).DisplayName;时,没有溢出,该消息得到提示,这是应该的。但是,GetCategoryByID是我编写的一个函数,我也编写了一个类似的函数,该函数也很好用(GetCategoryByName),所以我不明白为什么它决定重复此代码

// Return the Category as Result (IGroup)
Result := Category;
// Exit the function.
Exit;

一遍又一遍。

编辑:这是您如何复制它:https://gist.github.com/813389

编辑:这是我的CallStack,根据要求:“

Edit2:更多信息:“更多信息”

delphi function stack-overflow skype
3个回答
3
投票

您的问题没有显示什么:您在此处发布的“ OnCategoryRename”函数是一个从“ TForm.Skype1Reply”回调中调用的子函数。

要看到这一点,我必须单击您的github链接-但我认为这是您问题的重点。

我的猜测:

  • 您的“ GetCategoryById”函数实际上发送了一个查询,该查询触发了“ Skype1Reply”。
  • 如果组名已更改,则“ Skype1Reply”将调用“ OnCategoryRename”。
  • “ OnCategoryRename”调用“ GetCategoryById”
  • “” GetCategoryById“触发” Skype1Reply“
  • 以某种方式,说“如果组名已更改”的测试仍然是正确的,因此“ Skype1Reply”调用“ OnCategoryRename”
  • “ OnCategoryRename”调用“ GetCategoryById”
  • 冲洗,重复

我认为将有一个快速而肮脏的解决方法

sCtgName := GetCategoryByID(CategoryID).DisplayName; // Removing THIS line does not produce a Stack Overflow!

with

sCtgName := //find another way to get the new name, which you can probably get from your ICommand object
            pCommand.Reply.ReadDataFromReplyAndGetNewDisplayName;

以后,我建议您针对此类问题发布完整的代码示例。


5
投票

请确保在关闭“优化”,打开“堆栈框架”并打开“使用debug .dcu”的情况下编译项目,以获取尽可能详细的调用堆栈。然后发布您在此处遇到堆栈溢出时获得的调用堆栈(如果无法从中识别问题的性质)。


3
投票

堆栈溢出可能是无休止的递归引起的。

[编写包含事件处理程序的代码时必须非常小心。正如David所说,您可以做的一件事是帮助您调试此问题,而不是通过此类调用进入INTO。 F7进入通话。

您可以做的另一件事是在函数GetCategoryById的顶部放置一个断点。现在查看您的调用堆栈。您是否在堆栈中看到重复的名称?这应该很清楚。

© www.soinside.com 2019 - 2024. All rights reserved.