#5 0x000000000057eec4 in Player::clearPartyInvitations (this=this@entry=0x7f41e84b7eb0) at player.cpp:4609
it =
list = std::list = {[0] = 0x7f41c6fefda0, [1] = 0x7f41c13b6f20, [2] = 0x7f41c122dad0, [3] = 0x7f41c121a630, [4] = 0x7f41c1358e60, [5] = 0x7f41c6c3dfd0, [6] = 0x7f41c6938620, [7] = 0x7f4181a12590,
[8] = 0x7f4189518820, [9] = 0x7f418a1513d0, [10] = 0x7f4189377810, [11] = 0x7f418932aff0, [12] = 0x7f418a44af40...
I already did this, I deactivated the party system.Disable it untill you resolve problem
Good, I would love to help you but im really unexperienced with gdb or crash errorsI already did this, I deactivated the party system.
bool Party::isPlayerInvited(const Player* player, bool result/* = false*/) const
{
if(!player || player->isRemoved())
return result;
return std::find(inviteList.begin(), inviteList.end(), player) != inviteList.end();
}
This log seems kind useful. From what I've understood from gdb backtrace, its happening onLogout, when function clearPartyInvitations is called.
Going into the detail, this is the last function called before the crash:
Code:bool Party::isPlayerInvited(const Player* player, bool result/* = false*/) const { if(!player || player->isRemoved()) return result; return std::find(inviteList.begin(), inviteList.end(), player) != inviteList.end(); }
The last line of this function is causing the crash (std::find). I'm not really expert on this. Maybe someone with more experience with c++ can debug this?
the std::find function seems to be behaving correctly.. i suppose it's not actually the problem..looking closely at the gdb.. i found thisThis log seems kind useful. From what I've understood from gdb backtrace, its happening onLogout, when function clearPartyInvitations is called.
Going into the detail, this is the last function called before the crash:
Code:bool Party::isPlayerInvited(const Player* player, bool result/* = false*/) const { if(!player || player->isRemoved()) return result; return std::find(inviteList.begin(), inviteList.end(), player) != inviteList.end(); }
The last line of this function is causing the crash (std::find). I'm not really expert on this. Maybe someone with more experience with c++ can debug this?
#7 0x0000555555697df3 in Game::removeCreature (this=0x555555a740a0 <g_game>, creature=0x5555780f6000, isLogout=isLogout@entry=true) at game.cpp:1032
tile = 0x5555ee7efc00
list = std::unordered_set with 9 elements = {[0] = 0x555564b19000, [1] = 0x55556c98b800, [2] = 0x55556646f000, [3] = 0x5555688fa800, [4] = 0x55556b169800,
[5] = 0x5555709e6000, [6] = 0x5555780f6000, [7] = 0x555567611000, [8] = 0x5555636d9800}
it = {<std::__detail::_Node_iterator_base<Creature*, false>> = {_M_cur = 0x555579d82f20}, <No data fields>}
player = <optimized out>
oldStackPosVector = std::vector of length 23448906743891, capacity 23448725278603 = {
<error reading variable oldStackPosVector (Cannot access memory at address 0x701e320f3)>
oldIndex = <optimized out>
i = <optimized out>
player->sendCreatureDisappear(creature, oldStackPosVector[i]);
bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/)
bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/)
{
if(creature->isRemoved())
return false;
Tile* tile = creature->getTile();
SpectatorVec list;
getSpectators(list, tile->getPosition(), false, true);
SpectatorVec::iterator it;
for(it = list.begin(); it != list.end(); ++it)
(*it)->onCreatureDisappear(creature, isLogout);
if(tile != creature->getTile())
{
list.clear();
tile = creature->getTile();
getSpectators(list, tile->getPosition(), false, true);
}
Player* player = NULL;
std::vector<uint32_t> oldStackPosVector;
for(it = list.begin(); it != list.end(); ++it)
{
if((player = (*it)->getPlayer()) && player->canSeeCreature(creature))
oldStackPosVector.push_back(tile->getClientIndexOfThing(player, creature));
}
int32_t oldIndex = tile->__getIndexOfThing(creature);
if(!map->removeCreature(creature))
return false;
//send to client
uint32_t i = 0;
for(it = list.begin(); it != list.end(); ++it)
{
if(creature != (*it))
(*it)->updateTileCache(tile);
if(!(player = (*it)->getPlayer()) || !player->canSeeCreature(creature))
continue;
if(i < oldStackPosVector.size())
player->sendCreatureDisappear(creature, oldStackPosVector[i]);
++i;
}
creature->getParent()->postRemoveNotification(NULL, creature, NULL, oldIndex, true);
creature->onRemovedCreature();
autoList.erase(creature->getID());
freeThing(creature);
removeCreatureCheck(creature);
for(std::list<Creature*>::iterator it = creature->summons.begin(); it != creature->summons.end(); ++it)
removeCreature(*it);
return true;
}
the std::find function seems to be behaving correctly.. i suppose it's not actually the problem..looking closely at the gdb.. i found this
Code:#7 0x0000555555697df3 in Game::removeCreature (this=0x555555a740a0 <g_game>, creature=0x5555780f6000, isLogout=isLogout@entry=true) at game.cpp:1032 tile = 0x5555ee7efc00 list = std::unordered_set with 9 elements = {[0] = 0x555564b19000, [1] = 0x55556c98b800, [2] = 0x55556646f000, [3] = 0x5555688fa800, [4] = 0x55556b169800, [5] = 0x5555709e6000, [6] = 0x5555780f6000, [7] = 0x555567611000, [8] = 0x5555636d9800} it = {<std::__detail::_Node_iterator_base<Creature*, false>> = {_M_cur = 0x555579d82f20}, <No data fields>} player = <optimized out> oldStackPosVector = std::vector of length 23448906743891, capacity 23448725278603 = { <error reading variable oldStackPosVector (Cannot access memory at address 0x701e320f3)> oldIndex = <optimized out> i = <optimized out>
Error reading variable from vector.. i guess it went outside of vector bounds at line 996(I'm using 3774 .. so there might be slight differences)
in this Line exactly
You could try changing this functionCode:player->sendCreatureDisappear(creature, oldStackPosVector[i]);
Code:bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/)
To
Code:bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/) { if(creature->isRemoved()) return false; Tile* tile = creature->getTile(); SpectatorVec list; getSpectators(list, tile->getPosition(), false, true); SpectatorVec::iterator it; for(it = list.begin(); it != list.end(); ++it) (*it)->onCreatureDisappear(creature, isLogout); if(tile != creature->getTile()) { list.clear(); tile = creature->getTile(); getSpectators(list, tile->getPosition(), false, true); } Player* player = NULL; std::vector<uint32_t> oldStackPosVector; for(it = list.begin(); it != list.end(); ++it) { if((player = (*it)->getPlayer()) && player->canSeeCreature(creature)) oldStackPosVector.push_back(tile->getClientIndexOfThing(player, creature)); } int32_t oldIndex = tile->__getIndexOfThing(creature); if(!map->removeCreature(creature)) return false; //send to client uint32_t i = 0; for(it = list.begin(); it != list.end(); ++it) { if(creature != (*it)) (*it)->updateTileCache(tile); if(!(player = (*it)->getPlayer()) || !player->canSeeCreature(creature)) continue; if(i < oldStackPosVector.size()) player->sendCreatureDisappear(creature, oldStackPosVector[i]); ++i; } creature->getParent()->postRemoveNotification(NULL, creature, NULL, oldIndex, true); creature->onRemovedCreature(); autoList.erase(creature->getID()); freeThing(creature); removeCreatureCheck(creature); for(std::list<Creature*>::iterator it = creature->summons.begin(); it != creature->summons.end(); ++it) removeCreature(*it); return true; }
And Hopefully it works (
the std::find function seems to be behaving correctly.. i suppose it's not actually the problem..looking closely at the gdb.. i found this
Code:#7 0x0000555555697df3 in Game::removeCreature (this=0x555555a740a0 <g_game>, creature=0x5555780f6000, isLogout=isLogout@entry=true) at game.cpp:1032 tile = 0x5555ee7efc00 list = std::unordered_set with 9 elements = {[0] = 0x555564b19000, [1] = 0x55556c98b800, [2] = 0x55556646f000, [3] = 0x5555688fa800, [4] = 0x55556b169800, [5] = 0x5555709e6000, [6] = 0x5555780f6000, [7] = 0x555567611000, [8] = 0x5555636d9800} it = {<std::__detail::_Node_iterator_base<Creature*, false>> = {_M_cur = 0x555579d82f20}, <No data fields>} player = <optimized out> oldStackPosVector = std::vector of length 23448906743891, capacity 23448725278603 = { <error reading variable oldStackPosVector (Cannot access memory at address 0x701e320f3)> oldIndex = <optimized out> i = <optimized out>
Error reading variable from vector.. i guess it went outside of vector bounds at line 996(I'm using 3774 .. so there might be slight differences)
in this Line exactly
You could try changing this functionCode:player->sendCreatureDisappear(creature, oldStackPosVector[i]);
Code:bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/)
To
Code:bool Game::removeCreature(Creature* creature, bool isLogout /*= true*/) { if(creature->isRemoved()) return false; Tile* tile = creature->getTile(); SpectatorVec list; getSpectators(list, tile->getPosition(), false, true); SpectatorVec::iterator it; for(it = list.begin(); it != list.end(); ++it) (*it)->onCreatureDisappear(creature, isLogout); if(tile != creature->getTile()) { list.clear(); tile = creature->getTile(); getSpectators(list, tile->getPosition(), false, true); } Player* player = NULL; std::vector<uint32_t> oldStackPosVector; for(it = list.begin(); it != list.end(); ++it) { if((player = (*it)->getPlayer()) && player->canSeeCreature(creature)) oldStackPosVector.push_back(tile->getClientIndexOfThing(player, creature)); } int32_t oldIndex = tile->__getIndexOfThing(creature); if(!map->removeCreature(creature)) return false; //send to client uint32_t i = 0; for(it = list.begin(); it != list.end(); ++it) { if(creature != (*it)) (*it)->updateTileCache(tile); if(!(player = (*it)->getPlayer()) || !player->canSeeCreature(creature)) continue; if(i < oldStackPosVector.size()) player->sendCreatureDisappear(creature, oldStackPosVector[i]); ++i; } creature->getParent()->postRemoveNotification(NULL, creature, NULL, oldIndex, true); creature->onRemovedCreature(); autoList.erase(creature->getID()); freeThing(creature); removeCreatureCheck(creature); for(std::list<Creature*>::iterator it = creature->summons.begin(); it != creature->summons.end(); ++it) removeCreature(*it); return true; }
And Hopefully it works (
gdb xavato coreParty
Reading symbols from xavato...done.
[New LWP 31439]
[New LWP 31437]
[New LWP 31441]
[New LWP 31463]
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib/x86_64-linux-gnu/libthread_db.so.1".
Core was generated by `./xavato'.
Program terminated with signal SIGSEGV, Segmentation fault.
#0 std::__find_if<__gnu_cxx::__normal_iterator<Player* const*, std::vector<Player*, std::allocator<Player*> > >, __gnu_cxx::__ops::_Iter_equals_val<Player const* const> > (__first=...,
__last=__last@entry=..., __pred=__pred@entry=...) at /usr/include/c++/4.9/bits/stl_algo.h:120
120 if (__pred(__first))
bt full
but..#0 std::__find_if<__gnu_cxx::__normal_iterator<Player* const*, std::vector<Player*, std::allocator<Player*> > >, __gnu_cxx::__ops::_Iter_equals_val<Player const* const> > (
__first=<error reading variable: Cannot access memory at address 0x6073726579616c70>, __last=__last@entry=<error reading variable: Cannot access memory at address 0x6e6f602054455320>,
__pred=__pred@entry=...) at /usr/include/c++/4.9/bits/stl_algo.h:120
__trip_count = 31489385263734581
#1 0x0000000000572b8b in __find_if<__gnu_cxx::__normal_iterator<Player* const*, std::vector<Player*> >, __gnu_cxx::__ops::_Iter_equals_val<Player const* const> > (__pred=..., __last=..., __first=...)
at /usr/include/c++/4.9/bits/stl_algo.h:162
No locals.
#2 find<__gnu_cxx::__normal_iterator<Player* const*, std::vector<Player*> >, Player const*> (__val=<optimized out>, __last=<error reading variable: Cannot access memory at address 0x6e6f602054455320>,
__first=...) at /usr/include/c++/4.9/bits/stl_algo.h:3779
No locals.
#3 Party::isPlayerInvited (this=this@entry=0x7f41c6938620, player=player@entry=0x7f41e84b7eb0, result=result@entry=false) at party.cpp:439
No locals.
#4 0x0000000000572bc5 in Party::removeInvite (this=0x7f41c6938620, player=player@entry=0x7f41e84b7eb0) at party.cpp:173
it = <optimized out>
#5 0x000000000057eec4 in Player::clearPartyInvitations (this=this@entry=0x7f41e84b7eb0) at player.cpp:4609
it =
list = std::list = {[0] = 0x7f41c6fefda0, [1] = 0x7f41c13b6f20, [2] = 0x7f41c122dad0, [3] = 0x7f41c121a630, [4] = 0x7f41c1358e60, [5] = 0x7f41c6c3dfd0, [6] = 0x7f41c6938620, [7] = 0x7f4181a12590,
[8] = 0x7f4189518820, [9] = 0x7f418a1513d0, [10] = 0x7f4189377810, [11] = 0x7f418932aff0, [12] = 0x7f418a44af40, [13] = 0x7f418a4131a0, [14] = 0x7f418a47a900, [15] = 0x7f418a0c69b0,
[16] = 0x7f4188cf4e40, [17] = 0x7f419479e900, [18] = 0x7f4189a86f60, [19] = 0x7f4189a6b340, [20] = 0x7f4192ba24d0, [21] = 0x7f4189a35830, [22] = 0x7f41889dfd60, [23] = 0x7f41929a91a0}
#6 0x0000000000582b0e in Player:nCreatureDisappear (this=0x7f41e84b7eb0, creature=0x7f41e84b7eb0, isLogout=<optimized out>, setOnline=<optimized out>) at player.cpp:1444
saved = <optimized out>
#7 0x00000000004a2abe in Game::removeCreature (this=0x8e76c0 <g_game>, creature=0x7f41e84b7eb0, isLogout=isLogout@entry=true, setOnline=setOnline@entry=true) at game.cpp:1022
tile = 0x7f41d7ecc6a0
list = std::list = {[0] = 0x7f41ee83d810, [1] = 0x7f41ee8423b0, [2] = 0x7f41ef2a2130, [3] = 0x7f41ee847450, [4] = 0x7f41fa0721d0, [5] = 0x7f41e84b7eb0, [6] = 0x7f41fa738f20, [7] = 0x7f41fa2bd9d0,
[8] = 0x7f41ee16ed20, [9] = 0x7f41ee1767b0, [10] = 0x7f41e827b530, [11] = 0x7f41f9caf120, [12] = 0x7f41ef2a1ad0, [13] = 0x7f41ef2a2770, [14] = 0x7f41e850c740, [15] = 0x7f41efda0ce0,
[16] = 0x7f41ee17cdd0, [17] = 0x7f41fa0b1360, [18] = 0x7f41e81dcb30, [19] = 0x7f41ef2a3360, [20] = 0x7f41ef2a2dd0, [21] = 0x7f41ee858410, [22] = 0x7f41ee85c980, [23] = 0x7f41ee85e040,
[24] = 0x7f41ee85e5f0, [25] = 0x7f41ee85da90}
i = <optimized out>
it =
player = <optimized out>
oldStackPosVector = std::vector of length -7529021625, capacity -7526581769 = {<error reading variable oldStackPosVector (Cannot access memory at address 0x7030f02e6)>
oldIndex = <optimized out>
It's some C++ stl_algo.h library, not part of TFS, we are in most cases not able to fix it and in 99.999% it's related to 'wrong use' of functions (read not existing list), not bug in C++ basic libraries.#0 std::__find_if<__gnu_cxx::__normal_iterator<Player* const*, std::vector<Player*, std::allocator<Player*> > >, __gnu_cxx::__ops::_Iter_equals_val<Player const* const> > (
__first=<error reading variable: Cannot access memory at address 0x6073726579616c70>, __last=__last@entry=<error reading variable: Cannot access memory at address 0x6e6f602054455320>,
__pred=__pred@entry=...) at /usr/include/c++/4.9/bits/stl_algo.h:120
__trip_count = 31489385263734581
#1 0x0000000000572b8b in __find_if<__gnu_cxx::__normal_iterator<Player* const*, std::vector<Player*> >, __gnu_cxx::__ops::_Iter_equals_val<Player const* const> > (__pred=..., __last=..., __first=...)
at /usr/include/c++/4.9/bits/stl_algo.h:162
No locals.
#2 find<__gnu_cxx::__normal_iterator<Player* const*, std::vector<Player*> >, Player const*> (__val=<optimized out>, __last=<error reading variable: Cannot access memory at address 0x6e6f602054455320>,
__first=...) at /usr/include/c++/4.9/bits/stl_algo.h:3779
No locals.
Here is some TFS function! Now we can check what is in sources party.cpp function Party::isPlayerInvited:#3 Party::isPlayerInvited (this=this@entry=0x7f41c6938620, player=player@entry=0x7f41e84b7eb0, result=result@entry=false) at party.cpp:439
No locals.
bool Party::isPlayerInvited(const Player* player, bool result/* = false*/) const
Now assign that address to variable in gdb and cast it to Player* type:0x7f41e84b7eb0
p (Player*) 0x7f41e84b7eb0
Now we can check what variables are available in sources player.h, it extends creature.h and there is... name. We can print it:$1 = (Player *) 0x7f41e84b7eb0
print $1.name
$2 = "Summtingwong"
#5 0x000000000057eec4 in Player::clearPartyInvitations (this=this@entry=0x7f41e84b7eb0) at player.cpp:4609
it =
list = std::list = {[0] = 0x7f41c6fefda0, [1] = 0x7f41c13b6f20, [2] = 0x7f41c122dad0, [3] = 0x7f41c121a630, [4] = 0x7f41c1358e60, [5] = 0x7f41c6c3dfd0, [6] = 0x7f41c6938620, [7] = 0x7f4181a12590,
[8] = 0x7f4189518820, [9] = 0x7f418a1513d0, [10] = 0x7f4189377810, [11] = 0x7f418932aff0, [12] = 0x7f418a44af40, [13] = 0x7f418a4131a0, [14] = 0x7f418a47a900, [15] = 0x7f418a0c69b0,
[16] = 0x7f4188cf4e40, [17] = 0x7f419479e900, [18] = 0x7f4189a86f60, [19] = 0x7f4189a6b340, [20] = 0x7f4192ba24d0, [21] = 0x7f4189a35830, [22] = 0x7f41889dfd60, [23] = 0x7f41929a91a0}
10:07 Summtingwong has been invited. Open the party channel to communicate with your members.
10:07 Summtingwong has invited you to his party.
10:07 You have left the party.
10:07 Summtingwong has left the party.
if (invitedPlayer == player)
return false;
Party* party = player->getParty();
Guy is invited to 2 parties, probably he was a leader of both and that's why it crashed.#5 0x00005555557b1004 in Player::clearPartyInvitations (this=this@entry=0x5555b481e000) at player.cpp:5520
it = 0x55555787f500
list = std::__cxx11::list = {[0] = 0x55555789ef80, [1] = 0x55555787f500}
Great explanation, congratulations!I decided to release that bug in TFS 0.4 (and probably many other distros, not tested it on any other).
YOU CAN INVITE YOURSELF TO PARTY! - WHEN YOU ARE NOT A MEMBER OF ANY PARTY!
After reading gdb I found out that guy was invited to 24 parties:
PHP:#5 0x000000000057eec4 in Player::clearPartyInvitations (this=this@entry=0x7f41e84b7eb0) at player.cpp:4609 it = list = std::list = {[0] = 0x7f41c6fefda0, [1] = 0x7f41c13b6f20, [2] = 0x7f41c122dad0, [3] = 0x7f41c121a630, [4] = 0x7f41c1358e60, [5] = 0x7f41c6c3dfd0, [6] = 0x7f41c6938620, [7] = 0x7f4181a12590, [8] = 0x7f4189518820, [9] = 0x7f418a1513d0, [10] = 0x7f4189377810, [11] = 0x7f418932aff0, [12] = 0x7f418a44af40, [13] = 0x7f418a4131a0, [14] = 0x7f418a47a900, [15] = 0x7f418a0c69b0, [16] = 0x7f4188cf4e40, [17] = 0x7f419479e900, [18] = 0x7f4189a86f60, [19] = 0x7f4189a6b340, [20] = 0x7f4192ba24d0, [21] = 0x7f4189a35830, [22] = 0x7f41889dfd60, [23] = 0x7f41929a91a0}
I also knew his name from gdb, so I watched movie (CamSystem) and saw these messages:
PHP:10:07 Summtingwong has been invited. Open the party channel to communicate with your members. 10:07 Summtingwong has invited you to his party. 10:07 You have left the party. 10:07 Summtingwong has left the party.
After few checks I found out that function playerInviteToParty (in game.cpp) creates new Party (when you invite first player to it), but it does not check, if invited player is not an inviting player.
To invite 'yourself' you need to use OTClient, Elfbot or some other bot. There is no option 'Invite to party' when you click on yourself in Tibia client, but with bot you can send any 'packet'.
That's why no one found that bug in past 7 years (since 0.4 release).
Code you need to add is (in 0.4 r3777):
Add it above:PHP:if (invitePlayer == player) return false;
PHP:Party* party = player->getParty();
-----------------------
I've checked TFS 1.x sources and there is also no check for this (invite yourself):
otland/forgottenserver
Maybe there is other 'logout' procedure, that will remove invalid invitations without crash, but I got no server/bot to test it.
-----------------------
IS MY SERVER SAFE?
To check, if your server is safe, you need to write some bot that invite yourself and then disband party.
After few seconds of spam (invite -> disband -> invite -> ...), you just need to logout. If you server is bugged, it will crash.
EDIT:
gdb from first post of thread:
Guy is invited to 2 parties, probably he was a leader of both and that's why it crashed.
Best answer?
I decided to release that bug in TFS 0.4 (and probably many other distros, not tested it on any other).
YOU CAN INVITE YOURSELF TO PARTY! - WHEN YOU ARE NOT A MEMBER OF ANY PARTY!
After reading gdb I found out that guy was invited to 24 parties:
PHP:#5 0x000000000057eec4 in Player::clearPartyInvitations (this=this@entry=0x7f41e84b7eb0) at player.cpp:4609 it = list = std::list = {[0] = 0x7f41c6fefda0, [1] = 0x7f41c13b6f20, [2] = 0x7f41c122dad0, [3] = 0x7f41c121a630, [4] = 0x7f41c1358e60, [5] = 0x7f41c6c3dfd0, [6] = 0x7f41c6938620, [7] = 0x7f4181a12590, [8] = 0x7f4189518820, [9] = 0x7f418a1513d0, [10] = 0x7f4189377810, [11] = 0x7f418932aff0, [12] = 0x7f418a44af40, [13] = 0x7f418a4131a0, [14] = 0x7f418a47a900, [15] = 0x7f418a0c69b0, [16] = 0x7f4188cf4e40, [17] = 0x7f419479e900, [18] = 0x7f4189a86f60, [19] = 0x7f4189a6b340, [20] = 0x7f4192ba24d0, [21] = 0x7f4189a35830, [22] = 0x7f41889dfd60, [23] = 0x7f41929a91a0}
I also knew his name from gdb, so I watched movie (CamSystem) and saw these messages:
PHP:10:07 Summtingwong has been invited. Open the party channel to communicate with your members. 10:07 Summtingwong has invited you to his party. 10:07 You have left the party. 10:07 Summtingwong has left the party.
After few checks I found out that function playerInviteToParty (in game.cpp) creates new Party (when you invite first player to it), but it does not check, if invited player is not an inviting player.
To invite 'yourself' you need to use OTClient, Elfbot or some other bot. There is no option 'Invite to party' when you click on yourself in Tibia client, but with bot you can send any 'packet'.
That's why no one found that bug in past 7 years (since 0.4 release).
Code you need to add is (in 0.4 r3777):
Add it above:PHP:if (invitePlayer == player) return false;
PHP:Party* party = player->getParty();
-----------------------
I've checked TFS 1.x sources and there is also no check for this (invite yourself):
otland/forgottenserver
Maybe there is other 'logout' procedure, that will remove invalid invitations without crash, but I got no server/bot to test it.
-----------------------
IS MY SERVER SAFE?
To check, if your server is safe, you need to write some bot that invite yourself and then disband party.
After few seconds of spam (invite -> disband -> invite -> ...), you just need to logout. If you server is bugged, it will crash.
EDIT:
gdb from first post of thread:
Guy is invited to 2 parties, probably he was a leader of both and that's why it crashed.
Best answer?
Marged ^^Someone reported today problem with crashes on OTX. It was party crash bug.
I wrote fixes for otx2 and otx3:
Party self-invite crash bug fix by JSkalskiSBG · Pull Request #376 · mattyx14/otxserver
Party self-invite crash bug fix by JSkalskiSBG · Pull Request #377 · mattyx14/otxserver
If anyone got contact with mattyx, please tell him to merge these changes.