-
Notifications
You must be signed in to change notification settings - Fork 12
safety: introduce pointer types and their restrictions #208
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
Conversation
f433610
to
9dadad8
Compare
9dadad8
to
7b8bb5a
Compare
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.
The approach is very impressive.
I couldn't check all the changes, there were too much of them; I just peeked through them. I trust your meticulousness :)
7b8bb5a
to
e8d2d93
Compare
Rebased on master |
98fbac9
to
aa90f5a
Compare
v1.1: Addressed @wprzytula comments |
Waiting with review for a rebase on #207. |
Everything is up to date |
aa90f5a
to
6c2a061
Compare
v2: Improved pointer API based on @wprzytula suggestions. Thank you!
I still need to think how to address the issue in tests. It's not possible to reuse the pointer, which is not |
You could have an |
6c2a061
to
3686e0d
Compare
Applied the suggestion. At first, I did not understand how is this different from implementing |
3686e0d
to
f341734
Compare
Rebased on master |
f341734
to
8dfff0a
Compare
v2.1: improved docstrings as suggested by @wprzytula |
59cfb50
to
ce3896f
Compare
Before this commit, the pointer was obtained from a valid reference &CassFuture, which is totally fine. However, I want to reduce the ways one can obtain such pointer. For ArcFFI (shared pointers), I want them to be obtainable only in two ways: - `ArcFFI::as_ptr()` which accepts an &Arc - from the user, as a function parameter This way, we are guaranteed that the pointer comes from a valid Arc allocation (unless user provided pointer to some garbage, but there is no much we can do about it). If we assume that user provides a pointer returned from some prior call to API, we are guaranteed that it is valid, and comes from an Arc allocation (or is null). I don't want to allow ArcFFI api to create a pointer from a refernce, to prevent creating a pointer, from example from stack allocated object: ``` let future = CassFuture { ... }; let future_ptr = ArcFFI::as_ptr(&future); ``` Since some methods started accepting a pointer, they are marked as unsafe, because they assume that pointer is valid. We will be able to remove unsafes once CassPtr is introduced - the type will give enough guarantees for these methods to be safe. In this PR, there was a question regarding CassFuture::set_callback: Q: Here self_ptr should refer to the same CassFuture as self, right? Can you instead make the receiver of this function an arc? self: &Arc<CassFuture> A: I don't see a good reason behind it. We get a pointer in cass_future_set_callback, then we would need to convert it to Arc (increase a refcount), just to then convert it back to pointer (decrease refcount) and pass the ponter to callback.
v4:
|
v4.1: addressed @wprzytula comments |
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.
💯 Really great work! I no longer see any big problems, only left some minor comments.
I'm not a fan of the workaround in cass_future_set_callback, but I don't have any good ideas on how to improve it.
scylla-rust-wrapper/src/argconv.rs
Outdated
mod sealed { | ||
pub trait Sealed {} | ||
} | ||
|
||
/// A trait representing (Rust) mutability of the pointer. | ||
/// | ||
/// Pointer can either be [`Const`] or [`Mut`]. | ||
/// | ||
/// ## Const pointers | ||
/// Const pointers can only be converted to **immutable** Rust referential types. | ||
/// There is no way to obtain a mutable reference from such pointer. | ||
/// | ||
/// In some cases, we need to be able to mutate the data behind a shared pointer. | ||
/// There is an example of such use case - namely [`crate::cass_types::CassDataType`]. | ||
/// argconv API does not provide a way to mutate such pointer - one can only convert the pointer | ||
/// to [`Arc`] or &. It is the API user's responsibility to implement sound interior mutability | ||
/// pattern in such case. This is what we currently do - CassDataType wraps CassDataTypeInner | ||
/// inside an `UnsafeCell` to implement interior mutability for the type. | ||
/// Other example is [`crate::future::CassFuture`] which uses Mutex. | ||
/// | ||
/// ## Mut pointers | ||
/// Mut pointers can be converted to both immutable and mutable Rust referential types. | ||
pub trait Mutability: sealed::Sealed {} | ||
|
||
/// Represents immutable pointer. | ||
pub struct Const; | ||
impl sealed::Sealed for Const {} | ||
impl Mutability for Const {} | ||
|
||
/// Represents mutable pointer. | ||
pub struct Mut; | ||
impl sealed::Sealed for Mut {} | ||
impl Mutability for Mut {} |
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.
Mutability
and CMutability
are quite similar names. The names of specific structs are also similar.
WDYT about
Mutability
-> Ownership
Const
-> Shared
Mut
-> Exclusive
I think it better reflects what this property is about, and reflects the imo better way to think about rust references.
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 definitely agree with Exclusive
and Shared
names. Not sure about Ownership
. For me, Ownership property is currently represented via lifetimes (Owned vs Borrowed).
OTOH, Mutability
name is not perfect either. I'll try to come up with some reasonable name. If I fail to do so, I'll apply your suggestion and rename the trait to Ownership
.
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 couldn't come up with a better name. Renamed the trait and corresponding struct as you suggested.
This commit introduces a `CassPtr` type, generic over pointer `Properties`. It allows specific pointer-to-reference conversions based on the guarantees provided by the pointer type.
Existing `Ref/Box/Arc`FFIs are adjusted, so they now allow interaction with new pointer type. You can say, that for a user of `argconv` API, new type is opaque. The only way to operate on it is to use the corresponding ffi API.
Disallow implementing two different APIs for specific type.
v4.2: Addressed @Lorak-mmk comments. |
Hmm, why did cassandra tests fail? |
The cover letter needs to be adjusted for the recent |
Due to the recent change on scylla-ccm's master. I'll be investivating this, but the failure is not related to this PR. |
@wprzytula @Lorak-mmk I opened an issue on scylla-ccm: scylladb/scylla-ccm#646. As a temporary fix, should I set the ccm version in CI to the version before the change that introduced the bug? |
Yes |
See the issue linked in the comment.
CI passed - I am merging |
This is a follow-up to: #207.
It defines a
CassPtr
type, wrapper overOption<NonNull<T>>
. The pointer is parameterized by:Lifetime
Thanks to that, we can distinguish between owned (should be freed) and borrowed pointers.
Properties
There are currently two properties:
Ownership
- it tells whether the pointer is mutable from Rust perspective. In other words,Exclusive
= mutable pointer,Shared
= immutable pointer.CMutability
- the semantics of this one are very simple. It just tells whether the pointer isT*
orconst T*
in C API definition. It's introduced so we can distinguish shared, logically mutable types (Mutability::Const
andCMutability::CMut
) from shared, logically immutable types (Mutability::Const
andCMutability::CConst
). This property will help to write safe unit tests where we play a role of C API user.During review, please pay attention to that if some pointer was originally
const T*
(or*const T
in Rust), then it isCConst
after this PR. Analogously, if it wasT*
(or*mut T
in Rust), then it should beCMut
.Pre-review checklist
[ ] I have enabled appropriate tests in.github/workflows/build.yml
ingtest_filter
.[ ] I have enabled appropriate tests in.github/workflows/cassandra.yml
ingtest_filter
.