diff --git a/source/MaterialXCore/Util.cpp b/source/MaterialXCore/Util.cpp index 9bb75a19b5..639b8f343c 100644 --- a/source/MaterialXCore/Util.cpp +++ b/source/MaterialXCore/Util.cpp @@ -24,7 +24,7 @@ const std::tuple LIBRARY_VERSION_TUPLE(MATERIALX_MAJOR_VERSION, bool invalidNameChar(char c) { - return !isalnum(c) && c != '_' && c != ':'; + return !isalnum((unsigned char) c) && c != '_' && c != ':'; } } // anonymous namespace diff --git a/source/MaterialXFormat/File.cpp b/source/MaterialXFormat/File.cpp index bb40ba54d1..62b7ec39a8 100644 --- a/source/MaterialXFormat/File.cpp +++ b/source/MaterialXFormat/File.cpp @@ -51,7 +51,7 @@ const string MATERIALX_SEARCH_PATH_ENV_VAR = "MATERIALX_SEARCH_PATH"; inline bool hasWindowsDriveSpecifier(const string& val) { - return (val.length() > 1 && std::isalpha(val[0]) && (val[1] == ':')); + return (val.length() > 1 && std::isalpha((unsigned char) val[0]) && (val[1] == ':')); } // diff --git a/source/MaterialXTest/MaterialXFormat/XmlIo.cpp b/source/MaterialXTest/MaterialXFormat/XmlIo.cpp index 1336a080c4..495712381e 100644 --- a/source/MaterialXTest/MaterialXFormat/XmlIo.cpp +++ b/source/MaterialXTest/MaterialXFormat/XmlIo.cpp @@ -6,7 +6,6 @@ #include #include -#include #include #include @@ -262,6 +261,51 @@ TEST_CASE("Comments and newlines", "[xmlio]") REQUIRE(origXml == newXml); } +TEST_CASE("Fuzz testing", "[xmlio]") +{ + mx::FileSearchPath searchPath = mx::getDefaultDataSearchPath(); + mx::FilePath examplesPath = searchPath.find("resources/Materials/Examples/StandardSurface"); + + std::mt19937 rng(0); + std::uniform_int_distribution randChar(0, 255); + + for (const mx::FilePath& filename : examplesPath.getFilesInDirectory(mx::MTLX_EXTENSION)) + { + // Read the example file into an XML string buffer. + const std::string origString = mx::readFile(examplesPath / filename); + REQUIRE(origString.size() > 0); + std::uniform_int_distribution randPos(0, origString.size() - 1); + + // Iterate over test runs. + for (size_t testRun = 0; testRun < 256; testRun++) + { + std::string editString = origString; + + // Iterate over string edits. + for (size_t editIndex = 0; editIndex < 32; editIndex++) + { + // Randomly alter one character in the document. + size_t charIndex = randPos(rng); + size_t newChar = randChar(rng); + editString[charIndex] = (char) newChar; + + // Attempt to interpret the edited string as a document, allowing only MaterialX exceptions. + mx::DocumentPtr doc = mx::createDocument(); + try + { + mx::readFromXmlString(doc, editString, searchPath); + doc->validate(); + } + catch (const mx::Exception&) + { + // On a MaterialX exception, proceed to the next test run. + break; + } + } + } + } +} + TEST_CASE("Locale region testing", "[xmlio]") { // In the United States, the thousands separator is a comma, while in Germany it is a period. diff --git a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp index 2ca8afa86c..1280ff390d 100644 --- a/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp +++ b/source/MaterialXTest/MaterialXGenShader/GenShaderUtil.cpp @@ -370,9 +370,8 @@ void shaderGenPerformanceTest(mx::GenContext& context) REQUIRE(loadedDocuments.size() == documentsPaths.size()); // Shuffle the order of documents and perform document library import validatation and shadergen - std::random_device random_dev; - std::mt19937 generator(random_dev()); - std::shuffle(loadedDocuments.begin(), loadedDocuments.end(), generator); + std::mt19937 rng(0); + std::shuffle(loadedDocuments.begin(), loadedDocuments.end(), rng); for (const auto& doc : loadedDocuments) { doc->importLibrary(nodeLibrary);