堆栈溢出

时间:2011-02-05 20:38:49

标签: delphi function stack-overflow skype

嘿S.O!我在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被追溯到这里

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,按要求: CallStack

Edit2:更多信息: More Info

感谢您的时间! - 杰夫

3 个答案:

答案 0 :(得分:5)

确保编译项目时关闭“优化”,“堆栈帧”和“使用debug .dcu”,以获得最详细的callstack。然后发布你在这里遇到堆栈溢出时得到的callstack(如果你无法从中识别问题的性质)。

答案 1 :(得分:3)

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

编写包含事件处理程序的代码时,必须非常小心。 正如大卫所说,你可以做的一件事就是帮助你调试这个问题,而不是通过这样的调用。 F7进入通话。

您可以做的另一件事是在函数GetCategoryById的顶部放置一个断点。现在看看你的Call Stack。你看到堆栈中重复的名字了吗?这应该很清楚。

答案 2 :(得分:3)

您的问题中没有显示的内容: 你在这里发布的“OnCategoryRename”函数是一个从“TForm.Skype1Reply”回调调用的子函数。

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

我的猜测:

  • 您的“GetCategoryById”函数实际上会发送一个查询,触发“Skype1Reply”。
  • 如果组名已更改,“Skype1Reply”将调用“OnCategoryRename”。
  • “OnCategoryRename”调用“GetCategoryById”
  • “GetCategoryById”触发“Skype1Reply”
  • 不知怎的,测试说“如果groupname已经改变”仍然是,所以“Skype1Reply”调用“OnCategoryRename”
  • “OnCategoryRename”调用“GetCategoryById”
  • 冲洗,重复

我认为快速而肮脏的解决方法是改变

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

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

将来,我建议您发布此类问题的完整代码示例。