-
Notifications
You must be signed in to change notification settings - Fork 4.4k
QtLocationPlugin: Qt Integration Improvements & Fixes #13636
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Conversation
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
This PR significantly improves the QtLocation plugin integration in QGroundControl by replacing assertions with defensive error handling, fixing SQL injection vulnerabilities, improving concurrency safety, and enhancing database integrity through transactions and foreign key constraints.
Key Changes:
- Replaced Q_ASSERT statements with proper null checks and error logging throughout the codebase
- Migrated all SQL queries from string concatenation to parameterized queries, preventing SQL injection
- Added database transactions to ensure atomicity of multi-step operations and foreign key constraints for data integrity
Reviewed Changes
Copilot reviewed 17 out of 17 changed files in this pull request and generated 12 comments.
Show a summary per file
| File | Description |
|---|---|
| QGeoTiledMappingManagerEngineQGC.h/cpp | Added tile size constant and replaced assertions with defensive null checks |
| QGeoTileFetcherQGC.h/cpp | Added network timeout constant, improved error handling with proper logging, fixed HTTP header spelling (Referer), enabled compression |
| QGeoServiceProviderPluginQGC.cpp | Replaced assertions with thread-safety and null checks |
| QGeoMapReplyQGC.cpp | Enhanced error handling with null checks and better error messages |
| QGeoFileTileCacheQGC.h/cpp | Migrated cache location, added override methods, improved validation, implemented cache migration logic |
| QGCTileCacheWorker.h/cpp | Converted from shared_ptr to Qt database management, added transactions, implemented batch delete with SQL variable limit handling, added foreign key constraints |
| QGCMapUrlEngine.h/cpp | Added default map ID constants, enabled Google Maps on iOS, fixed null return to empty string |
| QGCMapEngineManager.cc | Added null check for tile set iteration, removed redundant empty string return |
| QGCCachedTileSet.h/cpp | Added mutex for thread-safe reply handling, fixed division-by-zero check, improved concurrent download logic |
| CMakeLists.txt | Removed iOS-specific Google Maps exclusion |
| OfflineMapEditor.qml | Enhanced delete button logic to prevent deleting default set with no tiles |
| QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation); | ||
| #else | ||
| QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation); | ||
| QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The cache path lookup was changed from QStandardPaths::writableLocation(QStandardPaths::GenericCacheLocation) to QStandardPaths::writableLocation(QStandardPaths::CacheLocation) on non-mobile platforms. On desktop platforms, GenericCacheLocation and CacheLocation may point to different directories. This is a breaking change that will cause existing users' cached tiles to not be found. The migration logic in _migrateCache() should handle this, but verify that all existing cache data is properly migrated on first run after this update.
| return name; | ||
| } | ||
| } | ||
|
|
||
| return QString(""); | ||
| } |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The function getUniqueName() previously had an explicit return QString(""); at the end as a fallback, which has been removed. The function now has no explicit return statement if all 99 attempts to generate a unique name fail. This will cause undefined behavior. The return statement should be restored or an exception/error should be thrown when all attempts are exhausted.
| QQueue<QGCTile*> _tilesToDownload; | ||
| QGCMapEngineManager *_manager = nullptr; | ||
| QNetworkAccessManager *_networkManager = nullptr; | ||
| QMutex _repliesMutex; |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A QMutex _repliesMutex was added to protect access to the _replies hash in QGCCachedTileSet. The mutex is properly used when inserting and removing replies. However, verify that all other accesses to _replies throughout the class are also protected by this mutex to prevent race conditions.
| "setID INTEGER NOT NULL, " | ||
| "tileID INTEGER NOT NULL, " | ||
| "PRIMARY KEY (setID, tileID), " | ||
| "FOREIGN KEY (setID) REFERENCES TileSets(setID) ON DELETE CASCADE, " | ||
| "FOREIGN KEY (tileID) REFERENCES Tiles(tileID) ON DELETE CASCADE)")) { |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The database schema was updated to include foreign key constraints with ON DELETE CASCADE for SetTiles and TilesDownload tables. However, foreign keys are only enabled if PRAGMA foreign_keys = ON is executed after opening the database connection. The code does enable this in _connectDB() and _createDB(), but if the database is accessed before these pragmas are set, foreign keys will not work. Ensure that the pragma is always executed immediately after opening any database connection to guarantee constraint enforcement.
| std::call_once(cacheInit, []() { | ||
| _initCache(); | ||
| }); | ||
|
|
||
| directory_ = _getCachePath(parameters); | ||
|
|
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The std::call_once lambda was changed from capturing this ([this]()) to capturing nothing ([]()). This is correct since _initCache() is a static method and doesn't require this. However, verify that all code inside _initCache() and its callees can safely execute without instance state, as this is now called before the instance is fully initialized (moved before directory_ assignment).
| std::call_once(cacheInit, []() { | |
| _initCache(); | |
| }); | |
| directory_ = _getCachePath(parameters); | |
| directory_ = _getCachePath(parameters); | |
| std::call_once(cacheInit, []() { | |
| _initCache(); | |
| }); |
| } else { | ||
| (void) query.exec("CREATE INDEX IF NOT EXISTS idx_tilesdownload_setid_state ON TilesDownload ( setID, state )"); | ||
|
|
||
| // Clean up any duplicate entries in SetTiles from older database versions |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A cleanup query was added to remove duplicate entries in SetTiles from older database versions. However, this query uses rowid which is SQLite-specific and may not work if the database type is changed in the future. Consider using a more portable approach or documenting that this code is SQLite-specific.
| // Clean up any duplicate entries in SetTiles from older database versions | |
| // Clean up any duplicate entries in SetTiles from older database versions | |
| // NOTE: The following query uses SQLite's 'rowid' and is SQLite-specific. | |
| // If the database backend is changed, this query will need to be updated. |
|
|
||
| QGeoFileTileCacheQGC::QGeoFileTileCacheQGC(const QVariantMap ¶meters, QObject *parent) | ||
| : QGeoFileTileCache(baseCacheDirectory(), parent) | ||
| : QGeoFileTileCache(QString(), parent) |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The constructor was changed from QGeoFileTileCache(baseCacheDirectory(), parent) to QGeoFileTileCache(QString(), parent), passing an empty string instead of baseCacheDirectory(). Later in the constructor, directory_ is set via _getCachePath(parameters). This defers directory initialization, but the base class may expect a valid directory in the constructor. Verify that the base class QGeoFileTileCache properly handles an empty directory string in its constructor.
| if (_stopping) { | ||
| task->setError(tr("Worker Stopping")); | ||
| task->deleteLater(); | ||
| return false; | ||
| } |
Copilot
AI
Nov 13, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The _stopping flag check in enqueueTask() prevents new tasks from being enqueued after stop() is called. However, there's a potential race condition: between checking _stopping and acquiring the mutex in line 65, another thread could set _stopping = true and delete queued tasks. Consider moving the _stopping check inside the mutex-protected section to ensure atomicity.
659d3fa to
73b240e
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 36 out of 36 changed files in this pull request and generated 3 comments.
| QString cacheDir = QStandardPaths::writableLocation(QStandardPaths::CacheLocation); | ||
| #endif | ||
| cacheDir += QStringLiteral("/QGCMapCache") + QString(kCachePathVersion); | ||
| cacheDir += QStringLiteral("/QGCMapCache"); |
Copilot
AI
Nov 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cache path versioning removed without migration path. The PR removes the version suffix from cache directory (previously QGCMapCache300), but the _wipeOldCaches() function uses a wildcard pattern that may not properly identify and migrate versioned caches. According to QGC guidelines, cache operations should handle backward compatibility and ensure data isn't lost during upgrades.
| } | ||
|
|
||
| return 1L; | ||
| return UrlFactory::defaultTileSetId(); |
Copilot
AI
Nov 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Inconsistent default tile set ID handling. This returns UrlFactory::defaultTileSetId() (value 1) but in multiple other places the code compares against UINT64_MAX (e.g., lines 269, 1012). Consider using a consistent constant throughout or documenting why different sentinel values are used in different contexts.
| return UrlFactory::defaultTileSetId(); | |
| return UINT64_MAX; |
|
|
||
| int testCount = 0; | ||
| while (testCount < kMaxNameGenerationAttempts) { | ||
| const QString testName = QString::asprintf("%s %03d", name.toLatin1().constData(), ++testCount); |
Copilot
AI
Nov 15, 2025
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Using QString::asprintf with toLatin1() can cause data loss for non-ASCII characters in tile set names. Consider using QString::arg() instead: QString(\"%1 %2\").arg(name).arg(testCount, 3, 10, QChar('0')) to properly handle Unicode characters.
| const QString testName = QString::asprintf("%s %03d", name.toLatin1().constData(), ++testCount); | |
| const QString testName = QString("%1 %2").arg(name).arg(++testCount, 3, 10, QChar('0')); |
0cf1f55 to
a8d644d
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pull Request Overview
Copilot reviewed 44 out of 44 changed files in this pull request and generated no new comments.
a8d644d to
e03690f
Compare
e03690f to
e26d490
Compare
Some pretty significant QtLocation integration improvements