Compile-time size assertions for MuJoCo basic types

PiperOrigin-RevId: 919107499
Change-Id: I07fcba4f33c77a2a1e68528dba6d399af94d0220
This commit is contained in:
Yuval Tassa
2026-05-21 09:54:33 -07:00
committed by Copybara-Service
parent 585be6cee5
commit 15d27b363f
7 changed files with 145 additions and 54 deletions
+1
View File
@@ -108,6 +108,7 @@ include(MujocoMacOS)
include(MujocoDependencies) include(MujocoDependencies)
set(MUJOCO_HEADERS set(MUJOCO_HEADERS
include/mujoco/mjassert.h
include/mujoco/mjdata.h include/mujoco/mjdata.h
include/mujoco/mjexport.h include/mujoco/mjexport.h
include/mujoco/mjmacro.h include/mujoco/mjmacro.h
+6
View File
@@ -80,6 +80,12 @@ General
- MJX: Removed the deprecated ``nconmax`` argument from ``mjx.make_data`` and ``mjx.put_data`` in favor of - MJX: Removed the deprecated ``nconmax`` argument from ``mjx.make_data`` and ``mjx.put_data`` in favor of
``naconmax``. ``naconmax``.
- Maybe-breaking: Added `mjassert.h
<https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjassert.h>`__, a new header containing
compile-time assertions that verify the sizes of MuJoCo's public types for ABI stability. This is a first step
towards replacing ``int`` with strongly-typed enums in the public API. If these assertions fail on your compiler or
platform, please report the issue on GitHub.
Version 3.8.1 (May 11, 2026) Version 3.8.1 (May 11, 2026)
---------------------------- ----------------------------
+2
View File
@@ -184,6 +184,8 @@ links below, to make this documentation self-contained.
code. code.
`mjsan.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjsan.h>`__ `mjsan.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjsan.h>`__
Definitions required when building with sanitizer instrumentation. Definitions required when building with sanitizer instrumentation.
`mjassert.h <https://github.com/google-deepmind/mujoco/blob/main/include/mujoco/mjassert.h>`__
Compile-time size assertions verifying MuJoCo ABI stability across C and C++ compilers.
.. _inVersion: .. _inVersion:
+133
View File
@@ -0,0 +1,133 @@
// Copyright 2026 DeepMind Technologies Limited
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#ifndef MUJOCO_MJASSERT_H_
#define MUJOCO_MJASSERT_H_
#include <mujoco/mjdata.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjplugin.h>
#include <mujoco/mjrender.h>
#include <mujoco/mjspec.h>
#include <mujoco/mjthread.h>
#include <mujoco/mjtype.h>
#include <mujoco/mjui.h>
#include <mujoco/mjvisualize.h>
#if defined(__cplusplus)
#define MJ_ASSERT_SIZE(type, size) \
static_assert(sizeof(type) == (size), #type " must be " #size " bytes for MuJoCo ABI stability")
#elif defined(__STDC_VERSION__) && __STDC_VERSION__ >= 201112L
#define MJ_ASSERT_SIZE(type, size) \
_Static_assert(sizeof(type) == (size), #type " must be " #size " bytes for MuJoCo ABI stability")
#else
#define MJ_ASSERT_SIZE(type, size) \
typedef char mj_assert_##type[sizeof(type) == (size) ? 1 : -1]
#endif
// mjtnum.h
MJ_ASSERT_SIZE(mjtByte, 1);
MJ_ASSERT_SIZE(mjtSize, 8);
#if !defined(mjUSESINGLE)
MJ_ASSERT_SIZE(mjtNum, 8);
#else
MJ_ASSERT_SIZE(mjtNum, 4);
#endif
// mjmodel.h
MJ_ASSERT_SIZE(mjtDisableBit, 4);
MJ_ASSERT_SIZE(mjtEnableBit, 4);
MJ_ASSERT_SIZE(mjtJoint, 4);
MJ_ASSERT_SIZE(mjtGeom, 4);
MJ_ASSERT_SIZE(mjtProjection, 4);
MJ_ASSERT_SIZE(mjtCamLight, 4);
MJ_ASSERT_SIZE(mjtLightType, 4);
MJ_ASSERT_SIZE(mjtTexture, 4);
MJ_ASSERT_SIZE(mjtTextureRole, 4);
MJ_ASSERT_SIZE(mjtColorSpace, 4);
MJ_ASSERT_SIZE(mjtIntegrator, 4);
MJ_ASSERT_SIZE(mjtCone, 4);
MJ_ASSERT_SIZE(mjtJacobian, 4);
MJ_ASSERT_SIZE(mjtSolver, 4);
MJ_ASSERT_SIZE(mjtEq, 4);
MJ_ASSERT_SIZE(mjtWrap, 4);
MJ_ASSERT_SIZE(mjtTrn, 4);
MJ_ASSERT_SIZE(mjtDyn, 4);
MJ_ASSERT_SIZE(mjtGain, 4);
MJ_ASSERT_SIZE(mjtBias, 4);
MJ_ASSERT_SIZE(mjtObj, 4);
MJ_ASSERT_SIZE(mjtSensor, 4);
MJ_ASSERT_SIZE(mjtStage, 4);
MJ_ASSERT_SIZE(mjtDataType, 4);
MJ_ASSERT_SIZE(mjtConDataField, 4);
MJ_ASSERT_SIZE(mjtRayDataField, 4);
MJ_ASSERT_SIZE(mjtCamOutBit, 4);
MJ_ASSERT_SIZE(mjtSameFrame, 4);
MJ_ASSERT_SIZE(mjtSleepPolicy, 4);
MJ_ASSERT_SIZE(mjtLRMode, 4);
MJ_ASSERT_SIZE(mjtFlexSelf, 4);
MJ_ASSERT_SIZE(mjtSDFType, 4);
// mjdata.h
MJ_ASSERT_SIZE(mjtState, 4);
MJ_ASSERT_SIZE(mjtConstraint, 4);
MJ_ASSERT_SIZE(mjtConstraintState, 4);
MJ_ASSERT_SIZE(mjtWarning, 4);
MJ_ASSERT_SIZE(mjtTimer, 4);
MJ_ASSERT_SIZE(mjtSleepState, 4);
// mjspec.h
MJ_ASSERT_SIZE(mjtGeomInertia, 4);
MJ_ASSERT_SIZE(mjtMeshInertia, 4);
MJ_ASSERT_SIZE(mjtMeshBuiltin, 4);
MJ_ASSERT_SIZE(mjtBuiltin, 4);
MJ_ASSERT_SIZE(mjtMark, 4);
MJ_ASSERT_SIZE(mjtLimited, 4);
MJ_ASSERT_SIZE(mjtAlignFree, 4);
MJ_ASSERT_SIZE(mjtInertiaFromGeom, 4);
MJ_ASSERT_SIZE(mjtOrientation, 4);
// mjvisualize.h
MJ_ASSERT_SIZE(mjtCatBit, 4);
MJ_ASSERT_SIZE(mjtMouse, 4);
MJ_ASSERT_SIZE(mjtPertBit, 4);
MJ_ASSERT_SIZE(mjtCamera, 4);
MJ_ASSERT_SIZE(mjtLabel, 4);
MJ_ASSERT_SIZE(mjtFrame, 4);
MJ_ASSERT_SIZE(mjtVisFlag, 4);
MJ_ASSERT_SIZE(mjtRndFlag, 4);
MJ_ASSERT_SIZE(mjtStereo, 4);
// mjrender.h
MJ_ASSERT_SIZE(mjtGridPos, 4);
MJ_ASSERT_SIZE(mjtFramebuffer, 4);
MJ_ASSERT_SIZE(mjtDepthMap, 4);
MJ_ASSERT_SIZE(mjtFontScale, 4);
MJ_ASSERT_SIZE(mjtFont, 4);
// mjui.h
MJ_ASSERT_SIZE(mjtButton, 4);
MJ_ASSERT_SIZE(mjtEvent, 4);
MJ_ASSERT_SIZE(mjtItem, 4);
MJ_ASSERT_SIZE(mjtSection, 4);
// mjthread.h
MJ_ASSERT_SIZE(mjtTaskStatus, 4);
// mjplugin.h
MJ_ASSERT_SIZE(mjtPluginCapabilityBit, 4);
#undef MJ_ASSERT_SIZE
#endif // MUJOCO_MJASSERT_H_
+1
View File
@@ -35,6 +35,7 @@
#include <mujoco/mjtype.h> #include <mujoco/mjtype.h>
#include <mujoco/mjui.h> #include <mujoco/mjui.h>
#include <mujoco/mjvisualize.h> #include <mujoco/mjvisualize.h>
#include <mujoco/mjassert.h>
// this is a C-API // this is a C-API
#ifdef __cplusplus #ifdef __cplusplus
+1 -54
View File
@@ -21,12 +21,7 @@
#include <vector> #include <vector>
#include <gtest/gtest.h> #include <gtest/gtest.h>
#include <mujoco/mjdata.h> #include <mujoco/mujoco.h>
#include <mujoco/mjmodel.h>
#include <mujoco/mjrender.h>
#include <mujoco/mjtype.h>
#include <mujoco/mjui.h>
#include <mujoco/mjvisualize.h>
#include <mujoco/mjxmacro.h> #include <mujoco/mjxmacro.h>
#include "test/fixture.h" #include "test/fixture.h"
@@ -58,59 +53,11 @@ void CheckAddressOrdering(
using HeaderTest = MujocoTest; using HeaderTest = MujocoTest;
TEST_F(HeaderTest, IntsHave4Bytes) {
EXPECT_EQ(4, sizeof(int));
}
TEST_F(HeaderTest, IntsHaveAtLeast31Bits) { TEST_F(HeaderTest, IntsHaveAtLeast31Bits) {
int shift_left_30 = 1 << 30; int shift_left_30 = 1 << 30;
EXPECT_GT(shift_left_30, 0); EXPECT_GT(shift_left_30, 0);
} }
TEST_F(HeaderTest, EnumsAreInts) {
EXPECT_EQ(sizeof(mjtDisableBit), sizeof(int));
EXPECT_EQ(sizeof(mjtEnableBit), sizeof(int));
EXPECT_EQ(sizeof(mjtJoint), sizeof(int));
EXPECT_EQ(sizeof(mjtGeom), sizeof(int));
EXPECT_EQ(sizeof(mjtCamLight), sizeof(int));
EXPECT_EQ(sizeof(mjtTexture), sizeof(int));
EXPECT_EQ(sizeof(mjtIntegrator), sizeof(int));
EXPECT_EQ(sizeof(mjtCone), sizeof(int));
EXPECT_EQ(sizeof(mjtJacobian), sizeof(int));
EXPECT_EQ(sizeof(mjtSolver), sizeof(int));
EXPECT_EQ(sizeof(mjtEq), sizeof(int));
EXPECT_EQ(sizeof(mjtWrap), sizeof(int));
EXPECT_EQ(sizeof(mjtTrn), sizeof(int));
EXPECT_EQ(sizeof(mjtDyn), sizeof(int));
EXPECT_EQ(sizeof(mjtGain), sizeof(int));
EXPECT_EQ(sizeof(mjtBias), sizeof(int));
EXPECT_EQ(sizeof(mjtObj), sizeof(int));
EXPECT_EQ(sizeof(mjtConstraint), sizeof(int));
EXPECT_EQ(sizeof(mjtConstraintState), sizeof(int));
EXPECT_EQ(sizeof(mjtSensor), sizeof(int));
EXPECT_EQ(sizeof(mjtStage), sizeof(int));
EXPECT_EQ(sizeof(mjtDataType), sizeof(int));
EXPECT_EQ(sizeof(mjtLRMode), sizeof(int));
EXPECT_EQ(sizeof(mjtWarning), sizeof(int));
EXPECT_EQ(sizeof(mjtTimer), sizeof(int));
EXPECT_EQ(sizeof(mjtGridPos), sizeof(int));
EXPECT_EQ(sizeof(mjtFramebuffer), sizeof(int));
EXPECT_EQ(sizeof(mjtFontScale), sizeof(int));
EXPECT_EQ(sizeof(mjtFont), sizeof(int));
EXPECT_EQ(sizeof(mjtButton), sizeof(int));
EXPECT_EQ(sizeof(mjtEvent), sizeof(int));
EXPECT_EQ(sizeof(mjtItem), sizeof(int));
EXPECT_EQ(sizeof(mjtCatBit), sizeof(int));
EXPECT_EQ(sizeof(mjtMouse), sizeof(int));
EXPECT_EQ(sizeof(mjtPertBit), sizeof(int));
EXPECT_EQ(sizeof(mjtCamera), sizeof(int));
EXPECT_EQ(sizeof(mjtLabel), sizeof(int));
EXPECT_EQ(sizeof(mjtFrame), sizeof(int));
EXPECT_EQ(sizeof(mjtVisFlag), sizeof(int));
EXPECT_EQ(sizeof(mjtRndFlag), sizeof(int));
EXPECT_EQ(sizeof(mjtStereo), sizeof(int));
}
TEST_F(HeaderTest, MjOptionFields) { TEST_F(HeaderTest, MjOptionFields) {
mjOption o; mjOption o;
std::vector<std::pair<const void*, const char*>> fields; std::vector<std::pair<const void*, const char*>> fields;
+1
View File
@@ -24,6 +24,7 @@ public static class MujocoLib {
// ----------------------------------Constants---------------------------------- // ----------------------------------Constants----------------------------------
public const bool THIRD_PARTY_MUJOCO_MJASSERT_H_ = true;
public const bool THIRD_PARTY_MUJOCO_MJDATA_H_ = true; public const bool THIRD_PARTY_MUJOCO_MJDATA_H_ = true;
public const bool THIRD_PARTY_MUJOCO_MJEXPORT_H_ = true; public const bool THIRD_PARTY_MUJOCO_MJEXPORT_H_ = true;
public const bool MUJOCO_HELPER_DLL_LOCAL = true; public const bool MUJOCO_HELPER_DLL_LOCAL = true;