#3584·mujoco

[Model editing] Failed allocations raise C++ exceptions through the C API

Author: davidhozicCreated Sep 15, 2026Updated Sep 15, 2026
Labelsbug

Intro

Hi!

I am a researcher at University of Ljubljana, I use MuJoCo for different things.

My setup

MuJoCo 3.13.0; C API (C++ code), x84, Fedora 44.

What's happening? What did you expect?

Model editing functions, such as mjs_addBody, don't provide an option to catch failed allocations and just segment fault when the returned pointer is supposed to be NULL.

This happens because the C API functions call C++ model-editing related code that seems to rely on throwing exceptions to indicate memory-allocation failure.

I know this is an edge case that can happen on fairly large number of items (or memory-constrained environments), but I'd still like to have an option in the API to control it, instead of just segment faulting due to C++'s exceptions trying to go through C (and in my case Rust) code.

Steps for reproduction

  1. Compile the below code with gcc -O0 -std=c23 -I mujoco-3.13.0/include -I mujoco-3.13.0/include/mujoco main.c -o ./crash_mujoco -L mujoco-3.13.0/lib -lmujoco -Wl,-rpath,$PWD/mujoco-3.13.0/lib
  2. Run the code.

Minimal model for reproduction

Not relevant. The bug is in model-editing (procedural generation) .

Code required for reproduction

In this "minimal" example, malloc is overridden with an implementation that will return NULL after the first mjs_addBody call, for the purpose of demonstration.

c
#include <stdio.h>
#include <stdint.h>
#include "mujoco.h"

// Real allocator
void* __libc_malloc(size_t size);

// Override malloc.
static size_t total = 0;
static size_t limit = UINT32_MAX;
void* malloc(size_t size) {
    if (total + size >= limit) {
        return NULL;
    }

    total += size;
    return __libc_malloc(size);
}

int main() {
    mjSpec* spec = mj_makeSpec();
    mjsBody* world = mjs_findBody(spec, "world");

    for (long i = 1;; i++) {
        mjsBody* body = mjs_addBody(world, NULL);
        printf("Added bodies: %ld\n", i);

        // Hack to deterministically fail malloc.
        limit = total;  // Force limit to the current size
        //////////////////////////////////////////////////////

        if (body == NULL) {
          printf("mjs_addBody returned NULL at body %ld\n", i);
          return 0;
        }
    }
}

Confirmations