[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.
This commit is contained in:
Mario Zechner 2024-05-16 16:31:02 +02:00
parent a911384e67
commit cb0fc7adaa
2 changed files with 24 additions and 17 deletions

View File

@ -69,6 +69,7 @@ class DressUpState extends State<DressUp> {
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<DressUp> {
}
}
_drawable.skeleton.setSkin(_customSkin!);
_drawable.skeleton.setToSetupPose();
_drawable.skeleton.setSlotsToSetupPose();
}
@override

View File

@ -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))
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);