diff --git a/doc/APIreference/APItypes.rst b/doc/APIreference/APItypes.rst index eda4dc70..355eb3a7 100644 --- a/doc/APIreference/APItypes.rst +++ b/doc/APIreference/APItypes.rst @@ -1871,7 +1871,10 @@ mjfOpenResource typedef int (*mjfOpenResource)(mjResource* resource); -This callback is for opening a resource; returns zero on failure. +This callback is for opening a resource; returns zero on failure. Note that +if this callback returns zero, the ``close`` callback will not be called. +Therefore, the ``open`` callback is responsible for cleaning up any allocated +memory or resources before returning zero to avoid memory leaks. .. _mjfReadResource: diff --git a/include/mujoco/mjplugin.h b/include/mujoco/mjplugin.h index a0ee0076..e1656d34 100644 --- a/include/mujoco/mjplugin.h +++ b/include/mujoco/mjplugin.h @@ -33,7 +33,10 @@ struct mjResource_ { }; typedef struct mjResource_ mjResource; -// callback for opening a resource, returns zero on failure +// callback for opening a resource, returns zero on failure. +// Note: If opening fails, the close callback will not be called. Therefore, the +// open callback is responsible for cleaning up any allocated memory before +// returning 0. typedef int (*mjfOpenResource)(mjResource* resource); // callback for reading a resource diff --git a/python/mujoco/experimental/studio/native_viewer.cc b/python/mujoco/experimental/studio/native_viewer.cc index 71d6cf51..3cc587d4 100644 --- a/python/mujoco/experimental/studio/native_viewer.cc +++ b/python/mujoco/experimental/studio/native_viewer.cc @@ -79,6 +79,10 @@ class Viewer { resource_provider.open = [](mjResource* resource) { auto* data = new ResourceData(); data->bytes = LoadAsset(resource->name); + if (data->bytes.empty()) { + delete data; + return 0; + } resource->data = data; return static_cast(data->bytes.size()); }; @@ -135,9 +139,7 @@ class Viewer { bytes_per_pixel); } - std::string GetDropFile() { - return window_->GetDropFile(); - } + std::string GetDropFile() { return window_->GetDropFile(); } void Present(const mujoco::python::MjModelWrapper& model, mujoco::python::MjDataWrapper& data, diff --git a/src/experimental/studio/main.cc b/src/experimental/studio/main.cc index ca84aa4f..c6bc03e8 100644 --- a/src/experimental/studio/main.cc +++ b/src/experimental/studio/main.cc @@ -84,6 +84,10 @@ int main(int argc, char** argv, char** envp) { resource_provider.open = [](mjResource* resource) { const std::string resolved_path = Resolve(resource->name); FileResource* f = new FileResource(resolved_path); + if (f->Size() == 0) { + delete f; + return 0; + } resource->data = f; return f->Size(); };