From 219b7ff6dbc6d3e7bbac3e4304b2e1b7dd6973f5 Mon Sep 17 00:00:00 2001 From: Hermet Park Date: Tue, 1 Sep 2020 20:13:07 +0900 Subject: [PATCH] svg_loader: fix vector memory leaks. vector is designed for c++ syntaxes, it works properly when c++ memory allocator is applied, Here svg_loader uses c style structures which allocated using malloc()/calloc(). That brings the memory broken of stl vectors. So, we replaced it with our customized SvgVector to easily fix it. Change-Id: Iccf5090b13322671893bb8b185bba6d8253e96f5 --- src/loaders/svg/tvgSvgLoader.cpp | 109 ++++++++++++++++++--------------- src/loaders/svg/tvgSvgLoaderCommon.h | 39 ++++++++++-- src/loaders/svg/tvgSvgSceneBuilder.cpp | 26 ++++---- 3 files changed, 107 insertions(+), 67 deletions(-) diff --git a/src/loaders/svg/tvgSvgLoader.cpp b/src/loaders/svg/tvgSvgLoader.cpp index fedf8a9..6367fc4 100644 --- a/src/loaders/svg/tvgSvgLoader.cpp +++ b/src/loaders/svg/tvgSvgLoader.cpp @@ -944,7 +944,7 @@ static SvgNode* _createNode(SvgNode* parent, SvgNodeType type) node->parent = parent; node->type = type; - if (parent) parent->child.push_back(node); + if (parent) parent->child.push(node); return node; } @@ -1334,22 +1334,22 @@ static SvgNode* _getDefsNode(SvgNode* node) static SvgNode* _findChildById(SvgNode* node, const char* id) { - if (!node) return nullptr; - for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { - if (((*itrChild)->id != nullptr) && !strcmp((*itrChild)->id->c_str(), id)) return *itrChild; + auto child = node->child.list; + for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) { + if (((*child)->id != nullptr) && !strcmp((*child)->id->c_str(), id)) return (*child); } return nullptr; } -static void _cloneGradStops(vector *dst, vector src) +static void _cloneGradStops(SvgVector* dst, SvgVector* src) { - for (auto colorStop : src) { - auto stop = static_cast(malloc(sizeof(Fill::ColorStop))); - *stop = *colorStop; - dst->push_back(stop); + for (uint32_t i = 0; i < src->cnt; ++i) { + auto stop = static_cast(malloc(sizeof(Fill::ColorStop))); + *stop = *src->list[i]; + dst->push(stop); } } @@ -1379,7 +1379,7 @@ static SvgStyleGradient* _cloneGradient(SvgStyleGradient* from) memcpy(grad->radial, from->radial, sizeof(SvgRadialGradient)); } - _cloneGradStops(&(grad->stops), from->stops); + _cloneGradStops(&grad->stops, &from->stops); return grad; } @@ -1454,8 +1454,9 @@ static void _cloneNode(SvgNode* from, SvgNode* parent) newNode = _createNode(parent, from->type); _copyAttr(newNode, from); - for (auto child : from->child) { - _cloneNode(child, newNode); + auto child = from->child.list; + for (uint32_t i = 0; i < from->child.cnt; ++i, ++child) { + _cloneNode(*child, newNode); } _freeNode(newNode); @@ -1907,7 +1908,7 @@ static void _svgLoaderParerXmlClose(SvgLoaderData* loader, const char* content) for (i = 0; i < sizeof(popArray) / sizeof(popArray[0]); i++) { if (!strncmp(content, popArray[i].tag, popArray[i].sz - 1)) { - loader->stack.pop_back(); + loader->stack.pop(); break; } } @@ -1951,17 +1952,17 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, loader->doc = node; } else { if (!strcmp(tagName, "svg")) return; //Already loadded (SvgNodeType::Doc) tag - if (loader->stack.size() > 0) parent = loader->stack.at(loader->stack.size() - 1); + if (loader->stack.cnt > 0) parent = loader->stack.list[loader->stack.cnt - 1]; node = method(loader, parent, attrs, attrsLength); } - loader->stack.push_back(node); + loader->stack.push(node); if (node->type == SvgNodeType::Defs) { loader->doc->node.doc.defs = node; loader->def = node; } } else if ((method = _findGraphicsFactory(tagName))) { - parent = loader->stack.at(loader->stack.size() - 1); + parent = loader->stack.list[loader->stack.cnt - 1]; node = method(loader, parent, attrs, attrsLength); } else if ((gradientMethod = _findGradientFactory(tagName))) { SvgStyleGradient* gradient; @@ -1973,9 +1974,9 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, // This is only to support this when multiple gradients are declared, even if no defs are declared. // refer to: https://developer.mozilla.org/en-US/docs/Web/SVG/Element/defs if (loader->doc->node.doc.defs) { - loader->def->node.defs.gradients.push_back(gradient); + loader->def->node.defs.gradients.push(gradient); } else { - loader->gradients.push_back(gradient); + loader->gradients.push(gradient); } loader->latestGradient = gradient; } else if (!strcmp(tagName, "stop")) { @@ -1985,7 +1986,7 @@ static void _svgLoaderParserXmlOpen(SvgLoaderData* loader, const char* content, stop->a = 255; simpleXmlParseAttributes(attrs, attrsLength, _attrParseStops, loader); if (loader->latestGradient) { - loader->latestGradient->stops.push_back(stop); + loader->latestGradient->stops.push(stop); } } } @@ -2074,32 +2075,38 @@ static void _updateStyle(SvgNode* node, SvgStyleProperty* parentStyle) { _styleInherit(node->style, parentStyle); - for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { - _updateStyle(*itrChild, node->style); + auto child = node->child.list; + for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) { + _updateStyle(*child, node->style); } } -static SvgStyleGradient* _gradientDup(vector gradList, string* id) +static SvgStyleGradient* _gradientDup(SvgVector* gradients, string* id) { SvgStyleGradient* result = nullptr; - for (vector::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) { - if (!((*itrGrad)->id->compare(*id))) { - result = _cloneGradient(*itrGrad); + auto gradList = gradients->list; + + for (uint32_t i = 0; i < gradients->cnt; ++i) { + if (!((*gradList)->id->compare(*id))) { + result = _cloneGradient(*gradList); break; } + ++gradList; } if (result && result->ref) { - for (vector::iterator itrGrad = gradList.begin(); itrGrad != gradList.end(); itrGrad++) { - if (!((*itrGrad)->id->compare(*result->ref))) { - if (!result->stops.empty()) { - _cloneGradStops(&(result->stops), (*itrGrad)->stops); + gradList = gradients->list; + for (uint32_t i = 0; i < gradients->cnt; ++i) { + if (!((*gradList)->id->compare(*result->ref))) { + if (result->stops.cnt > 0) { + _cloneGradStops(&result->stops, &(*gradList)->stops); } //TODO: Properly inherit other property break; } + ++gradList; } } @@ -2107,15 +2114,16 @@ static SvgStyleGradient* _gradientDup(vector gradList, string } -static void _updateGradient(SvgNode* node, vector gradList) +static void _updateGradient(SvgNode* node, SvgVector* gradidents) { - if (!node->child.empty()) { - for (vector::iterator itrChild = node->child.begin(); itrChild != node->child.end(); itrChild++) { - _updateGradient(*itrChild, gradList); + if (node->child.cnt > 0) { + auto child = node->child.list; + for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) { + _updateGradient(*child, gradidents); } } else { if (node->style->fill.paint.url) { - node->style->fill.paint.gradient = _gradientDup(gradList, node->style->fill.paint.url); + node->style->fill.paint.gradient = _gradientDup(gradidents, node->style->fill.paint.url); } else if (node->style->stroke.paint.url) { //node->style->stroke.paint.gradient = _gradientDup(gradList, node->style->stroke.paint.url); } @@ -2132,8 +2140,11 @@ static void _freeGradientStyle(SvgStyleGradient* grad) free(grad->linear); if (grad->transform) free(grad->transform); - for (auto colorStop : grad->stops) free(colorStop); - + for (uint32_t i = 0; i < grad->stops.cnt; ++i) { + auto colorStop = grad->stops.list[i]; + free(colorStop); + } + grad->stops.clear(); free(grad); } @@ -2152,8 +2163,9 @@ static void _freeNode(SvgNode* node) { if (!node) return; - for(auto child : node->child) { - _freeNode(child); + auto child = node->child.list; + for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) { + _freeNode(*child); } node->child.clear(); @@ -2178,9 +2190,12 @@ static void _freeNode(SvgNode* node) break; } case SvgNodeType::Defs: { - for(vector::iterator itrGrad = node->node.defs.gradients.begin(); itrGrad != node->node.defs.gradients.end(); itrGrad++) { - _freeGradientStyle(*itrGrad); + auto gradients = node->node.defs.gradients.list; + for (size_t i = 0; i < node->node.defs.gradients.cnt; ++i) { + _freeGradientStyle(*gradients); + ++gradients; } + node->node.defs.gradients.clear(); break; } default: { @@ -2221,7 +2236,7 @@ static bool _svgLoaderParserForValidCheckXmlOpen(SvgLoaderData* loader, const ch if (strcmp(tagName, "svg")) return true; //Not a valid svg document node = method(loader, nullptr, attrs, attrsLength); loader->doc = node; - loader->stack.push_back(node); + loader->stack.push(node); return false; } } @@ -2257,15 +2272,10 @@ void SvgTask::run() if (loader->loaderData.doc) { _updateStyle(loader->loaderData.doc, nullptr); auto defs = loader->loaderData.doc->node.doc.defs; - if (defs) _updateGradient(loader->loaderData.doc, defs->node.defs.gradients); + if (defs) _updateGradient(loader->loaderData.doc, &defs->node.defs.gradients); else { - if (!loader->loaderData.gradients.empty()) { - vector gradientList; - for (auto gradient : loader->loaderData.gradients) { - gradientList.push_back(gradient); - } - _updateGradient(loader->loaderData.doc, gradientList); - gradientList.clear(); + if (loader->loaderData.gradients.cnt > 0) { + _updateGradient(loader->loaderData.doc, &loader->loaderData.gradients); } } } @@ -2368,6 +2378,7 @@ bool SvgLoader::close() } _freeNode(loaderData.doc); loaderData.doc = nullptr; + loaderData.stack.clear(); return true; } diff --git a/src/loaders/svg/tvgSvgLoaderCommon.h b/src/loaders/svg/tvgSvgLoaderCommon.h index bba9523..f579c59 100644 --- a/src/loaders/svg/tvgSvgLoaderCommon.h +++ b/src/loaders/svg/tvgSvgLoaderCommon.h @@ -119,6 +119,35 @@ enum class SvgParserLengthType struct SvgNode; struct SvgStyleGradient; +template +struct SvgVector +{ + T* list; + uint32_t cnt; + uint32_t reserved; + + void push(T element) + { + if (cnt + 1 > reserved) { + reserved = (cnt + 1) * 2; + list = static_cast(realloc(list, sizeof(T) * reserved)); + } + list[cnt++] = element; + } + + void pop() + { + if (cnt > 0) --cnt; + } + + void clear() + { + if (list) free(list); + list = nullptr; + cnt = reserved = 0; + } +}; + struct SvgDocNode { float w; @@ -137,7 +166,7 @@ struct SvgGNode struct SvgDefsNode { - vector gradients; + SvgVector gradients; }; struct SvgArcNode @@ -240,7 +269,7 @@ struct SvgStyleGradient SvgRadialGradient* radial; SvgLinearGradient* linear; Matrix* transform; - vector stops; + SvgVector stops; bool userSpace; bool usePercentage; }; @@ -281,7 +310,7 @@ struct SvgNode { SvgNodeType type; SvgNode* parent; - vector child; + SvgVector child; string *id; SvgStyleProperty *style; Matrix* transform; @@ -320,10 +349,10 @@ struct SvgParser struct SvgLoaderData { - vector stack; + SvgVector stack = {nullptr, 0, 0}; SvgNode* doc = nullptr; SvgNode* def = nullptr; - vector gradients; + SvgVector gradients; SvgStyleGradient* latestGradient = nullptr; //For stops SvgParser* svgParse = nullptr; int level = 0; diff --git a/src/loaders/svg/tvgSvgSceneBuilder.cpp b/src/loaders/svg/tvgSvgSceneBuilder.cpp index 5496ae8..ad5bdca 100644 --- a/src/loaders/svg/tvgSvgSceneBuilder.cpp +++ b/src/loaders/svg/tvgSvgSceneBuilder.cpp @@ -93,13 +93,13 @@ unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, Sha fillGrad->spread(g->spread); //Update the stops - stopCount = g->stops.size(); + stopCount = g->stops.cnt; if (stopCount > 0) { float opacity; float fopacity = fillOpacity / 255.0f; //fill opacity if any exists. - int i = 0; stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop)); - for (auto colorStop : g->stops) { + for (uint32_t i = 0; i < g->stops.cnt; ++i) { + auto colorStop = g->stops.list[i]; //Use premultiplied color opacity = ((float)colorStop->a / 255.0f) * fopacity; stops[i].r = colorStop->r * opacity; @@ -107,7 +107,6 @@ unique_ptr _applyLinearGradientProperty(SvgStyleGradient* g, Sha stops[i].b = colorStop->b * opacity; stops[i].a = colorStop->a * fopacity; stops[i].offset = colorStop->offset; - i++; } fillGrad->colorStops(stops, stopCount); free(stops); @@ -179,13 +178,13 @@ unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, Sha fillGrad->spread(g->spread); //Update the stops - stopCount = g->stops.size(); + stopCount = g->stops.cnt; if (stopCount > 0) { float opacity; float fopacity = fillOpacity / 255.0f; //fill opacity if any exists. - int i = 0; stops = (Fill::ColorStop*)calloc(stopCount, sizeof(Fill::ColorStop)); - for (auto colorStop : g->stops) { + for (uint32_t i = 0; i < g->stops.cnt; ++i) { + auto colorStop = g->stops.list[i]; //Use premultiplied color opacity = ((float)colorStop->a / 255.0f) * fopacity; stops[i].r = colorStop->r * opacity; @@ -193,7 +192,6 @@ unique_ptr _applyRadialGradientProperty(SvgStyleGradient* g, Sha stops[i].b = colorStop->b * opacity; stops[i].a = colorStop->a * fopacity; stops[i].offset = colorStop->offset; - i++; } fillGrad->colorStops(stops, stopCount); free(stops); @@ -335,11 +333,13 @@ unique_ptr _sceneBuildHelper(SvgNode* node, float vx, float vy, float vw, if (node->transform) scene->transform(*node->transform); node->style->opacity = (node->style->opacity * parentOpacity) / 255.0f; if (node->display) { - for (auto child : node->child) { - if (child->type == SvgNodeType::Doc || child->type == SvgNodeType::G) scene->push(_sceneBuildHelper(child, vx, vy, vw, vh, node->style->opacity)); - else { - child->style->opacity = (child->style->opacity * node->style->opacity) / 255.0f; - scene->push(_shapeBuildHelper(child, vx, vy, vw, vh)); + auto child = node->child.list; + for (uint32_t i = 0; i < node->child.cnt; ++i, ++child) { + if ((*child)->type == SvgNodeType::Doc || (*child)->type == SvgNodeType::G) { + scene->push(_sceneBuildHelper(*child, vx, vy, vw, vh, node->style->opacity)); + } else { + (*child)->style->opacity = ((*child)->style->opacity * node->style->opacity) / 255.0f; + scene->push(_shapeBuildHelper(*child, vx, vy, vw, vh)); } } } -- 2.7.4