Переполнение стека - PullRequest
       16

Переполнение стека

6 голосов
/ 05 февраля 2011

Эй, ТАК!Я публикую свою проблему переполнения стека на StackOverflow.com.Ирония в лучшем виде!

В любом случае.Я вызываю эту процедуру в моем обработчике событий 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 это не имеет значения, так как мой SO был отслежен, чтобы появиться здесь

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;и Single Step thru, эти две строки выполняются снова и снова, сразу после друг друга!

И когда я закомментирую 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 ]

5 голосов
/ 06 февраля 2011

Убедитесь, что ваш проект компилирован с отключенной опцией «оптимизация», с включенным «стеком фреймов» и с «debug .dcu», чтобы получить максимально детализированный стек вызовов.Затем опубликуйте коллстек, полученный при переполнении стека, здесь (если у вас возникли проблемы с определением характера проблемы по нему).

3 голосов
/ 07 февраля 2011

Что не отображается в вашем вопросе: функция «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!

на

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

В будущем, я предлагаю вам опубликовать полный пример кода для этоготакой вопрос.

3 голосов
/ 06 февраля 2011

Переполнение стека может быть вызвано бесконечной рекурсией.

Вы должны быть очень осторожны, когда пишете код, в котором есть обработчики событий. Одна вещь, которую вы можете сделать, чтобы помочь вам отладить это, как говорит Дэвид, шаг за шагом, а не через такие вызовы. F7 вступает в вызов.

Еще одна вещь, которую вы можете сделать, это поставить точку останова в верхней части функции GetCategoryById. Теперь посмотрите на ваш стек вызовов. Вы видите повторное имя в стеке? Это должно сделать это очень ясно.

...