-
Notifications
You must be signed in to change notification settings - Fork 212
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
Rid
and APIs accepting it are now unsafe
#844
Conversation
This dug up some extra dirt, especially regarding 1. This is a rather weird function to be public. Do we really need it, as we have 2. Both equality and less operators are unsafe because the Godot implementation looks like this: godot_bool GDAPI godot_rid_operator_equal(const godot_rid *p_self, const godot_rid *p_b) {
const RID *self = (const RID *)p_self;
const RID *b = (const RID *)p_b;
return *self == *b;
}
godot_bool GDAPI godot_rid_operator_less(const godot_rid *p_self, const godot_rid *p_b) {
const RID *self = (const RID *)p_self;
const RID *b = (const RID *)p_b;
return *self < *b;
} Thanks to the dereferencing, passing an empty 3. Our current impl PartialOrd for Rid {
#[inline]
fn partial_cmp(&self, other: &Rid) -> Option<Ordering> {
unsafe {
let native = (get_api().godot_rid_operator_less)(&self.0, &other.0);
if native {
Some(Ordering::Less)
} else {
Some(Ordering::Greater)
}
}
}
} When is Let's say we have This violates the duality and irreflexibility properties:
|
To sum up, both We have the following options:
|
It's probably unnecessary, yes.
I don't think that's the case here, unless further dereferencing happens in the operator implementations? We're calling As I understand it the C++ code seems to be simply comparing the pointers as numbers.
I suppose this will have be fixed by calling |
Indeed I missed that we're passing a raw pointer to But they're not numbers. I researched a bit more, typedef struct {
uint8_t _dont_touch_that[GODOT_RID_SIZE];
} godot_rid; (i.e. the C origin of the bindgen'ed code). That pointer class RID {
mutable RID_Data *_data;
public:
_FORCE_INLINE_ RID_Data *get_data() const { return _data; }
_FORCE_INLINE_ bool operator==(const RID &p_rid) const {
return _data == p_rid._data;
}
_FORCE_INLINE_ bool operator<(const RID &p_rid) const {
return _data < p_rid._data;
}
_FORCE_INLINE_ bool is_valid() const { return _data != nullptr; }
_FORCE_INLINE_ uint32_t get_id() const { return _data ? _data->get_id() : 0; }
_FORCE_INLINE_ RID() {
_data = nullptr;
}
}; So there is another nesting ( mutable RID_Data *_data;
bool operator<(const RID &p_rid) const {
return _data < p_rid._data;
} Now this is C++, where nothing is just the way you'd intuitively expect it to be, especially in the territory of UB. And better yet, to be sure you not only need to find the right laws among the 1853 pages, but you better have 200$+ ready to spend. I checked StackOverflow, where we can continue the treasure hunt:
Great, so in theory we'd need to check compiler handbooks. But I don't think we have to go that far, if dangling RIDs can be compared in Godot, it will work for us. In practice, comparing pointers should just work. So
uint32_t get_id() const { return _data ? _data->get_id() : 0; } |
15f6f12
to
cc8ff55
Compare
Ok, all changes in
|
bors r+ |
Build succeeded: |
Fixes #836.
Makes all GDNative API methods accepting at least one
Rid
parameterunsafe
.Overall changes in
Rid
:operator_less()
is_valid()
->is_occupied()
get_id()
is nowunsafe
+ null-checked (if the RID is dangling, Godot dereferences an invalid pointer)PartialOrd
impl