Skip to content

Commit 14c8dc6

Browse files
quaglacopybara-github
authored andcommitted
Add termination character to flattened plugin attributes if empty.
Fixes google-deepmind#2450. PiperOrigin-RevId: 730521722 Change-Id: Iec3fa377c65693d782eeb766a144a1c89096d1f3
1 parent 0246163 commit 14c8dc6

File tree

2 files changed

+65
-4
lines changed

2 files changed

+65
-4
lines changed

src/user/user_objects.cc

+5
Original file line numberDiff line numberDiff line change
@@ -7157,6 +7157,11 @@ void mjCPlugin::Compile(void) {
71577157
}
71587158
}
71597159

7160+
// if there are no attributes, add a null terminator
7161+
if (plugin->nattribute == 0) {
7162+
flattened_attributes.push_back('\0');
7163+
}
7164+
71607165
// anything left in xml_attributes at this stage is not a valid attribute
71617166
if (!config_attribs_copy.empty()) {
71627167
std::string error =

test/engine/engine_plugin_test.cc

+60-4
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ using ::testing::NotNull;
3939

4040
constexpr int kNumTruePlugins = 10;
4141
constexpr int kNumFakePlugins = 30;
42-
constexpr int kNumTestPlugins = 3;
42+
constexpr int kNumTestPlugins = 4;
4343

4444
class BaseTestPlugin {
4545
public:
@@ -340,6 +340,42 @@ int RegisterPassivePlugin() {
340340
return mjp_registerPlugin(&plugin);
341341
}
342342

343+
int RegisterNoAttributePlugin() {
344+
mjpPlugin plugin;
345+
mjp_defaultPlugin(&plugin);
346+
347+
plugin.name = "mujoco.test.noattribute";
348+
349+
plugin.nattribute = 0;
350+
plugin.attributes = nullptr;
351+
352+
plugin.capabilityflags |= mjPLUGIN_PASSIVE;
353+
354+
plugin.nstate = +[](const mjModel* m, int instance) { return 0; };
355+
356+
plugin.init = +[](const mjModel* m, mjData* d, int instance) {
357+
auto* passive = new TestPassive(m, d, instance);
358+
d->plugin_data[instance] = reinterpret_cast<uintptr_t>(passive);
359+
return 0;
360+
};
361+
plugin.destroy = +[](mjData* d, int instance) {
362+
delete reinterpret_cast<TestPassive*>(d->plugin_data[instance]);
363+
d->plugin_data[instance] = 0;
364+
};
365+
366+
plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
367+
int instance) {
368+
auto passive = reinterpret_cast<TestPassive*>(plugin_data);
369+
passive->Reset();
370+
};
371+
plugin.compute = +[](const mjModel* m, mjData* d, int instance, int type) {
372+
auto passive = reinterpret_cast<TestPassive*>(d->plugin_data[instance]);
373+
passive->Compute();
374+
};
375+
376+
return mjp_registerPlugin(&plugin);
377+
}
378+
343379
class EnginePluginTest : public PluginTest {
344380
public:
345381
// register all plugins
@@ -356,6 +392,7 @@ class EnginePluginTest : public PluginTest {
356392

357393
RegisterActuatorPlugin();
358394
RegisterPassivePlugin();
395+
RegisterNoAttributePlugin();
359396
}
360397
};
361398

@@ -374,6 +411,9 @@ constexpr char xml[] = R"(
374411
<config key="multiplier" value="0.125"/>
375412
</instance>
376413
</plugin>
414+
<plugin plugin="mujoco.test.noattribute">
415+
<instance name="noattribute"/>
416+
</plugin>
377417
<plugin plugin="mujoco.test.passive"/>
378418
</extension>
379419
<worldbody>
@@ -430,6 +470,22 @@ TEST_F(PluginTest, FirstPartyPlugins) {
430470
EXPECT_THAT(mjp_pluginCount(), kNumTruePlugins);
431471
}
432472

473+
TEST_F(EnginePluginTest, NoAttributePlugin) {
474+
static constexpr char xml[] = R"(
475+
<mujoco>
476+
<extension>
477+
<plugin plugin="mujoco.test.noattribute">
478+
<instance name="noattribute"/>
479+
</plugin>
480+
</extension>
481+
</mujoco>
482+
)";
483+
std::array<char, 1024> error;
484+
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
485+
EXPECT_THAT(m, testing::NotNull()) << error.data();
486+
mj_deleteModel(m);
487+
}
488+
433489
TEST_F(EnginePluginTest, MultiplePluginTableBlocks) {
434490
EXPECT_EQ(mjp_pluginCount(), kNumTruePlugins + kNumFakePlugins + kNumTestPlugins);
435491

@@ -529,7 +585,7 @@ TEST_F(EnginePluginTest, SensorPlugin) {
529585
EXPECT_EQ(TestSensor::InitCount(), expected_init_count);
530586
EXPECT_EQ(TestSensor::DestroyCount(), expected_destroy_count);
531587

532-
EXPECT_EQ(m->nplugin, 6);
588+
EXPECT_EQ(m->nplugin, 7);
533589
EXPECT_EQ(mj_name2id(m, mjOBJ_PLUGIN, "twosensors"), 0);
534590
EXPECT_EQ(mj_name2id(m, mjOBJ_PLUGIN, "threesensors"), 1);
535591

@@ -547,7 +603,7 @@ TEST_F(EnginePluginTest, SensorPlugin) {
547603
m->plugin_stateadr[1]),
548604
testing::ElementsAreArray<int>({3*(i+1), 6*j, 3*j}));
549605
EXPECT_THAT(*reinterpret_cast<mjtNum(*)[3]>(d->plugin_state +
550-
m->plugin_stateadr[4]),
606+
m->plugin_stateadr[5]),
551607
testing::ElementsAreArray<int>({5*(i+1), 10*j, 5*j}));
552608
EXPECT_THAT(*reinterpret_cast<mjtNum(*)[18]>(d->sensordata),
553609
testing::ElementsAreArray<int>({ i+1, 2*j, j,
@@ -587,7 +643,7 @@ TEST_F(EnginePluginTest, ActuatorPlugin) {
587643
EXPECT_EQ(TestActuator::InitCount(), expected_init_count);
588644
EXPECT_EQ(TestActuator::DestroyCount(), expected_destroy_count);
589645

590-
EXPECT_EQ(m->nplugin, 6);
646+
EXPECT_EQ(m->nplugin, 7);
591647
EXPECT_EQ(mj_name2id(m, mjOBJ_PLUGIN, "actuator2"), 2);
592648

593649
mjData* d = mj_makeData(m);

0 commit comments

Comments
 (0)