renderer/paint: fixed a mismatched reference count.

This correction ensures a consistent use of 'ref' and 'unref' for paints to release memory properly.
The memory leak occurred when a picture was not pushed to a valid canvas.

This issue was reported by the unit-test memory sanitizer.
This commit is contained in:
Hermet Park 2023-09-25 23:39:28 +09:00 committed by Hermet Park
parent 2fb0cc8309
commit 1819fed033
8 changed files with 17 additions and 8 deletions

View file

@ -304,6 +304,7 @@ unique_ptr<Paint> LottieLoader::paint()
{ {
this->done(); this->done();
if (!comp) return nullptr; if (!comp) return nullptr;
comp->initiated = true;
return cast<Paint>(comp->scene); return cast<Paint>(comp->scene);
} }

View file

@ -158,6 +158,8 @@ int32_t LottieLayer::remap(int32_t frameNo)
LottieComposition::~LottieComposition() LottieComposition::~LottieComposition()
{ {
if (!initiated) delete(scene);
delete(root); delete(root);
free(version); free(version);
free(name); free(name);

View file

@ -585,6 +585,7 @@ struct LottieComposition
float frameRate; float frameRate;
Array<LottieObject*> assets; Array<LottieObject*> assets;
Array<LottieInterpolator*> interpolators; Array<LottieInterpolator*> interpolators;
bool initiated = false;
}; };
#endif //_TVG_LOTTIE_MODEL_H_ #endif //_TVG_LOTTIE_MODEL_H_

View file

@ -36,12 +36,12 @@ struct Animation::Impl
Impl() Impl()
{ {
picture = Picture::gen().release(); picture = Picture::gen().release();
static_cast<Paint*>(picture)->pImpl->ref(); PP(picture)->ref();
} }
~Impl() ~Impl()
{ {
if (static_cast<Paint*>(picture)->pImpl->unref() == 0) { if (PP(picture)->unref() == 0) {
delete(picture); delete(picture);
} }
} }

View file

@ -53,6 +53,7 @@ struct Canvas::Impl
auto p = paint.release(); auto p = paint.release();
if (!p) return Result::MemoryCorruption; if (!p) return Result::MemoryCorruption;
PP(p)->ref();
paints.push_back(p); paints.push_back(p);
return update(p, true); return update(p, true);
@ -66,8 +67,9 @@ struct Canvas::Impl
//Free paints //Free paints
if (free) { if (free) {
for (auto paint : paints) { for (auto paint : paints) {
if (paint->pImpl->dispose(*renderer)) { P(paint)->unref();
if (paint->pImpl->unref() == 0) delete(paint); if (paint->pImpl->dispose(*renderer) && P(paint)->refCnt == 0) {
delete(paint);
} }
} }
paints.clear(); paints.clear();

View file

@ -68,7 +68,7 @@ namespace tvg
uint8_t ctxFlag = ContextFlag::Invalid; uint8_t ctxFlag = ContextFlag::Invalid;
uint8_t id; uint8_t id;
uint8_t opacity = 255; uint8_t opacity = 255;
uint8_t refCnt = 1; uint8_t refCnt = 0;
~Impl() ~Impl()
{ {

View file

@ -55,6 +55,7 @@ Result Scene::push(unique_ptr<Paint> paint) noexcept
{ {
auto p = paint.release(); auto p = paint.release();
if (!p) return Result::MemoryCorruption; if (!p) return Result::MemoryCorruption;
PP(p)->ref();
pImpl->paints.push_back(p); pImpl->paints.push_back(p);
return Result::Success; return Result::Success;

View file

@ -220,7 +220,9 @@ struct Scene::Impl
auto dup = ret.get()->pImpl; auto dup = ret.get()->pImpl;
for (auto paint : paints) { for (auto paint : paints) {
dup->paints.push_back(paint->duplicate()); auto cdup = paint->duplicate();
P(cdup)->ref();
dup->paints.push_back(cdup);
} }
return ret.release(); return ret.release();
@ -231,8 +233,8 @@ struct Scene::Impl
auto dispose = renderer ? true : false; auto dispose = renderer ? true : false;
for (auto paint : paints) { for (auto paint : paints) {
if (dispose) free &= paint->pImpl->dispose(*renderer); if (dispose) free &= P(paint)->dispose(*renderer);
if (free) delete(paint); if (P(paint)->unref() == 0 && free) delete(paint);
} }
paints.clear(); paints.clear();
renderer = nullptr; renderer = nullptr;