-
-
Notifications
You must be signed in to change notification settings - Fork 260
Safeguard levels: fine-tune the amount of runtime validations #1278
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
|
API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-1278 |
|
What if we call this The |
Bromeon
left a comment
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.
Thanks a lot for the pull request! 👍
Please see my comment #1046 (comment) and subsequent response by @TitanNano, where we detailed quite a bit of the design.
Some feedback:
-
My first impression is that I'd rather not have this configured via environment variables, that's rather brittle and easy to silently get wrong (e.g. someone sets the environment variable for Godot, not for rustc). Instead, it should be a Cargo feature. While features are technically additive, we already do a similar thing with
api-4-2etc.- I know it can be slightly annoying since you can't easily enable a feature only in the Release config. But this isn't really easier with env vars.
-
Safety profiles should be named, not magic numbers. It's not obvious whether "0" means "no safety" or "no performance". An option is to use the term
checks, but it could also be something else.- The individual levels could be called
fast-unsafe,balancedandparanoid. (To be discussed) - Cargo feature would then be
checks-fast-unsafe. - Conditional compilation would be
#[cfg(checks_at_least = "balanced")]. Let's avoidnotif possible.
- The individual levels could be called
|
I think including chosen safety profile in preamble would be good idea as well (something along the lines of "Initialize godot-rust (API v4.4.stable.official, runtime v4.4.stable.official) fast-unsafe/balanced/slow-safe mode"?). Lines 288 to 293 in 0dde85e
There are some validity checks which would be nice to cover, albeit I wouldn't sweat too much about it – we can cover them later 😄. One such example is the gdext/godot-core/src/obj/gd.rs Lines 1078 to 1087 in aaf3ed5
(I'll underline – I don't think we should sweat to cover all (or even the aforementioned one) the cases, we should just make an issue for tracking them) |
|
Yeah, I'd suggest not to add more specific checks in this PR, to get the basic mechanism working first 🙂 As for defaults, it should be:
While it means the user won't get max performance per default, it's better if they don't risk UB by default. But if we go for Cargo feature, we need to find a way how they can opt in... I could imagine that in Debug mode, many would still want to keep paranoid or balanced checks, while Release builds should have fast performance. It's unfortunately not that easy to specify Cargo features based on the build profile... |
793ac8b to
99e3534
Compare
779c043 to
ddc5b76
Compare
37b86cd to
12a3cce
Compare
|
Hm, 6 new Cargo features is quite a lot, although I see the dilemma. What would the alternatives be? |
|
@beicause could you for now limit this to 3 features? The compiler invocation is already different due to |
The problem is if you have already specified |
|
Note – I was thinking earlier about exposing every safety level as an independent feature (the simplest possible implementation – |
That is true, but the same happens with |
|
As some stuff isn't yet clear and this can be added in a non-breaking way, I'll postpone this to after the initial v0.4 release. |
12a3cce to
dcbc049
Compare
20fb757 to
a8eb3da
Compare
|
I think we can just add two features: |
|
Great idea! We can always add more if users have a concrete case for it 💪 |
Bromeon
left a comment
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.
Thanks for the update!
We should have some CI jobs that run itest with those features, otherwise we don't even know if code compiles, let alone it works.
Maybe we find a way to reuse existing CI jobs, so that total CI time isn't increased... Do you have any suggestions?
|
@beicause Not sure if you saw my review, do you think the suggestions make sense? |
99afb5a to
21adba7
Compare
I think CI already tested paranoid and balanced in debug build and release build. Only fast unsafe is not tested, but I believe it won't pass many test cases in the itest. |
True, we can see it in our CI 😄.
True – and this should be covered, to inform what guarantees are and what aren't held on given check level (not including some tests with I can cover them in separate PR. Failing tests:
As for test target itself – IMO (I don't strive to be authoritative here) it is good to go, we can address itest tweaks to cover |
Renames: - "checks" -> "safeguards" - "debug" -> "dev" (matches Cargo profile) - "paranoid" -> "strict" - "fast-unsafe" -> "disengaged"
|
I took this PR over and will have something working soon. |
21adba7 to
f37c32d
Compare
Use simple #[cfg]s: `safeguards_strict` + `safeguards_balanced`. This implies "at least this safety level". No more indirect `*_at_least = "string"` conditions and extra negation.
f37c32d to
a14de8f
Compare
|
Implemented CI, simplified the Many thanks to @beicause for providing a solid base! |
Update Bromeon -- tweaked some things, but huge thanks go to @beicause for initiative and the solid groundwork.
Safeguard levels
godot-rust now supports three tiers that differ in the amount of runtime checks and validations that are performed:
🛡️ Strict (default for dev builds)
Lots of additional, sometimes expensive checks. Detects many bugs during development.
Gd::bind/bind_mut()provides extensive diagnostics to locate runtime borrow errors.Arraysafe conversion checks (for types likeArray<i8>).⚖️ Balanced (default for release builds)
Basic validity and invariant checks, reasonably fast. Within this level, you should not be able to encounter undefined behavior (UB) in safe Rust code. Invariant violations may however cause panics and logic errors.
Gd::bind/bind_mut()cause panics on borrow errors.☣️ Disengaged
Most checks disabled, sacrifices safety for raw speed. This renders a large part of the godot-rust API
unsafewithout polluting the code; you opt in viaunsafe impl ExtensionLibrary.Before using this, measure to ensure you truly need the last bit of performance (balanced should be fast enough for most cases; if not, consider bringing it up). Also test your code thoroughly using the other levels first. Undefined behavior and crashes arising from using this level are your full responsibility. When reporting a bug, make sure you can reproduce it under the balanced level.
Gd::bind/bind_mut()are unchecked -> UB if mutable aliasing occurs.Cargo features
You can downgrade 1 level in each
dev(Debug) andreleaseCargo profiles, with following features:safeguards-dev-balanced: fordev, use balanced instead of the default strict level.safeguards-release-disengaged: forrelease, use disengaged instead of the default balanced level.This PR also adds both features to both minimal and full CI runs. There were a lot of missing classifications in test, as well as a few bugs/UB due to wrong
#[cfg].CI and conditional compilation
Speaking of
#[cfg], I simplified the way they can be checked for in code. The safeguards usage can be extended over time, and probably replace quite a few#[cfg(debug_assertions)]conditions.Outlook
Warning
Safeguards are a recent addition to godot-rust and need calibrating over time. If you are unhappy with how the balanced level performs in basic operations, consider bringing it up for discussion. We'd like to offer the disengaged level for power users who really need it, but it shouldn't be the only choice for decent runtime performance, as it comes with heavy trade-offs.
As of v0.4, the above checks are not fully implemented yet. Neither are they guarantees; categorization and naming may change over time.
Original description:
Addresses #1276.
Allow configuring safety level through
GDEXT_SAFETY_LEVEL_DEBUGandGDEXT_SAFETY_LEVEL_RELEASEenvironment variables. Not sure if it can be implemented as ExtensionLibrary function. Also implemented as Cargo features may be annoying.debug_assertions(RTTI,backtrace, Array elements validation)(Correct me if I missed anything).