I'm writing a party system for a game, and I'm getting some very strange behavior out of a std::set std::wstring that contains IP addresses for the party. The error I'm getting is in xtree, usually in clear, but I've also hit it in insert. It's a read access violation at _Head->_Parent, usually says something like "_Head->_Parent was [memory address]."
This problem is very rare, and I've been trying to reproduce it for 2 months with no success. The game is up 24/7, and thousands of parties are created and destroyed each day, and I only get this error 2-3 times a week. Everything that inserts into, erases from, iterates over, or clears this set has a global mutex around it, that's only used for this set. Here's the relevant code:
Party.h
```
private:
std::set<std::wstring> ipList;
public:
std::set<std::wstring> getIPList() { return ipList; }
```
Party.cpp
```
PartyManager::DisbandParty(Party* party){
SAFE_DELETE(party);
}
Party::~Party(){
ipList.clear();
}
Party::AddPartyMember(){
getUniquePlayerLock.lock();
ipList.insert(s2ws(player->GetClientSession()->GetRemoteIP()));
getUniquePlayerLock.unlock();
}
Party::LeaveParty(){
getUniquePlayerLock.lock();
ipList.erase(s2ws(player->GetClientSession()->GetRemoteIP()));
getUniquePlayerLock.unlock();
}
Party::KickMember(){
getUniquePlayerLock.lock();
ipList.erase(s2ws(kickedplayer->GetClientSession()->GetRemoteIP()));
getUniquePlayerLock.unlock();
}
Party::GetUniquePlayers(){
std::set<std::wstring>::iterator it;
std::wstring curIP;
std::list<CPlayer*> uniquePlayers;
if (!ipList.empty()) {
for (it = ipList.begin(); it != ipList.end(); it++)
{
curIP = *it;
//std::wcout << "\nChecking IP " << curIP;
for (int i = 0; i < m_byMemberInfoCount; i++)
{
//std::cout << "\n" << i;
CPlayer* player = GetPlayer(i);
if (player) {
if (curIP == s2ws(player->GetClientSession()->GetRemoteIP())) {
uniquePlayers.push_back(player);
//std::wcout << "\n" << curIP;
break;
}
}
}
}
}
return uniquePlayers;
}
```
I'm all out of ideas here. It has to be some sort of undefined behavior, memory corruption, or something very obvious that I'm missing. Maybe in certain circumstances ipList is being destroyed before the party destructor is called? I'm still fuzzy on when variables declared in header files are considered "out of scope" and thus destroyed. Any help is appreciated.
Edit: With this logic, would the value of player->GetClientSession()->GetRemoteIP() be destroyed until it is repopulated?
Edit2: I've made some changes to check for nulls in the client session and IP as requested. This time, I'm getting an access violation error on accessing the lower bound of the set.
```
template <class _Keyty>
_Tree_find_result<_Nodeptr> _Find_lower_bound(const _Keyty& _Keyval) const {
const auto _Scary = _Get_scary();
_Tree_find_result<_Nodeptr> _Result{{_Scary->_Myhead->_Parent, _Tree_child::_Right}, _Scary->_Myhead}; **ACCESS VIOLATION ERROR IS HERE**
_Nodeptr _Trynode = _Result._Location._Parent;
while (!_Trynode->_Isnil) {`enter code here`
_Result._Location._Parent = _Trynode;
if (_DEBUG_LT_PRED(_Getcomp(), _Traits::_Kfn(_Trynode->_Myval), _Keyval)) {
_Result._Location._Child = _Tree_child::_Right;
_Trynode = _Trynode->_Right;
} else {
_Result._Location._Child = _Tree_child::_Left;
_Result._Bound = _Trynode;
_Trynode = _Trynode->_Left;
}
}
return _Result;
}
```
What could I possibly be doing to this set to cause this memory access error? It's a member variable being accessed in a class function, with no out of band destructors being called on it anywhere. I'm totally lost here.
Edit 3: Adding ifdefs for the global mutex below:
globalVariables.h:
#pragma once
#ifndef playerLockDefined
#include <mutex>
#define playerLockDefined
extern std::mutex getUniquePlayerLock;
#endif // !1
globalVariables.cpp:
#include "stdafx.h"
#include "globalVariables.h"
std::mutex getUniquePlayerLock;