Add termination character to flattened plugin attributes if empty.

Fixes #2450.

PiperOrigin-RevId: 730521722
Change-Id: Iec3fa377c65693d782eeb766a144a1c89096d1f3
This commit is contained in:
Alessio Quaglino
2025-02-24 11:06:27 -08:00
committed by Copybara-Service
parent 024616345d
commit 14c8dc62f0
2 changed files with 65 additions and 4 deletions
+5
View File
@@ -7157,6 +7157,11 @@ void mjCPlugin::Compile(void) {
}
}
// if there are no attributes, add a null terminator
if (plugin->nattribute == 0) {
flattened_attributes.push_back('\0');
}
// anything left in xml_attributes at this stage is not a valid attribute
if (!config_attribs_copy.empty()) {
std::string error =
+60 -4
View File
@@ -39,7 +39,7 @@ using ::testing::NotNull;
constexpr int kNumTruePlugins = 10;
constexpr int kNumFakePlugins = 30;
constexpr int kNumTestPlugins = 3;
constexpr int kNumTestPlugins = 4;
class BaseTestPlugin {
public:
@@ -340,6 +340,42 @@ int RegisterPassivePlugin() {
return mjp_registerPlugin(&plugin);
}
int RegisterNoAttributePlugin() {
mjpPlugin plugin;
mjp_defaultPlugin(&plugin);
plugin.name = "mujoco.test.noattribute";
plugin.nattribute = 0;
plugin.attributes = nullptr;
plugin.capabilityflags |= mjPLUGIN_PASSIVE;
plugin.nstate = +[](const mjModel* m, int instance) { return 0; };
plugin.init = +[](const mjModel* m, mjData* d, int instance) {
auto* passive = new TestPassive(m, d, instance);
d->plugin_data[instance] = reinterpret_cast<uintptr_t>(passive);
return 0;
};
plugin.destroy = +[](mjData* d, int instance) {
delete reinterpret_cast<TestPassive*>(d->plugin_data[instance]);
d->plugin_data[instance] = 0;
};
plugin.reset = +[](const mjModel* m, mjtNum* plugin_state, void* plugin_data,
int instance) {
auto passive = reinterpret_cast<TestPassive*>(plugin_data);
passive->Reset();
};
plugin.compute = +[](const mjModel* m, mjData* d, int instance, int type) {
auto passive = reinterpret_cast<TestPassive*>(d->plugin_data[instance]);
passive->Compute();
};
return mjp_registerPlugin(&plugin);
}
class EnginePluginTest : public PluginTest {
public:
// register all plugins
@@ -356,6 +392,7 @@ class EnginePluginTest : public PluginTest {
RegisterActuatorPlugin();
RegisterPassivePlugin();
RegisterNoAttributePlugin();
}
};
@@ -374,6 +411,9 @@ constexpr char xml[] = R"(
<config key="multiplier" value="0.125"/>
</instance>
</plugin>
<plugin plugin="mujoco.test.noattribute">
<instance name="noattribute"/>
</plugin>
<plugin plugin="mujoco.test.passive"/>
</extension>
<worldbody>
@@ -430,6 +470,22 @@ TEST_F(PluginTest, FirstPartyPlugins) {
EXPECT_THAT(mjp_pluginCount(), kNumTruePlugins);
}
TEST_F(EnginePluginTest, NoAttributePlugin) {
static constexpr char xml[] = R"(
<mujoco>
<extension>
<plugin plugin="mujoco.test.noattribute">
<instance name="noattribute"/>
</plugin>
</extension>
</mujoco>
)";
std::array<char, 1024> error;
mjModel* m = LoadModelFromString(xml, error.data(), error.size());
EXPECT_THAT(m, testing::NotNull()) << error.data();
mj_deleteModel(m);
}
TEST_F(EnginePluginTest, MultiplePluginTableBlocks) {
EXPECT_EQ(mjp_pluginCount(), kNumTruePlugins + kNumFakePlugins + kNumTestPlugins);
@@ -529,7 +585,7 @@ TEST_F(EnginePluginTest, SensorPlugin) {
EXPECT_EQ(TestSensor::InitCount(), expected_init_count);
EXPECT_EQ(TestSensor::DestroyCount(), expected_destroy_count);
EXPECT_EQ(m->nplugin, 6);
EXPECT_EQ(m->nplugin, 7);
EXPECT_EQ(mj_name2id(m, mjOBJ_PLUGIN, "twosensors"), 0);
EXPECT_EQ(mj_name2id(m, mjOBJ_PLUGIN, "threesensors"), 1);
@@ -547,7 +603,7 @@ TEST_F(EnginePluginTest, SensorPlugin) {
m->plugin_stateadr[1]),
testing::ElementsAreArray<int>({3*(i+1), 6*j, 3*j}));
EXPECT_THAT(*reinterpret_cast<mjtNum(*)[3]>(d->plugin_state +
m->plugin_stateadr[4]),
m->plugin_stateadr[5]),
testing::ElementsAreArray<int>({5*(i+1), 10*j, 5*j}));
EXPECT_THAT(*reinterpret_cast<mjtNum(*)[18]>(d->sensordata),
testing::ElementsAreArray<int>({ i+1, 2*j, j,
@@ -587,7 +643,7 @@ TEST_F(EnginePluginTest, ActuatorPlugin) {
EXPECT_EQ(TestActuator::InitCount(), expected_init_count);
EXPECT_EQ(TestActuator::DestroyCount(), expected_destroy_count);
EXPECT_EQ(m->nplugin, 6);
EXPECT_EQ(m->nplugin, 7);
EXPECT_EQ(mj_name2id(m, mjOBJ_PLUGIN, "actuator2"), 2);
mjData* d = mj_makeData(m);