Падает сервер
|
|
Entity
|
Дата: Пятница, 03.11.2017, 17:42:45 | Сообщение # 1 |
|
Сообщений: 67
Репутация: 1 [ +/- ]
|
|
Здравствуйте. Такая проблема мучает. Почти каждый день (1-2 раза в день) сервер падает на смене карты. До смены карты сервер не лагает. Возможно, дело в утечке памяти. Плагинов своих много, скоро пересмотрю весь код на наличие утечек. Как думаете, в чем проблема? Может кто сталкивался с этим...
|
|
| |
Nail
|
Дата: Суббота, 04.11.2017, 17:42:51 | Сообщение # 2 |
|
Сообщений: 38
Репутация: 8 [ +/- ]
|
|
Можно сдампить хэндлы и посмотреть что там с потреблением памяти. Последний сорсмод сам хорошо с утечками справляется и всё логирует т.ч. многого ждать не стоит. Еще есть инструмент accelerator, он выдает трэйсстэк при краше. По нему можно вычислить сбоящий экстеншин или сбой в двиге. По стэку видно какая функция не отработала а по ней можно уже определить и спэшник, который формирует плохой запрос. То, что крашит часто - это хорошо, можно методом исключения найти плохой плагин. Надо разбить список плагинов на 2 и первый день проверять первую половину, второй вторую затем еще разбить на 2 и т.д. так можно выйти на баговый плагин за несколько дней. Главное делать выдержку с запасом т.к. баговых плагинов может быть несколько и если один из них пропустить, придется начинать заново. Есть еще железный метод - добавить логирование в плагины на начало вызова функций и на конец. При краше в логах будет видно какая функция была вызвана но не завершилась.
Сообщение отредактировал Nail - Воскресенье, 05.11.2017, 14:19:20 |
|
| |
Entity
|
Дата: Среда, 08.11.2017, 11:33:08 | Сообщение # 3 |
|
Сообщений: 67
Репутация: 1 [ +/- ]
|
|
Nail, спасибо большое) попробую сначала accelerator'om. Может без лишней заморочки проблему сразу выявлю)Добавлено (08.11.2017, 11:33:08) --------------------------------------------- Nail, отловил acceletor'om такое вот:
0 engine_srv.so!CFrameSnapshotManager::RemoveEntityReference(int) + 0x15 1 engine_srv.so!CFrameSnapshotManager::DeleteFrameSnapshot(CFrameSnapshot*) + 0x4b 2 engine_srv.so!CFrameSnapshot::ReleaseReference() + 0x2c 3 engine_srv.so!CClientFrame::SetSnapshot(CFrameSnapshot*) + 0x3a 4 engine_srv.so!CClientFrame::SetSnapshot(CFrameSnapshot*) + 0x70 5 engine_srv.so!CClientFrameManager::FreeFrame(CClientFrame*) + 0x28 6 engine_srv.so!CClientFrameManager::DeleteClientFrames(int) + 0x40 7 engine_srv.so!CGameClient::UpdateAcknowledgedFramecount(int) + 0x75 8 engine_srv.so!NET_Tick::Process() + 0x18 9 engine_srv.so!CNetChan::ProcessMessages(bf_read&) + 0x2fa 10 engine_srv.so!CNetChan::ProcessPacket(netpacket_s*, bool) + 0x33b 11 engine_srv.so!NET_ProcessSocket(int, IConnectionlessPacketHandler*) + 0x3ae 12 engine_srv.so!CBaseServer::RunFrame() + 0x14f 13 engine_srv.so!SV_Frame(bool) + 0x13e 14 engine_srv.so!_Host_RunFrame_Server(bool) + 0x177 15 engine_srv.so!_Host_RunFrame(float) + 0x441 16 engine_srv.so!Host_RunFrame(float) + 0x248 17 engine_srv.so!CHostState::State_Run(float) + 0xe1 18 engine_srv.so!CHostState::FrameUpdate(float) + 0x9e 19 engine_srv.so!HostState_Frame(float) + 0x19 20 engine_srv.so!CEngine::Frame() + 0x38e 21 engine_srv.so!CDedicatedServerAPI::RunFrame() + 0x26 22 dedicated_srv.so!RunServer() + 0x42 23 engine_srv.so!CModAppSystemGroup::Main() + 0x9d 24 engine_srv.so!CAppSystemGroup::Run() + 0x30 25 engine_srv.so!CDedicatedServerAPI::ModInit(ModInfo_t&) + 0x1df 26 dedicated_srv.so!CDedicatedAppSystemGroup::Main() + 0x93 27 dedicated_srv.so!CAppSystemGroup::Run() + 0x30 28 dedicated_srv.so!CAppSystemGroup::Run() + 0x30 29 dedicated_srv.so!main + 0x1c6 30 srcds_linux + 0x9b9 31 libc-2.17.so + 0x19933 32 ld-2.17.so + 0x14fa0 33 libc-2.17.so + 0x19849 34 ld-2.17.so + 0xf930
не особо понятно, что и как косячит :)
|
|
| |
Nail
|
Дата: Пятница, 10.11.2017, 18:12:03 | Сообщение # 4 |
|
Сообщений: 38
Репутация: 8 [ +/- ]
|
|
Судя по трейсу всё плохо. Следов экстеншинов и самих sourcemod/metamod нету т.е. это или баг самого двига или что-то косвенным образом вызывает краш. Возможно один из плагинов меняет какую-то переменную, которая вызывает сбой при исполнении этой функции или же где-то повреждается память. Функция RemoveEntityReference - часть сетевого модуля, в ней выполняется очистка пакетов энтит, сложно представить что какой-то плагин может внедряться так глубоко в этот модуль.
Код void CFrameSnapshotManager::RemoveEntityReference( PackedEntityHandle_t handle ) { Assert( handle != INVALID_PACKED_ENTITY_HANDLE );
PackedEntity *packedEntity = m_PackedEntities[ handle ];
if ( --packedEntity->m_ReferenceCount <= 0) { AUTO_LOCK_FM( m_WriteMutex );
m_PackedEntities.Remove( handle ); m_PackedEntitiesPool.Free( packedEntity );
// if we have a uncompression cache, remove reference too FOR_EACH_VEC( m_PackedEntityCache, i ) { UnpackedDataCache_t &pdc = m_PackedEntityCache[i]; if ( pdc.pEntity == packedEntity ) { pdc.pEntity = NULL; pdc.counter = 0; break; } } } }
Я бы рекомендовал карантин плагинов с использованием бинарного (логарифмического) разделения плагонов. Т.е.на каждом шаге дробить список оставшихся плагинов на 2 и проверять половины. Если есть знания в области написания экстеншинов, можно подключиться к этой функции и посмотреть что там происходит. Хэндл можно из детоура вынуть (если функция не виртуальная) и оффсет для packedEntity выудить через иду... можно и через саму иду дебажить, но придется мириться с лагами. Впрочем, по этой части у меня мало опыта, может в вашем случае это будет весьма сносный вариант.
Код int __cdecl CFrameSnapshotManager::RemoveEntityReference(int a1, int a2) { int result; // eax@1 unsigned __int8 v3; // zf@1 int v4; // edi@3 int v5; // ecx@6 int v6; // edi@7 int v7; // eax@7 int v8; // edx@8
result = *(_DWORD *)(a2 + 12) - 1; v3 = *(_DWORD *)(a2 + 12) == 1; *(_DWORD *)(a2 + 12) = result; if ( result < 0 | v3 ) { v4 = ThreadGetCurrentId(); if ( v4 == *(_DWORD *)(a1 + 16488) || (unsigned __int8)ThreadInterlockedAssignIf(a1 + 16488, v4, 0) ) { ++*(_DWORD *)(a1 + 16492); } else { _mm_pause(); CThreadFastMutex::Lock(a1 + 16488, v4, 0); } PackedEntity::_PackedEntity(a2); CUtlMemoryPool::Free(a1 + 32, a2); v5 = *(_DWORD *)(a1 + 96); if ( v5 > 0 ) { v6 = *(_DWORD *)(a1 + 84); v7 = 0; if ( *(_DWORD *)v6 == a2 ) { v8 = *(_DWORD *)(a1 + 84); LABEL_13: *(_DWORD *)v8 = 0; *(_DWORD *)(v8 + 4) = 0; } else { while ( 1 ) { ++v7; if ( v7 == v5 ) break; v8 = v6 + 16396 * v7; if ( *(_DWORD *)v8 == a2 ) goto LABEL_13; } } } --*(_DWORD *)(a1 + 16492); result = *(_DWORD *)(a1 + 16492); if ( !result ) result = ThreadInterlockedExchange(a1 + 16488, 0); } return result; }
Псевдокод из иды для CSS, вероятно в GO ситуация особо и не изменилась. Можно по оффсету посмотреть примерно где сбойнул... на глаз это начало функции. Функция не виртуальная и не статическая, подойдет Detour Member Hook
Сообщение отредактировал Nail - Пятница, 10.11.2017, 18:23:36 |
|
| |
|