6.4 KiB
CRITICAL: Resurrection System Crash Analysis
Date: 2025-10-30 15:35:18
Severity: CRITICAL - Production Blocker
Status: REGRESSION - New bug introduced by direct resurrection changes
Crash Summary
- Crash Rate: 1 crash after 27 successful resurrections (15 minutes runtime, 100 bots)
- Production Impact: UNACCEPTABLE - Server cannot run stably
- Assertion Failed:
Unit.cpp:10863 - ASSERT(m_procDeep)inUnit::SetCantProc()
What Happened
- ✅ Bot "Cathrine" resurrected successfully via
ResurrectPlayer(0.5f, false) - ✅ Health/Mana restored (119/238 HP, 180/360 Mana)
- ✅ Death recovery transitioned to state 0 (NOT_DEAD)
- ❌ CRASH during post-resurrection zone update:
ResurrectPlayer()→UpdateZone()→UpdateAreaDependentAuras()- Zone change spell cast → Proc system triggered
m_procDeepcounter became zero whenSetCantProc(false)expected non-zero- Assertion failure → Server crash
Call Stack
Player::ResurrectPlayer (line 4407)
└─> Player::UpdateZone
└─> Player::UpdateArea
└─> Player::UpdateAreaDependentAuras
└─> WorldObject::CastSpell (zone aura)
└─> Unit::ProcSkillsAndAuras
└─> Unit::TriggerAurasProcOnEvent
└─> Unit::SetCantProc [CRASH]
└─> ASSERT(m_procDeep) FAILED
Root Cause Analysis
The Proc Depth Counter (m_procDeep)
TrinityCore uses m_procDeep to track spell proc recursion depth:
SetCantProc(true)→++m_procDeep(increment before procs)SetCantProc(false)→--m_procDeep(decrement after procs)- Assertion: When decrementing,
m_procDeepmust be > 0
Why It Failed
The counter became unbalanced during resurrection:
- Some code path called
SetCantProc(true)without matchingSetCantProc(false) - OR: Some code path called
SetCantProc(false)too many times - Result: Counter reached zero, next
SetCantProc(false)→ assertion failure
Possible Causes
- Thread Safety Issue:
ResurrectPlayer()called from bot worker thread may have race conditions with proc counter - State Transition Bug: Resurrection may not properly clean up pending proc states
- Zone Update Bug: Area-dependent aura application during resurrection triggers unexpected proc chains
- Pre-existing TrinityCore Bug: Exposed by our specific resurrection code path
Changes That Introduced This
Before (Packet-Based - STABLE)
// Old approach: Send CMSG_RECLAIM_CORPSE packet
WorldPacket packet(CMSG_RECLAIM_CORPSE);
packet << m_bot->GetGUID();
m_bot->GetSession()->HandleReclaimCorpseOpcode(packet);
- Processed on main thread via packet handler
- Full TrinityCore validation path
- No crashes observed
After (Direct API - UNSTABLE)
// New approach: Direct API call from worker thread
m_bot->ResurrectPlayer(0.5f, false);
m_bot->SpawnCorpseBones();
- Called directly from bot worker thread (BotSession mutex protected)
- Bypasses packet handler validation
- Crashes with m_procDeep assertion
Success Before Crash
- ✅ 27 successful resurrections
- ✅ 100% resurrection success rate
- ✅ No "Resurrection did not complete" failures
- ✅ Direct resurrection DOES work
- ❌ BUT: Server crashes after ~15 minutes
Production Impact
This is a CRITICAL REGRESSION:
- Old system: Stable, no crashes (but had other issues)
- New system: Works but crashes server periodically
- Cannot be deployed to production
Investigation Needed
- ✅ Check if old packet approach had same crash → User confirms this is NEW
- ❌ Investigate thread safety of
ResurrectPlayer()from worker thread - ❌ Check if we need to call additional cleanup before/after resurrection
- ❌ Review TrinityCore's packet handler for missing state management
- ❌ Consider wrapping resurrection in main thread dispatch
Potential Fixes (Priority Order)
Option 1: Dispatch ResurrectPlayer to Main Thread
// Queue resurrection to execute on main thread instead of worker thread
m_bot->GetMap()->AddToWorld([bot = m_bot]() {
bot->ResurrectPlayer(0.5f, false);
bot->SpawnCorpseBones();
});
Pros: Matches TrinityCore's threading model
Cons: Adds complexity, may have timing issues
Option 2: Add Proc State Cleanup
// Clear proc state before resurrection
m_bot->RemoveAllAuras(); // Clear all auras including proc-triggering ones
m_bot->ResurrectPlayer(0.5f, false);
m_bot->SpawnCorpseBones();
Pros: Simple, might fix proc counter issues
Cons: May be too aggressive, could break other systems
Option 3: Revert to Packet-Based Approach
// Use packet approach but with proper threading
// Queue packet to be processed on main thread
Pros: Known stable approach
Cons: Defeats purpose of direct API usage
Option 4: Wrap ResurrectPlayer in Proc Guards
// Manually manage proc depth
bool hadProcs = m_bot->IsProcsActive();
m_bot->SetCantProc(true); // Prevent procs during resurrection
m_bot->ResurrectPlayer(0.5f, false);
m_bot->SetCantProc(false); // Re-enable procs
m_bot->SpawnCorpseBones();
Pros: Surgical fix for specific issue
Cons: May not address root cause
Next Steps
- Identify exact condition causing
m_procDeepimbalance - Test if packet-based approach had this issue (user says NO)
- Implement thread-safe resurrection (Option 1 most promising)
- Add comprehensive proc state logging for debugging
- Stress test with 100+ bots for extended periods
Related Files
DeathRecoveryManager.cpp:598- Direct resurrection callPlayer.cpp:4407- ResurrectPlayer() implementationUnit.cpp:10863- SetCantProc() assertionUnit.cpp:10437-10577- Proc system implementation
Crash Dumps
- Latest:
3f33f776e3ba+_worldserver.exe_[2025_10_30_15_35_18].txt - Previous:
3f33f776e3ba+_worldserver.exe_[2025_10_30_15_17_39].txt(Freeze detector) - Previous:
3f33f776e3ba+_worldserver.exe_[2025_10_30_13_36_1].txt(Ghost aura assertion)
Conclusion
The direct ResurrectPlayer() approach works functionally but has critical stability issues that make it unsuitable for production. We need to either:
- Fix the thread safety/proc state issues
- OR revert to a modified packet-based approach
- OR find TrinityCore's intended resurrection API path
Status: Blocking production deployment until resolved.