From cb0fc7adaaa2cedd816140a1e3bf0f22abf9067d Mon Sep 17 00:00:00 2001 From: Mario Zechner Date: Thu, 16 May 2024 16:31:02 +0200 Subject: [PATCH] [flutter] Closes #2526, fix use after free error in dress-up. When setting a new skin in _toggleSkin, we first dispose the old skin, then set the new skin. However, setting the new skin will compare attachments against the still set but already freed old skin. We end up with use after free memory access. --- spine-flutter/example/lib/dress_up.dart | 3 +- spine-sfml/cpp/example/main.cpp | 38 ++++++++++++++----------- 2 files changed, 24 insertions(+), 17 deletions(-) diff --git a/spine-flutter/example/lib/dress_up.dart b/spine-flutter/example/lib/dress_up.dart index 7e071d49a..2626a87d7 100644 --- a/spine-flutter/example/lib/dress_up.dart +++ b/spine-flutter/example/lib/dress_up.dart @@ -69,6 +69,7 @@ class DressUpState extends State { void _toggleSkin(String skinName) { _selectedSkins[skinName] = !_selectedSkins[skinName]!; + _drawable.skeleton.setSkinByName("default"); if (_customSkin != null) _customSkin?.dispose(); _customSkin = Skin("custom-skin"); for (var skinName in _selectedSkins.keys) { @@ -78,7 +79,7 @@ class DressUpState extends State { } } _drawable.skeleton.setSkin(_customSkin!); - _drawable.skeleton.setToSetupPose(); + _drawable.skeleton.setSlotsToSetupPose(); } @override diff --git a/spine-sfml/cpp/example/main.cpp b/spine-sfml/cpp/example/main.cpp index bbb565e54..e6c9d0b61 100644 --- a/spine-sfml/cpp/example/main.cpp +++ b/spine-sfml/cpp/example/main.cpp @@ -573,19 +573,11 @@ void mixAndMatch(SkeletonData *skeletonData, Atlas *atlas) { Skeleton *skeleton = drawable.skeleton; - Skin skin("mix-and-match"); - skin.addSkin(skeletonData->findSkin("skin-base")); - skin.addSkin(skeletonData->findSkin("nose/short")); - skin.addSkin(skeletonData->findSkin("eyelids/girly")); - skin.addSkin(skeletonData->findSkin("eyes/violet")); - skin.addSkin(skeletonData->findSkin("hair/brown")); - skin.addSkin(skeletonData->findSkin("clothes/hoodie-orange")); - skin.addSkin(skeletonData->findSkin("legs/pants-jeans")); - skin.addSkin(skeletonData->findSkin("accessories/bag")); - skin.addSkin(skeletonData->findSkin("accessories/hat-red-yellow")); - - skeleton->setSkin(&skin); - skeleton->setSlotsToSetupPose(); + Skin *skin = new Skin("mix-and-match"); + skin->addSkin(skeletonData->findSkin("full-skins/girl")); + skin->addSkin(skeletonData->findSkin("accessories/cape-blue")); + skeleton->setSkin(skin); + skeleton->setToSetupPose(); skeleton->setPosition(320, 590); skeleton->updateWorldTransform(Physics_Update); @@ -596,9 +588,21 @@ void mixAndMatch(SkeletonData *skeletonData, Atlas *atlas) { window.setFramerateLimit(60); sf::Event event; sf::Clock deltaClock; + bool isCapeEquipped = true; while (window.isOpen()) { - while (window.pollEvent(event)) - if (event.type == sf::Event::Closed) window.close(); + while (window.pollEvent(event)) { + if (event.type == sf::Event::Closed) window.close(); + if (event.type == sf::Event::MouseButtonPressed && event.mouseButton.button == sf::Mouse::Left) { + skeleton->setSkin(nullptr); + delete skin; + isCapeEquipped = !isCapeEquipped; + skin = new Skin("mix-and-match"); + skin->addSkin(skeletonData->findSkin("full-skins/girl")); + if (isCapeEquipped) skin->addSkin(skeletonData->findSkin("accessories/cape-blue")); + skeleton->setSkin(skin); + skeleton->setSlotsToSetupPose(); + } + } float delta = deltaClock.getElapsedTime().asSeconds(); deltaClock.restart(); @@ -609,6 +613,8 @@ void mixAndMatch(SkeletonData *skeletonData, Atlas *atlas) { window.draw(drawable); window.display(); } + + delete skin; } void celestialCircus(SkeletonData *skeletonData, Atlas *atlas) { @@ -771,6 +777,7 @@ DebugExtension dbgExtension(SpineExtension::getInstance()); int main() { SpineExtension::setInstance(&dbgExtension); + testcase(mixAndMatch, "data/mix-and-match-pro.json", "data/mix-and-match-pro.skel", "data/mix-and-match-pma.atlas", 0.5f); testcase(cloudpot, "data/cloud-pot.json", "data/cloud-pot.skel", "data/cloud-pot-pma.atlas", 0.2); testcase(sack, "data/sack-pro.json", "data/sack-pro.skel", "data/sack-pma.atlas", 0.2f); testcase(celestialCircus, "data/celestial-circus-pro.json", "data/celestial-circus-pro.skel", "data/celestial-circus-pma.atlas", 0.2f); @@ -781,7 +788,6 @@ int main() { testcase(vine, "data/vine-pro.json", "data/vine-pro.skel", "data/vine-pma.atlas", 0.5f); testcase(dragon, "data/dragon-ess.json", "data/dragon-ess.skel", "data/dragon-pma.atlas", 0.6f); testcase(owl, "data/owl-pro.json", "data/owl-pro.skel", "data/owl-pma.atlas", 0.5f); - testcase(mixAndMatch, "data/mix-and-match-pro.json", "data/mix-and-match-pro.skel", "data/mix-and-match-pma.atlas", 0.5f); testcase(coin, "data/coin-pro.json", "data/coin-pro.skel", "data/coin-pma.atlas", 0.5f); testcase(raptor, "data/raptor-pro.json", "data/raptor-pro.skel", "data/raptor-pma.atlas", 0.5f); testcase(tank, "data/tank-pro.json", "data/tank-pro.skel", "data/tank-pma.atlas", 0.2f);