Fix buffer overrun when parsing 'l' line.

This commit is contained in:
Syoyo Fujita
2018-07-25 16:24:40 +09:00
parent 0e950513a3
commit 0d68262246
2 changed files with 255 additions and 261 deletions

View File

@@ -137,8 +137,10 @@ static void PrintInfo(const tinyobj::attrib_t& attrib,
for (size_t i = 0; i < shapes.size(); i++) { for (size_t i = 0; i < shapes.size(); i++) {
printf("shape[%ld].name = %s\n", static_cast<long>(i), printf("shape[%ld].name = %s\n", static_cast<long>(i),
shapes[i].name.c_str()); shapes[i].name.c_str());
printf("Size of shape[%ld].indices: %lu\n", static_cast<long>(i), printf("Size of shape[%ld].mesh.indices: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].mesh.indices.size())); static_cast<unsigned long>(shapes[i].mesh.indices.size()));
printf("Size of shape[%ld].path.indices: %lu\n", static_cast<long>(i),
static_cast<unsigned long>(shapes[i].path.indices.size()));
size_t index_offset = 0; size_t index_offset = 0;

View File

@@ -23,6 +23,7 @@ THE SOFTWARE.
*/ */
// //
// version 1.2.1 : Added initial support for line('l') primitive(PR #178)
// version 1.2.0 : Hardened implementation(#175) // version 1.2.0 : Hardened implementation(#175)
// version 1.1.1 : Support smoothing groups(#162) // version 1.1.1 : Support smoothing groups(#162)
// version 1.1.0 : Support parsing vertex color(#144) // version 1.1.0 : Support parsing vertex color(#144)
@@ -377,8 +378,8 @@ void LoadMtl(std::map<std::string, int> *material_map,
#include <cstddef> #include <cstddef>
#include <cstdlib> #include <cstdlib>
#include <cstring> #include <cstring>
#include <utility>
#include <limits> #include <limits>
#include <utility>
#include <fstream> #include <fstream>
#include <sstream> #include <sstream>
@@ -1010,9 +1011,8 @@ static void InitMaterial(material_t *material) {
} }
// code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html // code from https://wrf.ecse.rpi.edu//Research/Short_Notes/pnpoly.html
template<typename T> template <typename T>
static int pnpoly(int nvert, T *vertx, T *verty, T testx, static int pnpoly(int nvert, T *vertx, T *verty, T testx, T testy) {
T testy) {
int i, j, c = 0; int i, j, c = 0;
for (i = 0, j = nvert - 1; i < nvert; j = i++) { for (i = 0, j = nvert - 1; i < nvert; j = i++) {
if (((verty[i] > testy) != (verty[j] > testy)) && if (((verty[i] > testy) != (verty[j] > testy)) &&
@@ -1029,18 +1029,14 @@ static bool exportGroupsToShape(shape_t *shape,
const std::vector<face_t> &faceGroup, const std::vector<face_t> &faceGroup,
std::vector<int> &lineGroup, std::vector<int> &lineGroup,
const std::vector<tag_t> &tags, const std::vector<tag_t> &tags,
const int material_id, const int material_id, const std::string &name,
const std::string &name, bool triangulate, bool triangulate,
const std::vector<real_t> &v) { const std::vector<real_t> &v) {
if (faceGroup.empty() && lineGroup.empty()) { if (faceGroup.empty() && lineGroup.empty()) {
return false; return false;
} }
if (!faceGroup.empty()) { if (!faceGroup.empty()) {
// Flatten vertices and indices // Flatten vertices and indices
for (size_t i = 0; i < faceGroup.size(); i++) { for (size_t i = 0; i < faceGroup.size(); i++) {
const face_t &face = faceGroup[i]; const face_t &face = faceGroup[i];
@@ -1067,8 +1063,7 @@ static bool exportGroupsToShape(shape_t *shape,
size_t vi1 = size_t(i1.v_idx); size_t vi1 = size_t(i1.v_idx);
size_t vi2 = size_t(i2.v_idx); size_t vi2 = size_t(i2.v_idx);
if (((3 * vi0 + 2) >= v.size()) || if (((3 * vi0 + 2) >= v.size()) || ((3 * vi1 + 2) >= v.size()) ||
((3 * vi1 + 2) >= v.size()) ||
((3 * vi2 + 2) >= v.size())) { ((3 * vi2 + 2) >= v.size())) {
// Invalid triangle. // Invalid triangle.
// FIXME(syoyo): Is it ok to simply skip this invalid triangle? // FIXME(syoyo): Is it ok to simply skip this invalid triangle?
@@ -1124,8 +1119,8 @@ static bool exportGroupsToShape(shape_t *shape,
area += (v0x * v1y - v0y * v1x) * static_cast<real_t>(0.5); area += (v0x * v1y - v0y * v1x) * static_cast<real_t>(0.5);
} }
int maxRounds = int maxRounds = 10; // arbitrary max loop count to protect against
10; // arbitrary max loop count to protect against unexpected errors // unexpected errors
face_t remainingFace = face; // copy face_t remainingFace = face; // copy
size_t guess_vert = 0; size_t guess_vert = 0;
@@ -1172,9 +1167,7 @@ static bool exportGroupsToShape(shape_t *shape,
continue; continue;
} }
size_t ovi = size_t( size_t ovi = size_t(remainingFace.vertex_indices[idx].v_idx);
remainingFace.vertex_indices[idx]
.v_idx);
if (((ovi * 3 + axes[0]) >= v.size()) || if (((ovi * 3 + axes[0]) >= v.size()) ||
((ovi * 3 + axes[1]) >= v.size())) { ((ovi * 3 + axes[1]) >= v.size())) {
@@ -1272,8 +1265,7 @@ static bool exportGroupsToShape(shape_t *shape,
shape->mesh.tags = tags; shape->mesh.tags = tags;
} }
if (!lineGroup.empty()) {
if(!lineGroup.empty()){
shape->path.indices.swap(lineGroup); shape->path.indices.swap(lineGroup);
} }
@@ -1765,8 +1757,7 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
#else #else
const char dirsep = '\\'; const char dirsep = '\\';
#endif #endif
if (baseDir[baseDir.length() - 1] != dirsep) if (baseDir[baseDir.length() - 1] != dirsep) baseDir += dirsep;
baseDir += dirsep;
} }
MaterialFileReader matFileReader(baseDir); MaterialFileReader matFileReader(baseDir);
@@ -1865,19 +1856,20 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
} }
// line // line
if (token[0] == 'l' && IS_SPACE((token[1]))){ if (token[0] == 'l' && IS_SPACE((token[1]))) {
token += 2; token += 2;
line_t line_cache; line_t line_cache;
bool end_line_bit = 0; bool end_line_bit = 0;
while(!IS_NEW_LINE(token[0])){ while (!IS_NEW_LINE(token[0])) {
//get index from string // get index from string
int idx; int idx;
fixIndex(parseInt(&token), 0, &idx); fixIndex(parseInt(&token), 0, &idx);
// move to next space or end of string (\0 / \n)
token += strcspn(token, " \t\r")+1;
if(!end_line_bit){ size_t n = strspn(token, " \t\r");
token += n;
if (!end_line_bit) {
line_cache.idx0 = idx; line_cache.idx0 = idx;
} else { } else {
line_cache.idx1 = idx; line_cache.idx1 = idx;
@@ -1995,8 +1987,8 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
// group name // group name
if (token[0] == 'g' && IS_SPACE((token[1]))) { if (token[0] == 'g' && IS_SPACE((token[1]))) {
// flush previous face group. // flush previous face group.
bool ret = exportGroupsToShape(&shape, faceGroup, lineGroup, tags, material, name, bool ret = exportGroupsToShape(&shape, faceGroup, lineGroup, tags,
triangulate, v); material, name, triangulate, v);
(void)ret; // return value not used. (void)ret; // return value not used.
if (shape.mesh.indices.size() > 0) { if (shape.mesh.indices.size() > 0) {
@@ -2032,8 +2024,8 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
// object name // object name
if (token[0] == 'o' && IS_SPACE((token[1]))) { if (token[0] == 'o' && IS_SPACE((token[1]))) {
// flush previous face group. // flush previous face group.
bool ret = exportGroupsToShape(&shape, faceGroup, lineGroup, tags, material, name, bool ret = exportGroupsToShape(&shape, faceGroup, lineGroup, tags,
triangulate, v); material, name, triangulate, v);
if (ret) { if (ret) {
shapes->push_back(shape); shapes->push_back(shape);
} }
@@ -2140,8 +2132,8 @@ bool LoadObj(attrib_t *attrib, std::vector<shape_t> *shapes,
// Ignore unknown command. // Ignore unknown command.
} }
bool ret = exportGroupsToShape(&shape, faceGroup, lineGroup, tags, material, name, bool ret = exportGroupsToShape(&shape, faceGroup, lineGroup, tags, material,
triangulate, v); name, triangulate, v);
// exportGroupsToShape return false when `usemtl` is called in the last // exportGroupsToShape return false when `usemtl` is called in the last
// line. // line.
// we also add `shape` to `shapes` when `shape.mesh` has already some // we also add `shape` to `shapes` when `shape.mesh` has already some