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

Fixed out of bounds reads for open_cursor #1837

Merged
Changes from 1 commit
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
30 changes: 18 additions & 12 deletions pgrx/src/spi/query.rs
Original file line number Diff line number Diff line change
Expand Up @@ -221,6 +221,22 @@ impl<'conn> PreparedStatement<'conn> {
mutating: self.mutating,
})
}

fn args_to_datums(
&self,
args: <Self as Query<'conn>>::Arguments,
) -> SpiResult<(Vec<pg_sys::Datum>, Vec<std::os::raw::c_char>)> {
let args = args.unwrap_or_default();

let actual = args.len();
let expected = unsafe { pg_sys::SPI_getargcount(self.plan.as_ptr()) } as usize;

if expected == actual {
Ok(args.into_iter().map(prepare_datum).unzip())
} else {
Err(SpiError::PreparedStatementArgumentMismatch { expected, got: actual })
}
}
}

impl<'conn: 'stmt, 'stmt> Query<'conn> for &'stmt PreparedStatement<'conn> {
Expand All @@ -236,16 +252,8 @@ impl<'conn: 'stmt, 'stmt> Query<'conn> for &'stmt PreparedStatement<'conn> {
unsafe {
pg_sys::SPI_tuptable = std::ptr::null_mut();
}
let args = arguments.unwrap_or_default();
let nargs = args.len();

let expected = unsafe { pg_sys::SPI_getargcount(self.plan.as_ptr()) } as usize;

if nargs != expected {
return Err(SpiError::PreparedStatementArgumentMismatch { expected, got: nargs });
}

let (mut datums, mut nulls): (Vec<_>, Vec<_>) = args.into_iter().map(prepare_datum).unzip();
let (mut datums, mut nulls) = self.args_to_datums(arguments)?;

// SAFETY: all arguments are prepared above
let status_code = unsafe {
Expand All @@ -262,9 +270,7 @@ impl<'conn: 'stmt, 'stmt> Query<'conn> for &'stmt PreparedStatement<'conn> {
}

fn open_cursor(self, _client: &SpiClient<'conn>, args: Self::Arguments) -> SpiCursor<'conn> {
let args = args.unwrap_or_default();

let (mut datums, nulls): (Vec<_>, Vec<_>) = args.into_iter().map(prepare_datum).unzip();
let (mut datums, nulls) = self.args_to_datums(args).unwrap();
Copy link
Member

@workingjubilee workingjubilee Sep 2, 2024

Choose a reason for hiding this comment

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

specifically adding the FIXME right here.

Also alternatively: add fn try_open_cursor, then tag this one with #[deprecated(since = "0.12.2", note = "lol ub")], and then replace the inner impl of this with just self.try_open_cursor(_client, args).unwrap().

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Will write the new method too then, that's not an issue for me. And actually, I have other plans for improvements there and around (:


// SAFETY: arguments are prepared above and SPI_cursor_open will never return the null
// pointer. It'll raise an ERROR if something is invalid for it to create the cursor
Expand Down
Loading