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

API methods that take RID arguments need to be unsafe #836

Closed
chitoyuu opened this issue Dec 26, 2021 · 5 comments · Fixed by #844
Closed

API methods that take RID arguments need to be unsafe #836

chitoyuu opened this issue Dec 26, 2021 · 5 comments · Fixed by #844
Labels
breaking-change Issues and PRs that are breaking to fix/merge. bug c: bindings Component: GDNative bindings (mod api)
Milestone

Comments

@chitoyuu
Copy link
Contributor

According to @Waridley on Discord:

Also, in investigating this, I realized it's super easy to invoke UB when working with RID's in release builds :ferris_sweat:

let vs = unsafe { VisualServer::godot_singleton() };
let canvas = vs.canvas_create();
let vp = vs.viewport_create();
vs.canvas_item_set_parent(vp, canvas); // crashes immediately
vs.canvas_item_set_parent(canvas, canvas); // crashes at shutdown

Fortunately, this still seems to require an unsafe block, and the engine catches it in debug builds, but the documentation for VisualServer only says that it's unsafe for multithreading reasons. Technically the unsafe part here is passing around typeless RID's which end up acting as raw pointers, even in a single-threaded context.

@chitoyuu chitoyuu added the bug label Dec 26, 2021
@Waridley
Copy link
Contributor

An alternative could be to parameterize Rid based on which API it was created from, and provide unsafe methods to convert from, e.g. Rid<Unknown> to Rid<Canvas> when it's obtained from an unknown source. But that would require potentially significant manual work. (maybe? I mean, most methods seem to follow a consistent naming convention, so we might be able to write some logic to cover most cases...)

@Bromeon Bromeon added breaking-change Issues and PRs that are breaking to fix/merge. c: bindings Component: GDNative bindings (mod api) labels Dec 27, 2021
@chitoyuu
Copy link
Contributor Author

An alternative could be to parameterize Rid based on which API it was created from...

Interesting idea. I took a glance at the methods and indeed they and their parameters are named quite consistently. Are Rids reference-counted, though? Because if we can get dangling pointers, then it doesn't matter as much if we know their types -- the methods would still have to be unsafe.

@Waridley
Copy link
Contributor

Interesting idea. I took a glance at the methods and indeed they and their parameters are named quite consistently. Are Rids reference-counted, though? Because if we can get dangling pointers, then it doesn't matter as much if we know their types -- the methods would still have to be unsafe.

Ugh, I think you're right. There's an _owner pointer on RID_Data when debug info is not enabled, but not all methods check it. There are some checks against double-freeing, but I don't think it prevents use-after-free in all methods... 😒

@Bromeon Bromeon added this to the v0.10.0 milestone Dec 30, 2021
@Bromeon
Copy link
Member

Bromeon commented Dec 30, 2021

Another thing to consider is that a small number of users may actually want type erasure. But this would be possible with a trait AbstractRid (basically Any + integer access; if implicit upcasts are intended), or the already suggested Rid<Unknown> (more explicit). For full type safety, we would need to type-ify the parameters as well.

For v0.10, should we simply mark the methods unsafe? It looks like type-ifying all Rids might be a larger endeavor, as we also need serialization (to/from variant), conversion between typed and untyped RIDs, etc. This might push the release further out, or maybe I'm overestimating it -- what do you think?

Regarding safety and double-free, this might also be relevant as a case in #808...

@chitoyuu
Copy link
Contributor Author

chitoyuu commented Jan 1, 2022

For v0.10, should we simply mark the methods unsafe? It looks like type-ifying all Rids might be a larger endeavor, as we also need serialization (to/from variant), conversion between typed and untyped RIDs, etc.

I believe so. It isn't worth as much to type-ify RIds if it doesn't allow us to make the interface safe.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
breaking-change Issues and PRs that are breaking to fix/merge. bug c: bindings Component: GDNative bindings (mod api)
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants