History

Fix memory corruption via lambdas that capture local variables by reference.

The lambdas in ScriptEngine::fetchModuleSource() were referencing local stack variables by reference. This could lead to un-expected results including memory corruption. To workaround this issue the QTimer and QEventLoop variables are allocated on the heap and held onto by a shared_ptr. This shared_ptr is passed to the lambda. This will not result in cycles and should result in the QTimer and QEventLoop being destroyed when the BatchLoader object they are connected to is deleted.

Anthony J. Thibault committed 8 years ago

Commit ac6fcf01 parent 7fb2e531 file · +11 −9Browse files

Showing the changes to libraries/script-engine/src/ScriptEngine.cpp (1 of 1 file). Show all

Unified · Split

libraries/script-engine/src/ScriptEngine.cpp+11−9
@@ -1639,22 +1639,24 @@ QVariantMap ScriptEngine::fetchModuleSource(const QString& modulePath, const boo · 1638 unmodified lines
16391639 loader->start(MAX_RETRIES);
16401640
16411641 if (!loader->isFinished()) {
1642− QTimer monitor;
1643− QEventLoop loop;
1644− QObject::connect(loader, &BatchLoader::finished, this, [&monitor, &loop]{
1645− monitor.stop();
1646− loop.quit();
1642+ // This lambda can get called AFTER this local scope has completed.
1643+ // This is why we pass smart ptrs to the lambda instead of references to local variables.
1644+ auto monitor = std::make_shared<QTimer>();
1645+ auto loop = std::make_shared<QEventLoop>();
1646+ QObject::connect(loader, &BatchLoader::finished, this, [monitor, loop] {
1647+ monitor->stop();
1648+ loop->quit();
16471649 });
16481650
16491651 // this helps detect the case where stop() is invoked during the download
16501652 // but not seen in time to abort processing in onload()...
1651− connect(&monitor, &QTimer::timeout, this, [this, &loop]{
1653+ connect(monitor.get(), &QTimer::timeout, this, [this, loop] {
16521654 if (isStopping()) {
1653− loop.exit(-1);
1655+ loop->exit(-1);
16541656 }
16551657 });
1656− monitor.start(500);
1657− loop.exec();
1658+ monitor->start(500);
1659+ loop->exec();
16581660 }
16591661 loader->deleteLater();
16601662 return req;