Function is called twice from the same thread for the same object with the same call stack

2

Background

I am debugging one open source project I am willing to join and learn C++. Then I tried extending some functionality needed for one of the issues over there and I stumbled on interesting case (never seen something like this in my life).

Source code

QuestSet Player::GetQuestForEvent(uint16 eventId) const
{
    QuestSet eventQuests; // QuestSet is typedef for std::set<uint32>

    for (uint8 i = 0; i < MAX_QUEST_LOG_SIZE; ++i)
    {
        uint32 questId = GetQuestSlotQuestId(i);
        if (questId == 0)
            continue;

        QuestStatusMap::const_iterator qs_itr = m_QuestStatus.find(questId);
        if (qs_itr == m_QuestStatus.end())
            continue;

        QuestStatusData const& qs = qs_itr->second;

        Quest const* qinfo = sObjectMgr->GetQuestTemplate(questId);
        if (!qinfo)
            continue;

        if (qinfo->GetEventIdForQuest() == eventId)
            eventQuests.insert(questId);
    }

    return eventQuests; <--- breakpoint here
}

I noticed that my server crash with

Unhandled exception at 0x00007FFE1BE6A388 (KernelBase.dll) in worldserver.exe: 0xC0000005: Access violation.

followed by this log from my server

C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Tools\MSVC\14.20.27508\include\xtree(240) : Assertion failed: map/set iterators in range are from different containers

So I've put breakpoint on the aforementioned place and I noticed that the function is called twice. I know uploading pictures might not be the best option but its the best explanation in this case in my opinion so take a look.

Screenshots

  • first breakpoint hit first breakpoint hit

  • second breakpoint hit (notice events window from diagnostic tools window) second breakpoint hit

This is the only place in the project where this function is being called.

void OnLogin(Player* player, bool /*firstLogin*/) override
{
    QuestSet eventQuests = player->GetQuestForEvent(1);
    /*std::for_each(eventQuests.begin(), eventQuests.end(), [&player](uint32 questId)
    {
        player->AbandonQuest(questId);
    });*/
}

I know it sounds silly but I am out of suggestions, could you please point me into the right direction, understanding why this breakpoint is hit twice most likely will fix the exceptions aswell.

Troubleshooting:

  • project is built in Debug configuration
  • callstack, thread and this object are all the same through both hits.
c++
visual-studio
debugging
asked on Stack Overflow May 8, 2019 by kuskmen • edited May 8, 2019 by kuskmen

1 Answer

2

Most likely the function is not actually called twice. You are just drawing the wrong conclusion from hitting the same breakpoint twice.

Visual Studio allows you to inspect the assembly code near your breakpoint, default is Ctrl+Alt+D I believe. In there you will see a mix of assembly instructions (what your CPU actually does) and the debugging information of "which line(s) of code did the following instruction(s) originate from".

What I expect you will see there is that the return eventQuests; line is associated to two blocks of assembly instructions, with another block of instructions in between. You will first hit the breakpoint in the first group of instructions, then the second group will execute (e.g. associated to the loop, or the closing brace) and then the breakpoint is hit once more due to the second group. Yes, that sounds pretty dumb but the debugging information that MSVC outputs is not the best I've seen.

Another simple way to check would be to insert a print statement (like std::cout << "Hi" << std::endl) before the return and check whether you get one or two printouts. Unless you get two printouts, your conclusion of actually entering the function more than once is wrong.

answered on Stack Overflow May 8, 2019 by Max Langhof

User contributions licensed under CC BY-SA 3.0