svg_loader: fix vector memory leaks.
authorHermet Park <chuneon.park@samsung.com>
Tue, 1 Sep 2020 11:13:07 +0000 (20:13 +0900)
committerHermet Park <chuneon.park@samsung.com>
Wed, 2 Sep 2020 04:07:09 +0000 (13:07 +0900)
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
src/loaders/svg/tvgSvgLoaderCommon.h
src/loaders/svg/tvgSvgSceneBuilder.cpp

index fedf8a9..6367fc4 100644 (file)
@@ -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<SvgNode*>::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<Fill::ColorStop*> *dst, vector<Fill::ColorStop*> src)
+static void _cloneGradStops(SvgVector<Fill::ColorStop*>* dst, SvgVector<Fill::ColorStop*>* src)
 {
-    for (auto colorStop : src) {
-         auto stop = static_cast<Fill::ColorStop *>(malloc(sizeof(Fill::ColorStop)));
-         *stop = *colorStop;
-         dst->push_back(stop);
+    for (uint32_t i = 0; i < src->cnt; ++i) {
+        auto stop = static_cast<Fill::ColorStop *>(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 <svg>(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<SvgNode*>::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<SvgStyleGradient*> gradList, string* id)
+static SvgStyleGradient* _gradientDup(SvgVector<SvgStyleGradient*>* gradients, string* id)
 {
     SvgStyleGradient* result = nullptr;
 
-    for (vector<SvgStyleGradient*>::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<SvgStyleGradient*>::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<SvgStyleGradient*> gradList, string
 }
 
 
-static void _updateGradient(SvgNode* node, vector<SvgStyleGradient*> gradList)
+static void _updateGradient(SvgNode* node, SvgVector<SvgStyleGradient*>* gradidents)
 {
-    if (!node->child.empty()) {
-        for (vector<SvgNode*>::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<SvgStyleGradient*>::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<SvgStyleGradient*> 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;
 }
index bba9523..f579c59 100644 (file)
@@ -119,6 +119,35 @@ enum class SvgParserLengthType
 struct SvgNode;
 struct SvgStyleGradient;
 
+template<class T>
+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<T*>(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<SvgStyleGradient *> gradients;
+    SvgVector<SvgStyleGradient*> gradients;
 };
 
 struct SvgArcNode
@@ -240,7 +269,7 @@ struct SvgStyleGradient
     SvgRadialGradient* radial;
     SvgLinearGradient* linear;
     Matrix* transform;
-    vector<Fill::ColorStop *> stops;
+    SvgVector<Fill::ColorStop *> stops;
     bool userSpace;
     bool usePercentage;
 };
@@ -281,7 +310,7 @@ struct SvgNode
 {
     SvgNodeType type;
     SvgNode* parent;
-    vector<SvgNode*> child;
+    SvgVector<SvgNode*> child;
     string *id;
     SvgStyleProperty *style;
     Matrix* transform;
@@ -320,10 +349,10 @@ struct SvgParser
 
 struct SvgLoaderData
 {
-    vector<SvgNode *> stack;
+    SvgVector<SvgNode *> stack = {nullptr, 0, 0};
     SvgNode* doc = nullptr;
     SvgNode* def = nullptr;
-    vector<SvgStyleGradient*> gradients;
+    SvgVector<SvgStyleGradient*> gradients;
     SvgStyleGradient* latestGradient = nullptr; //For stops
     SvgParser* svgParse = nullptr;
     int level = 0;
index 5496ae8..ad5bdca 100644 (file)
@@ -93,13 +93,13 @@ unique_ptr<LinearGradient> _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<LinearGradient> _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<RadialGradient> _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<RadialGradient> _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<Scene> _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));
                 }
             }
         }