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

prevent SIGSEGV for non-strings on read string method #284

Merged
merged 8 commits into from
Aug 25, 2022
4 changes: 4 additions & 0 deletions CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,6 +63,10 @@

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

- Prevent SIGGEGV when reading a string array on an MD Array that is not of type string.

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

## 0.12

- Bump Rust edition to 2021
Expand Down
7 changes: 7 additions & 0 deletions src/errors.rs
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,13 @@ pub enum GdalError {
UnlinkMemFile { file_name: String },
#[error("BadArgument")]
BadArgument(String),

#[cfg(all(major_ge_3, minor_ge_1))]
#[error("Unhandled type '{data_type:?}' on GDAL MD method {method_name}")]
UnsupportedMdDataType {
data_type: crate::raster::ExtendedDataType,
method_name: &'static str,
},
}

/// A wrapper for [`CPLErr::Type`] that reflects it as an enum
Expand Down
27 changes: 25 additions & 2 deletions src/raster/mdarray.rs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,10 @@ impl<'a> MDArray<'a> {
let c_dimensions =
GDALMDArrayGetDimensions(self.c_mdarray, std::ptr::addr_of_mut!(num_dimensions));

if c_dimensions.is_null() {
return Err(_last_null_pointer_err("GDALMDArrayGetDimensions"));
}

let dimensions_ref = std::slice::from_raw_parts_mut(c_dimensions, num_dimensions);

let mut dimensions: Vec<Dimension> = Vec::with_capacity(num_dimensions);
Expand Down Expand Up @@ -220,6 +224,18 @@ impl<'a> MDArray<'a> {

/// Read `MDArray` as one-dimensional string array
pub fn read_as_string_array(&self) -> Result<Vec<String>> {
let data_type = self.datatype();
if data_type.class() != GDALExtendedDataTypeClass::GEDTC_STRING {
// We have to check that the data type is string.
// Only then, GDAL returns an array of string pointers.
// Otherwise, we will dereference these string pointers and get a segfault.

return Err(GdalError::UnsupportedMdDataType {
data_type,
method_name: "GDALMDArrayRead (string)",
});
}

let num_values = self.num_elements() as usize;
let mut string_pointers: Vec<*const c_char> = vec![std::ptr::null(); num_values];

Expand Down Expand Up @@ -470,7 +486,7 @@ impl<'a> Dimension<'a> {
}

/// Wrapper for `GDALExtendedDataType`
#[derive(Debug)]
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct ExtendedDataType {
c_data_type: GDALExtendedDataTypeH,
}
Expand Down Expand Up @@ -503,7 +519,7 @@ impl ExtendedDataType {
}
}

// Wrapper for `GDALExtendedDataType`
// Wrapper for `GDALAttribute`
#[derive(Debug)]
pub struct Attribute {
c_attribute: GDALAttributeH,
Expand Down Expand Up @@ -760,6 +776,13 @@ mod tests {
.unwrap();

assert_eq!(string_array.read_as_string_array().unwrap(), ["abcd", "ef"]);

let non_string_array = root_group
.open_md_array("uint_var", CslStringList::new())
.unwrap();

// check that we don't get a `SIGSEV` here
assert!(non_string_array.read_as_string_array().is_err());
}

#[test]
Expand Down
2 changes: 1 addition & 1 deletion src/raster/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ mod types;
mod warp;

#[cfg(all(major_ge_3, minor_ge_1))]
pub use mdarray::{Group, MDArray};
pub use mdarray::{ExtendedDataType, Group, MDArray};
pub use rasterband::{
Buffer, ByteBuffer, CmykEntry, ColorEntry, ColorInterpretation, ColorTable, GrayEntry,
HlsEntry, PaletteInterpretation, RasterBand, ResampleAlg, RgbaEntry,
Expand Down