Skip to content

Fix client crash from DX primitive argument error leaks#5050

Open
HeresHavi wants to merge 1 commit into
multitheftauto:masterfrom
HeresHavi:fix-dx-primitive-error-crash
Open

Fix client crash from DX primitive argument error leaks#5050
HeresHavi wants to merge 1 commit into
multitheftauto:masterfrom
HeresHavi:fix-dx-primitive-error-crash

Conversation

@HeresHavi

@HeresHavi HeresHavi commented Jul 13, 2026

Copy link
Copy Markdown

Summary

Fixed native memory leaks on argument errors in:

  • dxDrawPrimitive
  • dxDrawPrimitive3D
  • dxDrawMaterialPrimitive
  • dxDrawMaterialPrimitive3D

Temporary parsing allocations and the heap-owned vertex vector are now released before the Lua error is raised. Valid drawing calls and their ownership flow remain unchanged.

Motivation

Lua uses longjmp when raising errors, which skips C++ destructors. The primitive functions raised an error while their temporary number vector was still alive and without deleting the heap vertex vector.

For example, a resource might leave a malformed dxDrawPrimitive call inside onClientRender. MTA catches the Lua error, so the render handler continues running and repeats the same leaking call every frame. Over time, this could exhaust the 32-bit client's address space and terminate the player with an Out of Memory error.

Crash Stack
Exception Type: User:OutOfMemory
Exception: Out of Memory - Allocation Failure
Fatal Exception: Yes
Reason: Out of Memory - Allocation Failure
Location: KERNELBASE.dll!RaiseException
Crash Out of memory dialog

Test plan

Runtime

  • Valid Case: A normal two-vertex dxDrawPrimitive call returned true before and after the fix.
  • Error Case: The malformed call continued to report Expected table with 2 or 3 numbers, got 4 numbers.
  • Before Fix: Private memory increased from about 503.1 MiB to 540.1 MiB after two batches of 512 malformed calls.
  • Before Fix: One 65,536-call batch increased private memory to about 2953.3 MiB. A second batch exhausted the client and caused the fatal out-of-memory crash.
  • After Fix: Three 512-call batches completed while private memory remained around 515.2 MiB.
  • Stress Case: Ten 65,536-call batches completed all 655360 calls. The client stayed responsive and settled at about 521.2 MiB private memory.

Builds and Tests

  • Debug | Win32: Client Deathmatch build passed.
  • Release | Win32: Client Deathmatch build passed.
  • Ran clang-format.

Checklist

  • Your code should follow the coding guidelines.
  • Smaller pull requests are easier to review. If your pull request is beefy, your pull request should be reviewable commit-by-commit.

Release primitive parsing and vertex allocations before raising Lua errors, preventing malformed primitive drawing calls from exhausting client memory.
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