Skip to content

Server: svMain hangs forever (100% CPU) on uncaught std::bad_any_cast from ServerRPC playerEntity AnyCast (regression in b34629+) #4154

Description

@Pitadart

What happened?

FXServer's svMain thread enters an infinite loop at 100% CPU, repeatedly throwing std::bad_any_cast, and never recovers. txAdmin kills the server after ~60s of missed heartbeats (Loop svMain seems hung!, watchdog stack: root). We captured 10+ occurrences over 6 days on a ~250-slot production server, at player counts from 4 to 199, at random times.

gdb on the live spinning process (breakpoint on __cxa_throw, fires repeatedly):

exception type: St12bad_any_cast
#0 libstdc++.so.6.0.33+0xc5ad0 (__cxa_throw)
#1 libcitizen-server-impl.so+0x3aebbc
#2 libcitizen-server-impl.so+0x3ae1fd
#3 fx::invoker::ScriptNativeContext::Invoke()  (libcitizen-scripting-core.so+0xda52e)
#4+ ~40 frames of libcitizen-scripting-lua.so (Lua VM)

A raw dump of the svMain stack during the spin contains the string literal "playerEntity". A full-heap scan finds no repeated Lua error strings — the exception never reaches script level; the engine re-throws forever.

This is not script load: resmon/profiler captures on the same days show a healthy server — total script time ~6–10% of svMain at 250 players, no resource above normal, no growing tick times before the hang. The transition is binary: one tick healthy, next tick spinning at 100% until killed. We also did elimination testing — stopped/patched several suspected resources over multiple days (guards against calling natives on disconnected players, callback response guards) — the hangs continued regardless, with no correlation to any specific resource.

Source analysis: fx::AnyCast throws std::bad_any_cast on an empty/mismatched client data slot (Client.h:101). GET_PLAYER_PED and MakePlayerEntityFunction.h wrap it in try/catch, but state/ServerRPC.cpp has three uncaught call sites (approx. lines 179, 386, 623 on master):

if (cxtEntity < 0x20000)
{
	auto client = clientRegistry->GetClientByNetID(cxtEntity);
	if (client)
	{
		cxtEntity = fx::AnyCast<uint32_t>(client->GetData("playerEntity"));  // <- uncaught
	}
}

Trigger: a server script calls an RPC native with an entity argument that is a player netID whose client has no playerEntity (player still in connection/character selection, just dropped, or a script passing a player id instead of a ped). The uncaught exception propagates into ScriptNativeContext::Invoke() and svMain never recovers.

Regression window narrowed to one merge: b33864 ran a full week with zero hangs. Hangs started immediately on b34629, whose server-side delta is essentially mr-944 "Update libraries" with commit ae71946 ("feat(lua): updated libraries" — vendor/lua runtime bump + glm/cmsgpack/rapidjson). The follow-up Lua fixes from Aug 19–20 (0a2f63772, 3c1715467) are included in b35265 and did not resolve it. Our theory: the Lua runtime update changed error propagation across the C++/CfxLua boundary, so this pre-existing uncaught throw now loops forever instead of unwinding into a script error.

Expected result

An invalid native call should raise a script error for the calling resource, not hang the entire server at 100% CPU until txAdmin kills it.

Reproduction steps

  1. Run FXServer b34629 or newer (Linux, OneSync, ESX) with real player traffic.
  2. Have a player connected but without a player ped yet (e.g. sitting in a multicharacter selection screen, or mid-connection).
  3. Any server resource calls an RPC (entity) native whose entity argument resolves to that player's netID (< 0x20000) — client->GetData("playerEntity") is emptyfx::AnyCast throws.
  4. svMain spins at 100% CPU throwing std::bad_any_cast forever; txAdmin restarts the server after ~60s. Not reproducible on b33864 (same scripts, same trigger — unwinds as a normal script error there).

Importancy

Crash

Area(s)

FXServer

Specific version(s)

FXServer linux b34629, b34833, b35265 (all affected); b33864 NOT affected (last clean build). Bug present in current master (ServerRPC.cpp unchanged since 2024)

Additional information

Happy to provide full gdb transcripts, eu-stack dumps of the spinning thread, or test a diagnostic build. Adding a try/catch at the three ServerRPC.cpp sites (returning 0 like GET_PLAYER_PED does) would mitigate the symptom even before the unwind regression itself is addressed — the hang is far worse than the original bad call. Related report with matching symptoms but no diagnosis: # 3753

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugcrashtriageNeeds a preliminary assessment to determine the urgency and required action

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions