Skip to content

Fix NPC_PutInVehicle crash when OnPlayerSpawn destroys the vehicle - #1282

Open
r4sheed wants to merge 1 commit into
openmultiplayer:masterfrom
r4sheed:fix/npc-put-in-vehicle-crash
Open

r4sheed wants to merge 1 commit into
openmultiplayer:masterfrom
r4sheed:fix/npc-put-in-vehicle-crash

Conversation

@r4sheed

@r4sheed r4sheed commented Oct 15, 2026

Copy link
Copy Markdown

NPC_PutInVehicle spawns the NPC again if it is not PlayerState_OnFoot. Right after NPC_Spawn the NPC is still PlayerState_Spawned, so it gets spawned a second time and OnPlayerSpawn runs inside the native. If the script destroys the vehicle there, putInVehicle keeps using it.

The crash

Access violation in Vehicles.dll, executing an address that is not code. In the minidump the vehicle's vtable pointer is already IExtensible::vftable (its destructor has run), so vehicle.getModel() at npc.cpp:1556 jumps into data.

NPC::respawn can hit the same thing: it keeps the vehicle pointer across its own PlayerSpawn RPC, which also runs OnPlayerSpawn.

Without the destroy it does not crash, but OnPlayerSpawn still runs twice and the second spawn resets health, armour and weapon.

Repro

Crashes every time on 3d20f3d:

new gVehicle = INVALID_VEHICLE_ID;

public OnPlayerSpawn(playerid)
{
    if (IsPlayerNPC(playerid) && gVehicle != INVALID_VEHICLE_ID)
    {
        DestroyVehicle(gVehicle);
        gVehicle = INVALID_VEHICLE_ID;
    }
    return 1;
}

public OnGameModeInit()
{
    new npc = NPC_Create("crash_npc");
    NPC_Spawn(npc);
    gVehicle = CreateVehicle(411, 0.0, 0.0, 3.0, 0.0, -1, -1, -1);
    NPC_PutInVehicle(npc, gVehicle, 0);
    return 1;
}

Fix

  • PlayerState_Spawned counts as spawned, so there is no second spawn.
  • When a spawn still happens (dead NPC, or one already in another vehicle), check that the vehicle is still in the pool afterwards and return false if it is not. respawn does the same check.
  • NPC_PutInVehicle (Pawn and CAPI) returns the real result instead of always true.

Tested

Windows, RelWithDebInfo, same tree before and after:

Case Before After
Repro above crash OnPlayerSpawn once, NPC seated
NPC_Spawn, set weapon and health, NPC_PutInVehicle OnPlayerSpawn twice, weapon and health reset OnPlayerSpawn once, weapon and health kept
NPC_Respawn while seated, OnPlayerSpawn destroys the vehicle crash NPC stays on foot
NPC in one vehicle, put into another, OnPlayerSpawn destroys the second crash returns false, NPC not seated

A freshly spawned NPC was spawned again inside NPC_PutInVehicle, so
OnPlayerSpawn ran twice and could delete the vehicle mid-call.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant