Skip to content
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

Fix use-after-free in Dataset::close #420

Merged
merged 2 commits into from
Aug 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
# Changes

## Unreleased
- **Breaking**: `Dataset::close` now consumes `self`

- <https://github.com/georust/gdal/pull/420>

- `Gcp` and `GcpRef` are now public

- <https://github.com/georust/gdal/pull/421>
Expand Down
27 changes: 20 additions & 7 deletions src/dataset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ impl GeoTransformEx for GeoTransform {
#[derive(Debug)]
pub struct Dataset {
c_dataset: GDALDatasetH,
closed: bool,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We could also have a wrapper around c_dataset and use ManuallyDrop on that instead.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ManuallyDrop sounds nice

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I switched to ManuallyDrop in 2e4b75e, but I'm not sure it's much better.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Scratch that, it doesn't really work, because the inner type's drop still runs, and we can't get the return value of GDALClose out of there. I'll revert to the previous version.

}

// These are skipped by bindgen and manually updated.
Expand Down Expand Up @@ -399,7 +400,10 @@ impl Dataset {
if c_dataset.is_null() {
return Err(_last_null_pointer_err("GDALOpenEx"));
}
Ok(Dataset { c_dataset })
Ok(Dataset {
c_dataset,
closed: false,
})
}

/// Flush all write cached data to disk.
Expand Down Expand Up @@ -428,8 +432,10 @@ impl Dataset {
///
/// See [`GDALClose`].
///
/// Note: on GDAL versions older than 3.7, this function always succeeds.
pub fn close(&mut self) -> Result<()> {
/// Note: on GDAL versions older than 3.7.0, this function always succeeds.
pub fn close(mut self) -> Result<()> {
lnicola marked this conversation as resolved.
Show resolved Hide resolved
self.closed = true;

#[cfg(any(all(major_ge_3, minor_ge_7), major_ge_4))]
{
let rv = unsafe { gdal_sys::GDALClose(self.c_dataset) };
Expand All @@ -450,8 +456,12 @@ impl Dataset {
///
/// # Safety
/// This method operates on a raw C pointer
/// The dataset must not have been closed (using [`GDALClose`]) before.
pub unsafe fn from_c_dataset(c_dataset: GDALDatasetH) -> Dataset {
Dataset { c_dataset }
Dataset {
c_dataset,
closed: false,
}
}

/// Fetch the projection definition string for this dataset.
Expand Down Expand Up @@ -1019,8 +1029,10 @@ impl Metadata for Dataset {}

impl Drop for Dataset {
fn drop(&mut self) {
unsafe {
gdal_sys::GDALClose(self.c_dataset);
if !self.closed {
unsafe {
gdal_sys::GDALClose(self.c_dataset);
}
}
}
}
Expand Down Expand Up @@ -1161,7 +1173,8 @@ mod tests {

#[test]
fn test_open_vector() {
Dataset::open(fixture("roads.geojson")).unwrap();
let dataset = Dataset::open(fixture("roads.geojson")).unwrap();
dataset.close().unwrap();
}

#[test]
Expand Down