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

Conversation

YohDeadfall
Copy link
Contributor

@YohDeadfall YohDeadfall commented Sep 2, 2024

The problem arises when the prepared statement has less arguments than
the used plan since there's no parameter to pass the number of arguments
like it's for SPI_execute_with_args. Meanwhile the execute method
does a check.

Introduce a variant, try_open_cursor, that returns an SpiResult instead.

@workingjubilee
Copy link
Member

can you add a FIXME for it? thanks.

@workingjubilee
Copy link
Member

workingjubilee commented Sep 2, 2024

The main reason it doesn't return a Result is that all of this was a relatively under-designed API that has been scheduled for total demolition and replacement, so comparatively minor but still breaking changes like "maybe we should have returned a Result here..." have been on-hold.

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 (:

Copy link
Member

@workingjubilee workingjubilee left a comment

Choose a reason for hiding this comment

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

that said, adding new API is optional, but we do need a #[should_panic] test on this case for open_cursor, or a "returns Err" test on the try_open_cursor fn, either one.

@workingjubilee
Copy link
Member

It feels a little early to bump to 0.13, not that I'm afraid of such, but yk "a month" seems like a good span.

@YohDeadfall
Copy link
Contributor Author

I addressed your changes, but what I honestly don't like is #[allow(deprecated)] attributes in tests, but if with the next breaking version it will be removed that seems fine.

If you share your plans on the SPI part, then I can contribute by reshaping it.

@workingjubilee
Copy link
Member

If you share your plans on the SPI part, then I can contribute by reshaping it.

The most fundamental issue is that the API does not enforce lifetime bounds properly. Solving this is hard, but it is why 0.12 landed a huge breaking change for most pgrx-using code: solving the problem with the pgrx::spi API and then not fixing the entire rest of everything was basically closing the barn door well after every cow had not only run out but acquired demonic powers, picked up a hellforged weapon, and turned into a roaming infernal bovine.

It also has some overly complicated parts, like the overly-cutesy Query trait, which I would wish to move away from.

Copy link
Member

@workingjubilee workingjubilee left a comment

Choose a reason for hiding this comment

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

thank you, this looks good.

Comment on lines +270 to +284
Spi::connect(|mut client| {
client.update("CREATE TABLE tests.cursor_table (id int)", None, None)?;
client.update(
"INSERT INTO tests.cursor_table (id) \
SELECT i FROM generate_series(1, 10) AS t(i)",
None,
None,
)?;
let prepared = client.prepare(
"SELECT * FROM tests.cursor_table WHERE id = $1",
Some([PgBuiltInOids::INT4OID.oid()].to_vec()),
)?;
client.open_cursor(&prepared, args);
unreachable!();
})
Copy link
Member

Choose a reason for hiding this comment

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

huh, does this return an error because we panic during the connection? interesting.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Right, it panics and the tests are marked as #[should_panic]. That allows us to verify that there's no undefined behavior.

Copy link
Member

Choose a reason for hiding this comment

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

Interesting.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Okay, it's a bit incorrect without the reason I haven't provided for tests because unreachable!! panics too and gives us a false negative. See #1843 for a fix.

/// # Panics
///
/// Panics if a cursor wasn't opened.
#[deprecated(since = "0.12.2", note = "undefined behavior")]
Copy link
Member

Choose a reason for hiding this comment

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

hm. on second thought, not entirely sure if we want to deprecate this just because it panics... otoh most people don't like panics...

Copy link
Contributor Author

Choose a reason for hiding this comment

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

So, deprecate or leave it as it is for now? Personally I hate panicking, but there's a lot of upcoming work with breaking changes anyway, I guess, so forcing users to fix their code on each release isn't wise.

Copy link
Member

Choose a reason for hiding this comment

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

Yeah, I've reconsidered and I think we should remove the deprecation note, I don't want to churn people pointlessly. I'll try to mention it in the release notes.

Copy link
Member

@workingjubilee workingjubilee Sep 6, 2024

Choose a reason for hiding this comment

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

or @eeeebbbbrrrr will. :^)

unless he feels that we should in fact deprecate this because it started panicking (but only when the alternative was UB).

Copy link
Member

@workingjubilee workingjubilee left a comment

Choose a reason for hiding this comment

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

stripping the deprecated stuff mostly, sorry about changing my mind back and forth.

pgrx-tests/src/tests/spi_tests.rs Outdated Show resolved Hide resolved
pgrx-tests/src/tests/spi_tests.rs Outdated Show resolved Hide resolved
pgrx-tests/src/tests/spi_tests.rs Outdated Show resolved Hide resolved
pgrx-tests/src/tests/spi_tests.rs Outdated Show resolved Hide resolved
pgrx-tests/src/tests/spi_tests.rs Outdated Show resolved Hide resolved
pgrx-tests/src/tests/spi_tests.rs Outdated Show resolved Hide resolved
@@ -532,6 +577,7 @@ mod tests {
}

#[pg_test]
#[allow(deprecated)]
Copy link
Member

Choose a reason for hiding this comment

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

Suggested change
#[allow(deprecated)]

pgrx/src/spi/client.rs Outdated Show resolved Hide resolved
pgrx/src/spi/client.rs Outdated Show resolved Hide resolved
pgrx/src/spi/query.rs Outdated Show resolved Hide resolved
@workingjubilee
Copy link
Member

Thanks!

@workingjubilee workingjubilee merged commit a772c49 into pgcentralfoundation:develop Sep 6, 2024
14 checks passed
@YohDeadfall YohDeadfall deleted the query-open-cursor-safety branch September 6, 2024 08:45
eeeebbbbrrrr added a commit that referenced this pull request Sep 6, 2024
Welcome to pgrx v0.12.2. This is a minor release that fixes a few bugs,
improves compilation times with `cargo pgrx run/install/test`, and adds
a few more Postgres headers.

As usual, please `cargo install cargo-pgrx --version 0.12.2 --locked`.
Then you can run `cargo pgrx upgrade` in your extension crate's root to
update its dependencies.

## What's Changed

* [ `CPPFLAGS`] Switch to `USE_ASSERT_CHECKING` by @SamuelMarks in
#1826
* Add UnboxDatum for Range<T> by @mhov in
#1827
* Moved Sized from FromDatum methods to trait by @YohDeadfall in
#1831
* Used SPI result type for cursor API by @YohDeadfall in
#1836
* always compile `pgrx_embed_*` without opts by @eeeebbbbrrrr in
#1838
* Fixed out of bounds reads for open_cursor by @YohDeadfall in
#1837
* Include `access/visibilitymap.h` and `utils/tuplestore.h` by
@eeeebbbbrrrr in #1841

## New Contributors

Thanks to these folks for their first-time contributions -- it's greatly
appreciated!

* @SamuelMarks made their first contribution in
#1826
* @YohDeadfall made their first contribution in
#1831

**Full Changelog**:
v0.12.1...v0.12.2
workingjubilee pushed a commit that referenced this pull request Sep 6, 2024
Fixes issues left from #1837, but nothing critical.

The problem with `unreachable!` in tests is that it requires to have a
non-empty `expected` in the `#[should_panic]` attribute. So we provide a
message to verify that panicking happens for the right reason.
eeeebbbbrrrr added a commit that referenced this pull request Sep 9, 2024
Welcome to pgrx v0.12.3. This point release upgrades to use the new
Postgres 17rc1.

As usual, please `cargo install cargo-pgrx --version 0.12.3 --locked`.
Then you can run `cargo pgrx upgrade` in your extension crate's root to
update its dependencies.


## What's Changed
* Fixups of issues left from #1837 by @YohDeadfall in
#1843
* move to Postgres v17rc1 by @eeeebbbbrrrr in
#1846


**Full Changelog**:
v0.12.2...v0.12.3
daamien pushed a commit to daamien/pgrx that referenced this pull request Sep 12, 2024
Welcome to pgrx v0.12.3. This point release upgrades to use the new
Postgres 17rc1.

As usual, please `cargo install cargo-pgrx --version 0.12.3 --locked`.
Then you can run `cargo pgrx upgrade` in your extension crate's root to
update its dependencies.


## What's Changed
* Fixups of issues left from pgcentralfoundation#1837 by @YohDeadfall in
pgcentralfoundation#1843
* move to Postgres v17rc1 by @eeeebbbbrrrr in
pgcentralfoundation#1846


**Full Changelog**:
pgcentralfoundation/pgrx@v0.12.2...v0.12.3
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants