简体   繁体   中英

Stack Overflow in Delphi

I am posting my Stack Overflow problem on StackOverflow.com. Irony at its best!

Anyways. I am calling this procedure on my SkypeReply event handler, which gets fired a lot:

  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;

The idea of this is to loop thru my list of Skype Groups, to see what group has been renamed. AFAIK thats of no importance, as my SO has been traced to appear 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;

When I set a breakpoint at Result := Category; and Single Step thru, those 2 lines get executed over and over, right after each other!

And when I comment out the sCtgName := GetCategoryByID(CategoryID).DisplayName; in the first code snippet, there is no Overflow, the message gets shown that one time it is supposed to. However, the GetCategoryByID is a function I wrote, and I wrote one similar, too, which works just fine (GetCategoryByName), so I don't get why it decided to repeat the

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

over and over again.

EDIT: Here is how you can reproduce it: https://gist.github.com/813389

EDIT: Here is my CallStack, as requested:调用堆栈

Edit2: More info:更多信息

Make sure to compile your project with "optimization" off, "stack frames" on and "use debug .dcu" on to get the most detailed callstack possible. Then post the callstack you get when you hit the stack overflow here (if you have trouble identifying the nature of the problem from it).

Stack overflows could be caused by endless recursion.

You have to be very careful when you write code that has event handlers in it. One thing you can do to help you debug this is, as David says, step INTO rather than over such calls. F7 steps into a call.

Another thing you can do is put a breakpoint at the top of the function GetCategoryById. Now look at your Call Stack. Do you see the repeated name in the stack? This should make it very clear.

What doesn't show up in your question : the "OnCategoryRename" function you posted up here is a subfunction called from a "TForm.Skype1Reply" callback.

To see this, I had to click on your github link - yet I think it is an important point of your problem.

My guess :

  • Your "GetCategoryById" function actually sends a query, which triggers "Skype1Reply".
  • If the groupname has changed, "Skype1Reply" calls "OnCategoryRename".
  • "OnCategoryRename" calls "GetCategoryById"
  • "GetCategoryById" triggers "Skype1Reply"
  • Somehow, the test saying "if groupname has changed" is still true, so "Skype1Reply" calls "OnCategoryRename"
  • "OnCategoryRename" calls "GetCategoryById"
  • rinse, repeat

I think a quick and dirty fix would be to change

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;

In the future, I suggest you post your complete code sample for this kind of question.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM