Skip to content

Out of range access on empty swizzle #3068

Description

@seang-ilm

Another edge case on the upgrade path.

If you add this test case to MaterialXTest/MaterialXCore/Document.cpp and run with MATERIALX_DYNAMIC_ANALYSIS=ON.

TEST_CASE("Document upgrade swizzle empty value", "[document]")
{
    mx::DocumentPtr doc = mx::createDocument();
    mx::XmlReadOptions readOptions;
    readOptions.upgradeVersion = false;
    mx::readFromXmlString(doc,
        "<?xml version=\"1.0\"?>"
        "<materialx version=\"1.38\">"
        "  <nodegraph name=\"NG1\">"
        "    <swizzle name=\"swz1\" type=\"color3\" nodedef=\"ND_swizzle\">"
        "      <input name=\"in\" type=\"color3\" value=\"\"/>"
        "      <input name=\"channels\" type=\"string\" value=\"\"/>"
        "    </swizzle>"
        "  </nodegraph>"
        "</materialx>",
        mx::FileSearchPath(), &readOptions);
    REQUIRE_NOTHROW(doc->upgradeVersion());
}
/usr/include/c++/11/bits/stl_vector.h:1046:34: runtime error: reference binding to null pointer of type 'struct value_type'

It's specifically on the upgrade path for 1.38-1.39, that converts old swizzle nodes to constant nodes.

The in input has an empty value value="". This means inInput->hasValue(); returns true and we go down path

convertToConstantNode = true; // because inInput exists and has a value attribute
...
if (convertToConstantNode)
{
    ...
    string valueString = inInput ? inInput->getValueString() : "0"; // <-- ""
    StringVec origValueTokens = splitString(valueString, ARRAY_VALID_SEPARATORS); // <-- empty vector {}
    ...
    newValueTokens.push_back(origValueTokens[0]); // <-- out of range access here

string valueString = inInput ? inInput->getValueString() : "0";
StringVec origValueTokens = splitString(valueString, ARRAY_VALID_SEPARATORS);
StringVec newValueTokens;
for (size_t i = 0; i < destChannelCount; i++)
{
if (i < channelString.size())
{
if (CHANNEL_INDEX_MAP.count(channelString[i]))
{
size_t index = CHANNEL_INDEX_MAP.at(channelString[i]);
if (index < origValueTokens.size())
{
newValueTokens.push_back(origValueTokens[index]);
continue;
}
}
else if (CHANNEL_CONSTANT_MAP.count(channelString[i]))
{
newValueTokens.push_back(std::to_string(CHANNEL_CONSTANT_MAP.at(channelString[i])));
continue;
}
}
// Invalid channel name, or missing channel name:
newValueTokens.push_back(origValueTokens[0]);
}

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions