Fix VFS use-after-move crash by using stable handles for mjVFS

Root cause: resources and default mount stored pointers tied to the public mjVFS object address. If mjVFS was moved after initialization, resource close/read paths could dereference stale pointers and crash.\n\nThis change stores a stable internal mjVFS handle inside VFS and points resources/default mount to that stable handle. It also tracks the current public owner pointer and rebinds it in Upcast so lifecycle operations (including self-destruct cleanup) target the current mjVFS address after moves.\n\nAdds regression test UserVfsTest.MoveVfsAfterOpenResource, which opens a resource, moves mjVFS, then reads/closes/deletes successfully.
This commit is contained in:
Nandini Dhanrale
2026-02-16 12:40:13 +05:30
parent 881544c0c5
commit c45f13d3a9
3 changed files with 49 additions and 7 deletions
+24
View File
@@ -15,6 +15,7 @@
#include <array>
#include <cstdio>
#include <string>
#include <utility>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
@@ -286,6 +287,29 @@ TEST_F(UserVfsTest, Timestamps) {
mj_deleteVFS(&vfs);
}
TEST_F(UserVfsTest, MoveVfsAfterOpenResource) {
mjVFS vfs;
mj_defaultVFS(&vfs);
std::string buffer = "<mujoco/>";
mj_addBufferVFS(&vfs, "model", static_cast<const void*>(buffer.c_str()),
buffer.size());
mjResource* resource = mju_openResource("", "model", &vfs, nullptr, 0);
ASSERT_THAT(resource, NotNull());
// Move the public mjVFS object after resources have been opened.
mjVFS moved = std::move(vfs);
const void* out = nullptr;
const int size = mju_readResource(resource, &out);
EXPECT_GT(size, 0);
EXPECT_THAT(out, NotNull());
mju_closeResource(resource);
mj_deleteVFS(&moved);
}
TEST_F(UserVfsTest, MountUnmount) {
int test = 0;
int expect = 0;