From 774528725be4b9d75d047aa1e0ce5744b685f30b Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 26 Feb 2022 19:37:07 +0300 Subject: [PATCH 1/8] Do default initialization of key frame values --- src/lottie/lottiemodel.h | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index 3e043085..c3845bbb 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -157,8 +157,8 @@ struct PathData { template struct Value { - T start_; - T end_; + T start_{}; + T end_{}; T at(float t) const { return lerp(start_, end_, t); } float angle(float) const { return 0; } void cache() {} @@ -168,10 +168,10 @@ struct Position; template struct Value { - T start_; - T end_; - T inTangent_; - T outTangent_; + T start_{}; + T end_{}; + T inTangent_{}; + T outTangent_{}; float length_{0}; bool hasTangent_{false}; From 7446363b482978746bd6e7b5dbc4f49553f9f50f Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 26 Feb 2022 19:40:16 +0300 Subject: [PATCH 2/8] Check that animation has frames before accessing --- src/lottie/lottiemodel.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index c3845bbb..7552c7d9 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -340,6 +340,7 @@ class Property { value().toPath(path); } else { const auto &vec = animation().frames_; + if (vec.empty()) return; if (vec.front().start_ >= frameNo) return vec.front().value_.start_.toPath(path); if (vec.back().end_ <= frameNo) From e3c63189c3b17fe7168f6fc0dda6110dd4fb0d32 Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 26 Feb 2022 20:00:21 +0300 Subject: [PATCH 3/8] Deal with cyclic structures, avoid stack overflow in Lottie model --- src/lottie/lottieitem.cpp | 4 ++++ src/lottie/lottiemodel.cpp | 25 +++++++++++++++++++++++++ src/lottie/lottiemodel.h | 1 + 3 files changed, 30 insertions(+) diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index cb1bc2cd..11a0844a 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -77,6 +77,10 @@ static renderer::Layer *createLayerItem(model::Layer *layerData, { switch (layerData->mLayerType) { case model::Layer::Type::Precomp: { + model::Composition *comp = layerData->extra()->mCompRef; + if (comp && comp->mRootLayer->includes(layerData)) { + return nullptr; + } return allocator->make(layerData, allocator); } case model::Layer::Type::Solid: { diff --git a/src/lottie/lottiemodel.cpp b/src/lottie/lottiemodel.cpp index 1bca99d2..1945b68a 100644 --- a/src/lottie/lottiemodel.cpp +++ b/src/lottie/lottiemodel.cpp @@ -23,12 +23,27 @@ #include "lottiemodel.h" #include #include +#include #include #include "vimageloader.h" #include "vline.h" using namespace rlottie::internal; +bool model::Group::includes(model::Group *pointer) { + if (this == pointer) { + return true; + } + for (Object *child : mChildren) { + if ((child->type() == Type::Group || child->type() == Type::Layer) + && this != child + && static_cast(child)->includes(pointer)) { + return true; + } + } + return false; +} + /* * We process the iterator objects in the children list * by iterating from back to front. when we find a repeater object @@ -79,6 +94,8 @@ class LottieRepeaterProcesser { void visit(model::Object *obj) { + if (!mVisited.insert(obj).second) return; + switch (obj->type()) { case model::Object::Type::Group: case model::Object::Type::Layer: { @@ -89,6 +106,9 @@ class LottieRepeaterProcesser { break; } } + +private: + std::set mVisited; }; class LottieUpdateStatVisitor { @@ -127,6 +147,8 @@ class LottieUpdateStatVisitor { } void visit(model::Object *obj) { + if (!mVisited.insert(obj).second) return; + switch (obj->type()) { case model::Object::Type::Layer: { visitLayer(static_cast(obj)); @@ -144,6 +166,9 @@ class LottieUpdateStatVisitor { break; } } + +private: + std::set mVisited; }; void model::Composition::processRepeaterObjects() diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index 7552c7d9..f2c8ff35 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -660,6 +660,7 @@ class Group : public Object { public: Group() : Object(Object::Type::Group) {} explicit Group(Object::Type type) : Object(type) {} + bool includes(Group *); public: std::vector mChildren; From 19fc8e9c2804ccfba5bee3eb18bc952a87684490 Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 26 Feb 2022 20:05:54 +0300 Subject: [PATCH 4/8] Points counter must be positive --- src/lottie/lottieitem.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/lottie/lottieitem.cpp b/src/lottie/lottieitem.cpp index 11a0844a..d2ef838d 100644 --- a/src/lottie/lottieitem.cpp +++ b/src/lottie/lottieitem.cpp @@ -1163,6 +1163,11 @@ void renderer::Polystar::updatePath(VPath &path, int frameNo) path.reset(); VMatrix m; + if (!(points > 0)) { + vWarning << "The number of path points is below zero or NaN at all"; + return; + } + if (mData->mPolyType == model::Polystar::PolyType::Star) { path.addPolystar(points, innerRadius, outerRadius, innerRoundness, outerRoundness, 0.0, 0.0, 0.0, mData->direction()); From f7b72f1ed133882f1d5a75ede5fe6b6fc4cbea1d Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 26 Feb 2022 20:11:25 +0300 Subject: [PATCH 5/8] =?UTF-8?q?Stop=20computing=20B=C3=A9zier=20curve=20le?= =?UTF-8?q?ngth=20when=20float=20overflow=20occurs=20after=20splitting?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/vector/vbezier.cpp | 8 +++++++- src/vector/vbezier.h | 13 +++++++++++++ 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/src/vector/vbezier.cpp b/src/vector/vbezier.cpp index 15889299..ea8745f9 100644 --- a/src/vector/vbezier.cpp +++ b/src/vector/vbezier.cpp @@ -52,7 +52,13 @@ float VBezier::length() const if ((len - chord) > 0.01) { VBezier left, right; split(&left, &right); - return left.length() + right.length(); + + float sum = 0; + if (*this != left) + sum += left.length(); + if (*this != right) + sum += right.length(); + return sum; } return len; diff --git a/src/vector/vbezier.h b/src/vector/vbezier.h index 18b7c596..df18c4f9 100644 --- a/src/vector/vbezier.h +++ b/src/vector/vbezier.h @@ -23,11 +23,14 @@ #ifndef VBEZIER_H #define VBEZIER_H +#include #include V_BEGIN_NAMESPACE class VBezier { + friend bool operator == (const VBezier &l, const VBezier &r); + public: VBezier() = default; VPointF pointAt(float t) const; @@ -134,6 +137,16 @@ inline void VBezier::split(VBezier *firstHalf, VBezier *secondHalf) const firstHalf->y4 = secondHalf->y1 = (firstHalf->y3 + secondHalf->y2) * 0.5f; } +inline bool operator == (const VBezier &l, const VBezier &r) +{ + return std::tie(l.x1, l.y1, l.x2, l.y2, l.x3, l.y3, l.x4, l.y4) + == std::tie(r.x1, r.y1, r.x2, r.y2, r.x3, r.y3, r.x4, r.y4); +} +inline bool operator != (const VBezier &l, const VBezier &r) +{ + return !(l == r); +} + V_END_NAMESPACE #endif // VBEZIER_H From a81585d39d2618a32dbd5c177d63f0bdb0549b2b Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 5 Mar 2022 22:52:31 +0300 Subject: [PATCH 6/8] Check overflow of outline points in ft_stroke_border_export() --- src/vector/freetype/v_ft_stroker.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/vector/freetype/v_ft_stroker.cpp b/src/vector/freetype/v_ft_stroker.cpp index 3160f84f..e53f51da 100644 --- a/src/vector/freetype/v_ft_stroker.cpp +++ b/src/vector/freetype/v_ft_stroker.cpp @@ -18,6 +18,7 @@ #include "v_ft_stroker.h" #include +#include #include #include #include "v_ft_math.h" @@ -626,6 +627,8 @@ static SW_FT_Error ft_stroke_border_get_counts(SW_FT_StrokeBorder border, static void ft_stroke_border_export(SW_FT_StrokeBorder border, SW_FT_Outline* outline) { + if ((unsigned long)outline->n_points + border->num_points > SHRT_MAX) return; + /* copy point locations */ memcpy(outline->points + outline->n_points, border->points, border->num_points * sizeof(SW_FT_Vector)); From a3984b60e861555624b7d9b7966e79d2c3093765 Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 5 Mar 2022 22:59:54 +0300 Subject: [PATCH 7/8] Touch up negative segment start and end values NaN values are also zeroed. --- src/lottie/lottiemodel.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/lottie/lottiemodel.h b/src/lottie/lottiemodel.h index f2c8ff35..b1161400 100644 --- a/src/lottie/lottiemodel.h +++ b/src/lottie/lottiemodel.h @@ -1055,8 +1055,8 @@ class Trim : public Object { private: Segment noloop(float start, float end) const { - assert(start >= 0); - assert(end >= 0); + if (!(start >= 0)) start = 0; + if (!(end >= 0)) end = 0; Segment s; s.start = std::min(start, end); s.end = std::max(start, end); @@ -1064,8 +1064,8 @@ class Trim : public Object { } Segment loop(float start, float end) const { - assert(start >= 0); - assert(end >= 0); + if (!(start >= 0)) start = 0; + if (!(end >= 0)) end = 0; Segment s; s.start = std::max(start, end); s.end = std::min(start, end); From 0b7d6354c3f76848d87fac4a15e12c7b3401a17f Mon Sep 17 00:00:00 2001 From: Nicholas Guriev Date: Sat, 5 Mar 2022 23:03:26 +0300 Subject: [PATCH 8/8] Realize a lock at any end of VRleTask --- src/vector/vraster.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/vector/vraster.cpp b/src/vector/vraster.cpp index fdf66fb0..007b56e4 100644 --- a/src/vector/vraster.cpp +++ b/src/vector/vraster.cpp @@ -373,6 +373,7 @@ struct VRleTask { { if (mPath.points().size() > SHRT_MAX || mPath.points().size() + mPath.segments() > SHRT_MAX) { + mRle.notify(); return; }