Add more validation in gmsh parsing.

PiperOrigin-RevId: 624179874
Change-Id: I423a740d7c2aae617a87ff31329a49b8275bb578
This commit is contained in:
Nimrod Gileadi
2024-04-12 08:01:41 -07:00
committed by Copybara-Service
parent 70f00b05a1
commit 9463a8816d
+40 -12
View File
@@ -13,11 +13,11 @@
// limitations under the License.
#include <algorithm>
#include <climits>
#include <cstddef>
#include <cstdio>
#include <cstring>
#include <sstream>
#include <stdio.h>
#include <string>
#include <vector>
@@ -33,6 +33,7 @@
#include "engine/engine_util_misc.h"
#include "engine/engine_util_spatial.h"
#include "user/user_flexcomp.h"
#include "user/user_api.h"
#include "user/user_model.h"
#include "user/user_objects.h"
#include "user/user_util.h"
@@ -1069,6 +1070,9 @@ void mjCFlexcomp::LoadGMSH41(char* buffer, int binary, int nodeend,
}
// read points
if (numNodes < 0 || numNodes >= INT_MAX / 3) {
throw mjCError(NULL, "Invalid number of nodes.");
}
point.reserve(3*numNodes);
for (size_t i=0; i < 3*numNodes; i++) {
double x;
@@ -1127,10 +1131,13 @@ void mjCFlexcomp::LoadGMSH41(char* buffer, int binary, int nodeend,
}
// read points
double x;
if (numNodes < 0 || numNodes >= INT_MAX / 3) {
throw mjCError(NULL, "Invalid number of nodes.");
}
point.reserve(3*numNodes);
const char* pointbuffer = buffer + nodebegin + kGmsh41HeaderSize + componentSize*numNodes;
for (size_t i=0; i < 3*numNodes; i++) {
double x;
ReadFromBuffer(&x, pointbuffer + i*componentSize);
point.push_back(x);
}
@@ -1162,6 +1169,10 @@ void mjCFlexcomp::LoadGMSH41(char* buffer, int binary, int nodeend,
throw mjCError(NULL, "Inconsistent dimensionality in Elements");
}
if (numElements < 0 || numElements >= INT_MAX / 4) {
throw mjCError(NULL, "Invalid numElements.");
}
// type must be consistent with dimensionality
if ((entityDim == 1 && elementType != 1) ||
(entityDim == 2 && elementType != 2) ||
@@ -1218,6 +1229,10 @@ void mjCFlexcomp::LoadGMSH41(char* buffer, int binary, int nodeend,
throw mjCError(NULL, "Element type inconsistent with dimensionality");
}
if (numElements < 0 || numElements >= INT_MAX / 4) {
throw mjCError(NULL, "Invalid numElements.");
}
// elementData: element tag and n node tags
int numElementComponents = (entityDim+2);
constexpr int componentSize = 8;
@@ -1265,6 +1280,10 @@ void mjCFlexcomp::LoadGMSH22(char* buffer, int binary, int nodeend,
}
size_t numNodes = maxNodeTag;
if (numNodes < 0 || numNodes >= INT_MAX / 3) {
throw mjCError(NULL, "Invalid number of nodes.");
}
// read points, discard tag
point.reserve(3*numNodes);
for (size_t i=0; i < numNodes; i++) {
@@ -1297,9 +1316,9 @@ void mjCFlexcomp::LoadGMSH22(char* buffer, int binary, int nodeend,
}
// parse maxNodeTag and then cast it to int
char maxNodeTagChar[20];
char maxNodeTagChar[11] = {0};
ReadStrFromBuffer(maxNodeTagChar, buffer + nodebegin, std::min(10, nodeend - nodebegin));
size_t measuredHeaderSize = strnlen(maxNodeTagChar, 20) - 1;
size_t measuredHeaderSize = strnlen(maxNodeTagChar, 10) - 1;
size_t maxNodeTag = std::stoi(maxNodeTagChar);
size_t numNodes = maxNodeTag;
@@ -1314,6 +1333,9 @@ void mjCFlexcomp::LoadGMSH22(char* buffer, int binary, int nodeend,
}
// read point, discard tag
if (numNodes < 0 || numNodes >= INT_MAX / 3) {
throw mjCError(NULL, "Invalid number of nodes.");
}
point.reserve(3*numNodes);
// beginning of buffer containing node info
const char* tagBuffer = buffer + nodebegin + measuredHeaderSize;
@@ -1346,6 +1368,11 @@ void mjCFlexcomp::LoadGMSH22(char* buffer, int binary, int nodeend,
throw mjCError(NULL, "Error reading Elements header");
}
size_t numElements = maxElementTag;
if (numElements < 0 || numElements >= INT_MAX / 4) {
throw mjCError(NULL, "Invalid number of elements.");
}
// read elements, discard all tags
element.reserve((entityDim+1)*numElements);
for (size_t i=0; i < numElements; i++) {
@@ -1385,9 +1412,9 @@ void mjCFlexcomp::LoadGMSH22(char* buffer, int binary, int nodeend,
}
// reading elements
char maxElementTagChar[20];
char maxElementTagChar[11] = {0};
ReadStrFromBuffer(maxElementTagChar, buffer + elembegin, std::min(10, elemend - elembegin));
int measuredHeaderSize = strnlen(maxElementTagChar, 20) - 1;
int measuredHeaderSize = strnlen(maxElementTagChar, 10) - 1;
int maxElementTag = std::stoi(maxElementTagChar);
int numElements = maxElementTag;
int tag, numTags;
@@ -1462,7 +1489,7 @@ void mjCFlexcomp::LoadGMSH22(char* buffer, int binary, int nodeend,
// Handling elements produced by ftetwild
else {
// read first element
for (int k =0; k < numNodeTags; k++) {
for (int k = 0; k < numNodeTags; k++) {
const char* nodeTagBuffer = elementsBuffer + componentSize*(4+k);
ReadFromBuffer(&nodeTag, nodeTagBuffer);
if (nodeTag > numElements || nodeTag < 1) {
@@ -1524,6 +1551,10 @@ void mjCFlexcomp::LoadGMSH(mjCModel* model, mjResource* resource) {
int elemend = findstring(buffer, buffer_sz, "$EndElements");
// correct begin for string size, +1 for LF in binary (CRLF in Win ascii works)
nodebegin += (int)strlen("$Nodes") + 1;
elembegin += (int)strlen("$Elements") + 1;
// check sections
if (nodebegin < 0) {
throw mjCError(NULL, "GMSH file missing $Nodes");
@@ -1538,11 +1569,6 @@ void mjCFlexcomp::LoadGMSH(mjCModel* model, mjResource* resource) {
throw mjCError(NULL, "GMSH file missing $EndElements after $Elements");
}
// correct begin for string size, +1 for LF in binary (CRLF in Win ascii works)
nodebegin += (int)strlen("$Nodes") + 1;
elembegin += (int)strlen("$Elements") + 1;
// Support for 4.1
if (mju_round(100*version) == 410) {
LoadGMSH41(buffer, binary, nodeend, nodebegin, elemend, elembegin);
@@ -1551,5 +1577,7 @@ void mjCFlexcomp::LoadGMSH(mjCModel* model, mjResource* resource) {
// Support for 2.2
else if (mju_round(100*version) == 220) {
LoadGMSH22(buffer, binary, nodeend, nodebegin, elemend, elembegin);
} else {
throw mjCError(NULL, "Unsupported GMSH file format version");
}
}