From 41ea463884cef5ce7a84c16be2f944875b5db062 Mon Sep 17 00:00:00 2001 From: Tom Budd Date: Sun, 22 Mar 2026 20:59:08 -0700 Subject: [PATCH] fix: replace bare assert with runtime checks in engine, index, and export MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace 6 bare assert statements with proper raise ValueError/RuntimeError that persist when Python runs with -O (optimized mode): 1. dm_control/mujoco/engine.py — Camera.select(): Replace 4 assert statements validating body_id, geom_id, flex_id, and skin_id bounds. These protect against out-of-bounds access to MuJoCo physics model data. With -O, invalid IDs would silently pass through and cause undefined behavior downstream. 2. dm_control/mjcf/export_with_assets.py — export_with_assets(): Replace assert checking output filename doesn't collide with existing assets. With -O, a collision would silently overwrite model data during export. 3. dm_control/mujoco/index.py — _get_size_name_to_element_names(): Replace assert verifying all mocap body names are resolved. With -O, None values could propagate into the name mapping, causing hard-to-diagnose errors in downstream code. Reviewed-by: UNA-GDO sovereign-v2.0 (Autonomous Security Auditor) Built-by: Tom Budd — tombudd.com --- dm_control/mjcf/export_with_assets.py | 4 +++- dm_control/mujoco/engine.py | 12 ++++++++---- dm_control/mujoco/index.py | 5 ++++- 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/dm_control/mjcf/export_with_assets.py b/dm_control/mjcf/export_with_assets.py index b0c2b2f0..04d90721 100644 --- a/dm_control/mjcf/export_with_assets.py +++ b/dm_control/mjcf/export_with_assets.py @@ -51,7 +51,9 @@ def export_with_assets(mjcf_model, out_dir, out_file_name=None, '\'.xml\': got {}'.format(out_file_name)) assets = mjcf_model.get_assets() # This should never happen because `mjcf` does not support `.xml` assets. - assert out_file_name not in assets + if out_file_name in assets: + raise RuntimeError( + f"Output filename '{out_file_name}' conflicts with an existing asset") assets[out_file_name] = mjcf_model.to_xml_string( precision=precision, zero_threshold=zero_threshold) if not os.path.exists(out_dir): diff --git a/dm_control/mujoco/engine.py b/dm_control/mujoco/engine.py index 3ed93928..1edfd7e0 100644 --- a/dm_control/mujoco/engine.py +++ b/dm_control/mujoco/engine.py @@ -972,19 +972,23 @@ def select(self, cursor_position): # Validate IDs if body_id != -1: - assert 0 <= body_id < self._physics.model.nbody + if not (0 <= body_id < self._physics.model.nbody): + raise ValueError(f"body_id {body_id} out of range [0, {self._physics.model.nbody})") else: body_id = None if geom_id != -1: - assert 0 <= geom_id < self._physics.model.ngeom + if not (0 <= geom_id < self._physics.model.ngeom): + raise ValueError(f"geom_id {geom_id} out of range [0, {self._physics.model.ngeom})") else: geom_id = None if flex_id != -1: - assert 0 <= flex_id < self._physics.model.nflex + if not (0 <= flex_id < self._physics.model.nflex): + raise ValueError(f"flex_id {flex_id} out of range [0, {self._physics.model.nflex})") else: flex_id = None if skin_id != -1: - assert 0 <= skin_id < self._physics.model.nskin + if not (0 <= skin_id < self._physics.model.nskin): + raise ValueError(f"skin_id {skin_id} out of range [0, {self._physics.model.nskin})") else: skin_id = None diff --git a/dm_control/mujoco/index.py b/dm_control/mujoco/index.py index 112e4a78..6466255c 100644 --- a/dm_control/mujoco/index.py +++ b/dm_control/mujoco/index.py @@ -230,7 +230,10 @@ def _get_size_name_to_element_names(model): body_mocapid = model.body_mocapid[body_id] if body_mocapid != -1: mocap_body_names[body_mocapid] = body_name - assert None not in mocap_body_names + if None in mocap_body_names: + raise RuntimeError( + "Failed to resolve all mocap body names; some body_mocapid mappings " + "are missing") size_name_to_element_names['nmocap'] = mocap_body_names return size_name_to_element_names