fix(camp): close GDAL/OGR handle leaks in chart/vector loading (#152)#159
Merged
Conversation
added 6 commits
June 30, 2026 11:31
Virtual destructor for Georeferenced + RAII fixes in VectorDataset::open
Every chart load leaked GDAL/OGR handles (valgrind-confirmed ~180 KB of OGR/PROJ state per Georeferenced instance, growing across a session): - Georeferenced had no destructor, so its two OGRCoordinateTransformation members (created in extractGeoreference) leaked per DepthRaster / VectorDataset. Add a virtual ~Georeferenced() that DestroyCT's both; the dtor is virtual because both subclasses are deleted through a base subobject. Rule-of-three: =delete copy ctor/assignment now that the class owns handles (both subclasses are heap-only, so no live call site changes). - VectorDataset::open never GDALClose'd the dataset, never destroyed the per-layer transformation, and never destroyed any OGRPointIterator. Fixes: RAII-close the dataset; destroy the transformation at end-of-layer (else all but the last layer leaked); destroy every iterator at its site, including the interior-ring iterator inside the ring loop. To make the leak path testable without standing up the whole application (open() built the project item graph + connected to AutonomousVehicleProject, which would drag ~all app TUs into a test), split the pure parse into a new MissionItem-free TU: camp::vector::parseVectorLayers(GDALDataset*) returns plain WGS84 geometry and owns the transform + iterator lifecycle. open() now RAII-opens the dataset, calls extractGeoreference, then buildItems(parseVectorLayers(...)); buildItems holds the unchanged item-graph construction. Per-geometry coordinate handling preserved verbatim. Tests: - test_vector_dataset_cleanup (new): links the standalone vector_parse TU; synthetic 2-layer GeoPackage (point + linestring + polygon-with-hole per layer) exercises every parse/iterator site; asserts the parse is non-vacuous and the GDAL open-dataset count returns to baseline. - test_depth_raster: add a baseline-delta test guarding the pre-existing DepthRaster GDALClose. The OGRCoordinateTransformation handles (the primary ~180 KB leak) are not visible to GetOpenDatasets(), so they are proven closed under valgrind: valgrind --leak-check=full on both test binaries reports "definitely lost: 0 bytes, indirectly lost: 0 bytes". Closes #152
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Closes #152. Every chart load leaked GDAL/OGR handles, valgrind-confirmed at ~180 KB of OGR/PROJ state per
Georeferencedinstance, growing monotonically across a session.Two leak sites fixed:
Georeferencedhad no destructor — its twoOGRCoordinateTransformationmembers (created inextractGeoreference) leaked perDepthRaster/VectorDataset. Added avirtual ~Georeferenced()thatDestroyCTs both.virtual: defensive future-proofing — today neither subclass is deleted through aGeoreferenced*(DepthRasterasDepthRaster*,VectorDatasetvia the QObject parent chain), so the dtor runs regardless;virtualkeeps delete-through-base correct if that ever changes.= deletecopy ctor/assignment now that the class owns handles (both subclasses are heap-only, so no live call site changes).VectorDataset::openneverGDALClosed the dataset, never destroyed the per-layer transformation, and never destroyed anyOGRPointIterator. Fixes: RAII-close the dataset; per-layer transformation freed by RAII (unique_ptr+DestroyCTdeleter) at end-of-layer (previously all but the last layer leaked); every iterator destroyed at its site, including the interior-ring iterator inside the ring loop.Testable seam (refactor)
open()interleaved the GDAL/OGR resource lifecycle with building the project item graph (Point/LineString/Polygon+connect(autonomousVehicleProject(), …)), so any test drivingopen()would link ~all 52 app TUs and stand up aQApplication-backedAutonomousVehicleProject. The pure parse is split into a MissionItem-free TU:vector/vector_parse.{h,cpp}—camp::vector::parseVectorLayers(GDALDataset*)returns plain WGS84 geometry (ParsedLayer/ParsedGeometry) and owns the transform + iterator lifecycle.open()→ RAII-open dataset,extractGeoreference, thenbuildItems(parseVectorLayers(...)).buildItemsholds the unchanged item-graph construction; per-geometry coordinate handling preserved verbatim.Tests
test_vector_dataset_cleanup(new) — links the standalonevector_parseTU (no item graph); synthetic 2-layer GeoPackage (point + linestring + polygon-with-hole per layer) exercises every parse/iterator site; asserts the parse is non-vacuous and the GDAL open-dataset count returns to baseline.test_depth_raster— added a baseline-delta test guarding the pre-existingDepthRasterGDALClose.The
OGRCoordinateTransformationhandles (the primary ~180 KB leak) are not visible toGetOpenDatasets(), so they are proven closed under valgrind:Full package suite: 154 tests, 0 failures.
Review
Local pre-push review (
/run-issue): approved, Ship: recommended (zero must-fix; two adversarial passes confirmed behavior-preserving + leak-free). Two review suggestions folded (RAII exception-safety on the per-layer transform; corrected the~Georeferencedcomment); the third (attach valgrind output) is the block above.Authored-By:
Claude Code AgentModel:
Claude Opus 4.8