Skip to content

Commit 5c36bff

Browse files
committed
fix #547: Always stop threads owned by clones
Closes #547
1 parent e9364c5 commit 5c36bff

File tree

3 files changed

+41
-3
lines changed

3 files changed

+41
-3
lines changed

src/engine/internal/engine.cpp

Lines changed: 24 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -363,15 +363,33 @@ void Engine::start()
363363
void Engine::stop()
364364
{
365365
// https://github.com/scratchfoundation/scratch-vm/blob/f1aa92fad79af17d9dd1c41eeeadca099339a9f1/src/engine/runtime.js#L2057-L2081
366-
deleteClones();
367-
stopSounds();
368-
369366
if (m_activeThread) {
370367
stopThread(m_activeThread.get());
371368
// NOTE: The project should continue running even after "stop all" is called and the remaining threads should be stepped once.
372369
// The remaining threads can even start new threads which will ignore the "stop all" call and will "restart" the project.
373370
// This is probably a bug in the Scratch VM, but let's keep it here to keep it compatible.
374371
m_threadsToStop = m_threads;
372+
373+
// Remove threads owned by clones because clones are going to be deleted (#547)
374+
m_threads.erase(
375+
std::remove_if(
376+
m_threads.begin(),
377+
m_threads.end(),
378+
[](std::shared_ptr<VirtualMachine> thread) {
379+
assert(thread);
380+
Target *target = thread->target();
381+
assert(target);
382+
383+
if (!target->isStage()) {
384+
Sprite *sprite = static_cast<Sprite *>(target);
385+
386+
if (sprite->isClone())
387+
return true;
388+
}
389+
390+
return false;
391+
}),
392+
m_threads.end());
375393
} else {
376394
// If there isn't any active thread, it means the project was stopped from the outside
377395
// In this case all threads should be removed and the project should be considered stopped
@@ -383,6 +401,9 @@ void Engine::stop()
383401
m_threads.clear();
384402
m_running = false;
385403
}
404+
405+
deleteClones();
406+
stopSounds();
386407
}
387408

388409
VirtualMachine *Engine::startScript(std::shared_ptr<Block> topLevelBlock, Target *target)

test/engine/engine_test.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2251,3 +2251,20 @@ TEST(EngineTest, NoCrashWithUndefinedVariableOrList)
22512251
ASSERT_EQ(list->id(), "}l+w#Er5y!:*gh~5!3t%");
22522252
ASSERT_TRUE(list->empty());
22532253
}
2254+
2255+
TEST(EngineTest, AlwaysStopCloneThreads)
2256+
{
2257+
// Regtest for #547
2258+
Project p("regtest_projects/547_stop_clone_threads_in_stop_all.sb3");
2259+
ASSERT_TRUE(p.load());
2260+
2261+
auto engine = p.engine();
2262+
2263+
Stage *stage = engine->stage();
2264+
ASSERT_TRUE(stage);
2265+
2266+
engine->run();
2267+
2268+
ASSERT_VAR(stage, "test");
2269+
ASSERT_EQ(GET_VAR(stage, "test")->value().toInt(), 0);
2270+
}
Binary file not shown.

0 commit comments

Comments
 (0)