-
-
Notifications
You must be signed in to change notification settings - Fork 255
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 unsound &
and &mut
in fcinfo.rs
#1595
Fix unsound &
and &mut
in fcinfo.rs
#1595
Conversation
We should not use `IncompleteArrayField::as_slice` as it is of questionable soundness. This version would pass miri regardless of opsem model, though we cannot actually run miri, due to our dependence on large quantities of FFI.
Not done yet. I have to fix the |
More of the same, but in addition, we avoid taking &mut to what could be uninit, and simply use palloc0 instead. This could hypothetically lead to perf regressions? In actuality, however, it probably is faster, if anything, and to be sure, we now instead elide the bounds check for every index of the args by directly iterating.
let fcinfo_ptr = pg_sys::palloc( | ||
let fcinfo = pg_sys::palloc0( | ||
std::mem::size_of::<pg_sys::FunctionCallInfoBaseData>() | ||
+ std::mem::size_of::<pg_sys::NullableDatum>() * args.len(), | ||
) | ||
.cast::<pg_sys::FunctionCallInfoBaseData>(); | ||
|
||
let fcinfo = fcinfo_ptr.as_mut().unwrap_unchecked(); | ||
fcinfo.flinfo = std::ptr::null_mut(); | ||
fcinfo.context = std::ptr::null_mut(); | ||
fcinfo.resultinfo = std::ptr::null_mut(); | ||
fcinfo.fncollation = pg_sys::InvalidOid; | ||
fcinfo.isnull = false; | ||
fcinfo.nargs = nargs; | ||
(*fcinfo).flinfo = std::ptr::null_mut(); | ||
(*fcinfo).context = std::ptr::null_mut(); | ||
(*fcinfo).resultinfo = std::ptr::null_mut(); | ||
(*fcinfo).fncollation = pg_sys::InvalidOid; | ||
(*fcinfo).isnull = false; | ||
(*fcinfo).nargs = nargs; | ||
|
||
let arg_slice = fcinfo.args.as_mut_slice(args.len()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This? Using a palloc, which creates uninit memory, and taking &mut
to an initialized type? Worse, one with illegal bitpatterns (bool)? This was simply UB. We could do &mut [MaybeUninit<NullableDatum>]
, but not this.
pgrx/src/fcinfo.rs
Outdated
for (n_datum, arg) in arg_slice.iter_mut().zip(args) { | ||
n_datum.isnull = arg.is_none(); | ||
n_datum.value = arg.unwrap_or(pg_sys::Datum::from(0)); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe this pattern is more idiomatic and optimizes better.
std::mem::size_of::<pg_sys::FunctionCallInfoBaseData>() | ||
+ std::mem::size_of::<pg_sys::NullableDatum>() * args.len(), | ||
) | ||
.cast::<pg_sys::FunctionCallInfoBaseData>(); | ||
|
||
let fcinfo = fcinfo_ptr.as_mut().unwrap_unchecked(); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a dubious-soundness action due to later interactions with the args slice being somewhat incompatible with Stacked Borrows.
let result = func(fcinfo_ptr); | ||
let result = if fcinfo.isnull { None } else { Some(result) }; | ||
let result = func(fcinfo); | ||
let result = if (*fcinfo).isnull { None } else { Some(result) }; | ||
|
||
pg_sys::pfree(fcinfo_ptr.cast()); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was UB. It has always been UB. Even under Tree Borrows, it will always be UB. This interacts with &mut T
and *mut T
as if they have equal standing. They do not. The &mut T
, even under the permissive models, "quiets" the *mut T
while it is still in existence, and this direct overlapping interaction with the two is and always was simply unsound.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In fact, we probably should drop
the slice before we call func
?
&
and &mut
in fcinfo.rs
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me, this looks like an improvement in soundness. Compiles and passes tests on my machine.
Welcome to pgrx 0.12.0-alpha.1! Say the magic words with me! ```shell cargo install cargo-pgrx --locked --version 0.12.0-alpha.1 ``` # Breaking Changes ## No more dlopen! Perhaps the most exciting change this round is @usamoi's contribution in #1468 which means that we no longer perform a `dlopen` in order to generate the schema. The cost, such as it is, is that your pgrx extensions now require a `src/bin/pgrx_embed.rs`, which will be used to generate the schema. This has much less cross-platform issues and will enable supporting things like `cargo binstall` down the line. It may be a bit touchy on first-time setup for transitioning older repos. If necessary, you may have to directly add a `src/bin/pgrx_embed.rs` and add the following code (which should be the only code in the file, though you can add comments if you like?): ```rust ::pgrx::pgrx_embed!(); ``` Your Cargo.toml will also want to update its crate-type key for the library: ```toml [lib] crate-type = ["cdylib", "lib"] ``` ## Library Code - pgrx-pg-sys will now use `ManuallyDropUnion` thanks to @NotGyro in #1547 - VARHDRSZ `const`s are no longer `fn`, thanks to @workingjubilee in #1584 - We no longer have `Interval::is_finite` since #1594 - We translate more `*_tree_walker` functions to the same signature their `*_impl` version in Postgres 16 has: #1596 - Thanks to @eeeebbbbrrrr in #1591 we no longer have the `pg_sql_graph_magic!()` macro, which should help with more things in the future! # What's New We have quite a lot of useful additions to our API: - `SpiClient::prepare_mut` was added thanks to @XeniaLu in #1275 - @usamoi also contributed bindings subscripting code in #1562 - For `#[pg_test]`, you have been able to use `#[should_panic(expected = "string")]` to anticipate a panic that contains that string in that test. For various reasons, `#[pg_test(error = "string")]` is much the same. Now, you can also use `#[pg_test(expected = "string")]`, in the hopes that is easier to stumble across, as of #1570 ## `Result<composite_type!("..."), E>` support - In #1560 @NotGyro contributed support for using `Result<composite_type!("Name"), E>`, as a case that had not been handled before. ## Significantly expanded docs Thanks to @rjuju, @NotGyro, and @workingjubilee, we now have significantly expanded docs for cargo-pgrx and pgrx in general. Some of these are in the API docs on https://docs.rs or the READMEs, but there's also a guide, now! It's not currently published, but is available as an [mdbook](https://github.com/rust-lang/mdBook) in the repo. Some diagnostic information that is also arguably documentation, like comments and the suggestion to `cargo install`, have also been improved, thanks to @workingjubilee in - #1579 - #1573 ## `#[pg_cast]` An experimental macro for a `CREATE CAST` was contributed by @xwkuang5 in #1445! ## Legal Stuff Thanks to @the-kenny in #1490 and @workingjubilee in #1504, it was brought to our attention that some dependencies had unusual legal requirements. So we fixed this with CI! We now check our code included into pgrx-using binaries is MIT/Apache 2.0 licensed, as is common across crates.io, using `cargo deny`!. The build tools will have more flexible legal requirements (partly due to the use of Mozilla Public License code in rustls). # Internal Changes Many internal cleanups were done thanks to - @workingjubilee in too many PRs to count! - @thomcc found a needless condition in #1501 - @nyurik in too many PRs to count! In particular: - we now actually `pfree` our `Array`s we detoasted as-of #1571 - creating a `RawArray` is now low-overhead due to #1587 ## Soundness Fixes We had a number of soundness issues uncovered or have added more tests to catch them. - Bounds-checking debug assertions for array access by @NotGyro in #1514 - Fix unsound `&` and `&mut` in `fcinfo.rs` by @workingjubilee in #1595 ## Less Deps Part of the cleanup by @workingjubilee was reducing the number of deps we compile: * cargo-pgrx: reduce trivial dep usages in #1499 * Update 2 syn in #1557 Hopefully it will reduce compile time and disk usage! ## New Contributors * @the-kenny made their first contribution in #1490 * @xwkuang5 made their first contribution in #1445 * @rjuju made their first contribution in #1516 * @nyurik made their first contribution in #1533 * @NotGyro made their first contribution in #1514 * @XeniaLu made their first contribution in #1275 **Full Changelog**: v0.12.0-alpha.0...v0.12.0-alpha.1
There were many unsound details in the implementation of this code, like using
*mut T
and&mut T
at the same time, creating slices using bindgen-provided code that is of dubious soundness, or taking&mut [T]
to what should be&mut [MaybeUninit<T>]
.They have been fixed. The primary strategy used is to interact only with
*mut T
if there is any doubt, and to constrain&mut
to very narrow scopes.