Skip to content

fix(physics): jolt static vectors being freed#1418

Open
Dhruv-0-Arora wants to merge 3 commits into
devfrom
darora1/252/free-jolt-vectors
Open

fix(physics): jolt static vectors being freed#1418
Dhruv-0-Arora wants to merge 3 commits into
devfrom
darora1/252/free-jolt-vectors

Conversation

@Dhruv-0-Arora

@Dhruv-0-Arora Dhruv-0-Arora commented Jul 16, 2026

Copy link
Copy Markdown
Collaborator

Task

Jolt.Vec3 is stored in heap but
anything a bound method returns by value (Normalized(), AddRVec3(), Add()) is not allocated. the binding keeps one static per method.

How it looks:

Vec3* emscripten_bind_Vec3_Normalized_0(Vec3* self) {
    static Vec3 temp;             // one slot, reused forever
    temp = self->Normalized();    // 16 bytes overwritten, no malloc
    return &temp;
}

So, we instead will copy the values from this memory and store it in a heap allocated Jolt.Vec3 for safer memory management. This means, however, that these Jolt.Vec3 s will need to be Jolt.destroy(x) ed.

Symptom

createAnchorPoint returned jointOrigin.AddRVec3(...) straight through, so callers got a static temp. PhysicsSystem freed it in four places: two JOLT.destroy(anchorPoint) on the ball constraint path, and two convertJoltRVec3ToJoltVec3(anchorPoint) whose destroy param defaults to true.

the function JOLT.getPointer() shows that AddRVec3 returns 54992 every call, malloc's block (heap) starts around 1157600. all four were freeing a data segment address (meaning they did nothing).

In addition

settings members are declared by value (RVec3 mPoint1;), so setters memcpy and the struct never takes ownership. JOLT.destroy(settings) won't free a vector you assigned in, but you can destroy it yourself right after assigning. we were dropping wheelPos, the four urdfWheelBasis vectors, and minBounds/maxBounds.

Solution

  1. new ownVec3/ownRVec3 helpers so no static escapes the expression that made it. createAnchorPoint and getPerpendicular now return owned heap vectors
  2. destroy the leaks above, plus anchorPoint now that it's real memory
  3. JoltOwnership.test.ts pins down both halves: fresh address per malloc, recycling on destroy, the static below the heap, 2000 calls yielding one address, the clobber, and structs copying bytes in

testing

JoltOwnership.test.ts passes in chromium + firefox

Bound methods that return a vector by value (`Normalized()`, `AddRVec3()`)
do not allocate. Emscripten's binding writes into one fixed static per
method and hands back that address, so the result is only valid until the
next call to the same method, and `JOLT.destroy` on one runs `free()` on an
address `malloc` never issued.

`createAnchorPoint` returned `jointOrigin.AddRVec3(jointOriginOffset)`
straight through, so every caller was handed a static. `PhysicsSystem` then
freed it in four places: two bare `JOLT.destroy(anchorPoint)` calls on the
ball constraint path, and two `convertJoltRVec3ToJoltVec3(anchorPoint)`
calls whose `destroy` parameter defaults to true. Each one asked dlmalloc to
reclaim a data segment address it has no record of.

Add `ownVec3`/`ownRVec3` and use them so no static escapes the expression
that produced it. `createAnchorPoint` and `getPerpendicular` now return heap
vectors the caller owns, which is what makes those frees legal.
Settings structs declare their vector members by value, so assigning into
one memcpys the bytes in and the struct never takes ownership. Destroying
the settings does not free the source vector, which means every `new
JOLT.Vec3` and `convert*` result assigned into settings is still ours.

Several were dropped instead: `wheelPos`, the four `urdfWheelBasis` vectors
from `inferURDFAutoWheelBasis`, and `minBounds`/`maxBounds`. These run at
joint and body creation rather than per frame, so the leak is bounded by
spawns and is small in absolute terms, but it is unreclaimed all the same.

Destroying `anchorPoint` is only valid because `createAnchorPoint` now
returns a real allocation.
Ownership depends on where a vector came from, and that is not visible in
any signature. These tests make the two cases concrete: `new JOLT.Vec3` is a
real `malloc` that hands out a fresh address each time and recycles it on
destroy, while a bound method's return value is one fixed static that sits
below malloc's block, survives 2000 calls without accumulating, and is
clobbered by the next call.

Also covers the struct-copies-the-bytes-in rule that the destroys in
`PhysicsSystem` depend on, and checks that `getPerpendicular` copies out of
the static so callers get distinct heap vectors.
@Dhruv-0-Arora Dhruv-0-Arora self-assigned this Jul 16, 2026
@Dhruv-0-Arora
Dhruv-0-Arora requested review from a team as code owners July 16, 2026 17:30
@Dhruv-0-Arora
Dhruv-0-Arora requested review from 0xda157, BrandonPacewic, PepperLola, azaleacolburn and rutmanz and removed request for 0xda157 July 16, 2026 17:30
Comment thread fission/src/systems/physics/ConstraintSettingsUtilities.ts
Comment thread fission/src/systems/physics/ConstraintSettingsUtilities.ts
import JOLT from "@/util/loading/JoltSyncLoader"

/**
* what you have to destroy and why

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

holy claude

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

... that was me?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

okay

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry if it was unclear :( @azaleacolburn

Comment thread fission/src/test/physics/JoltOwnership.test.ts
Comment thread fission/src/test/physics/JoltOwnership.test.ts
Comment thread fission/src/test/physics/JoltOwnership.test.ts
@azaleacolburn

Copy link
Copy Markdown
Contributor

Also could you not write your pr descriptions with claude please, it's just like a really annoying style

@azaleacolburn

Copy link
Copy Markdown
Contributor

Also, please use the pr description template in the future

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.

2 participants