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

Deny unsafe code in most of the code base #3824

Closed
alice-i-cecile opened this issue Jan 31, 2022 · 3 comments · Fixed by #12684
Closed

Deny unsafe code in most of the code base #3824

alice-i-cecile opened this issue Jan 31, 2022 · 3 comments · Fixed by #12684
Labels
A-Cross-Cutting Impacts the entire engine C-Code-Quality A section of code that is hard to understand or change

Comments

@alice-i-cecile
Copy link
Member

alice-i-cecile commented Jan 31, 2022

What problem does this solve or what need does it fill?

While undeniably useful and often irreplaceable, unsafe code is inherently challenging to audit and maintain.

Uses of unsafe code outside of the core engine crate should not be necessary; safe APIs for missing functionality should be exposed instead.

What solution would you like?

Add #![deny(unsafe_code)] annotations to most bevy crates at the top of lib.rs.

There are a few clear exceptions:

  • bevy_ecs
    • some submodules, like events, should probably forbid unsafe code
  • bevy_crevice
  • bevy_derive
  • bevy_reflect

There are some surprising usages of unsafe that should be handled in one form or another.

Each of these should be rewritten if feasible, or explicitly allowed if not.

Alternatives

We could use #![forbid(unsafe_code)] instead, but the ability to allow unsafe in carefully thought-out one-off instances is probably too valuable for many of these crates.

We could use #![warn(unsafe_code)] instead: keeping it at warning won't be a bother when you want to try things out locally, and Bevy CI will deny warnings.

@alice-i-cecile alice-i-cecile added C-Code-Quality A section of code that is hard to understand or change A-Meta About the project itself labels Jan 31, 2022
@mockersf
Copy link
Member

It should be at most #![warn(unsafe_code)]: keeping it at warning won't be a bother when you want to try things out locally, and Bevy CI will deny warnings.

I think this lint is better left to code reviews. It's unlikely unsafe code is going to be accepted without providing a reason for it anyway.

@DJMcNab
Copy link
Member

DJMcNab commented Jan 31, 2022

Fwiw, I'm in favour of forbid, but then downgraded to warn (or deny broadly equivalently) if it's needed for that crate. The change from forbid to warn should also be a warning that this PR is doing something spooky.

My counterexample to it being code review would be

unsafe fn run_unsafe(&mut self, _input: (), world: &World) -> ShouldRun {

This should (probably?) not be a manual System implementation. (I've not fixed that myself yet since I have other PRs open which would conflict IIRC, and honestly the whole fixed timestep solution needs a more thorough overhaul)

(That being said, this was added in a cart PR, so it's unclear how thoroughly it would have been reviewed anyway; would the change to warn have been caught?)

@alice-i-cecile
Copy link
Member Author

#3893 removes the dynamic plugin functionality, and with it a large amount of unsafe.

@alice-i-cecile alice-i-cecile added A-Cross-Cutting Impacts the entire engine and removed A-Meta About the project itself labels Mar 24, 2024
github-merge-queue bot pushed a commit that referenced this issue Mar 27, 2024
# Objective
Resolves #3824. `unsafe` code should be the exception, not the norm in
Rust. It's obviously needed for various use cases as it's interfacing
with platforms and essentially running the borrow checker at runtime in
the ECS, but the touted benefits of Bevy is that we are able to heavily
leverage Rust's safety, and we should be holding ourselves accountable
to that by minimizing our unsafe footprint.

## Solution
Deny `unsafe_code` workspace wide. Add explicit exceptions for the
following crates, and forbid it in almost all of the others.

* bevy_ecs - Obvious given how much unsafe is needed to achieve
performant results
* bevy_ptr - Works with raw pointers, even more low level than bevy_ecs.
 * bevy_render - due to needing to integrate with wgpu
 * bevy_window - due to needing to integrate with raw_window_handle
* bevy_utils - Several unsafe utilities used by bevy_ecs. Ideally moved
into bevy_ecs instead of made publicly usable.
 * bevy_reflect - Required for the unsafe type casting it's doing.
 * bevy_transform - for the parallel transform propagation
 * bevy_gizmos  - For the SystemParam impls it has.
* bevy_assets - To support reflection. Might not be required, not 100%
sure yet.
* bevy_mikktspace - due to being a conversion from a C library. Pending
safe rewrite.
* bevy_dynamic_plugin - Inherently unsafe due to the dynamic loading
nature.

Several uses of unsafe were rewritten, as they did not need to be using
them:

* bevy_text - a case of `Option::unchecked` could be rewritten as a
normal for loop and match instead of an iterator.
* bevy_color - the Pod/Zeroable implementations were replaceable with
bytemuck's derive macros.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-Cross-Cutting Impacts the entire engine C-Code-Quality A section of code that is hard to understand or change
Projects
None yet
Development

Successfully merging a pull request may close this issue.

3 participants