Skip to content

Allow configuring safety level through environment variables #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

Open
wants to merge 1 commit into
base: master
Choose a base branch
from

Conversation

beicause
Copy link

Addresses #1276.

Allow configuring safety level through GDEXT_SAFETY_LEVEL_DEBUG and GDEXT_SAFETY_LEVEL_RELEASE environment variables. Not sure if it can be implemented as ExtensionLibrary function. Also implemented as Cargo features may be annoying.

  • level 0: no checks.
  • level 1: ensures object is alive.
  • level 2: and other checks that prevously debug_assertions (RTTI, backtrace, Array elements validation)
    (Correct me if I missed anything).

@GodotRust
Copy link

API docs are being generated and will be shortly available at: https://godot-rust.github.io/docs/gdext/pr-1278

@Bromeon Bromeon added the feature Adds functionality to the library label Aug 17, 2025
@Bromeon Bromeon added this to the 0.4 milestone Aug 17, 2025
@TitanNano
Copy link
Contributor

What if we call this GDEXT_SAFETY_CHECKS_* and the values something like STRICT, MINIMAL and NONE. I find this clearer as a user.

The cfg attribute could also be called with_safety_level or with_checks.

Copy link
Member

@Bromeon Bromeon left a 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:

  1. 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-2 etc.

    • 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.
  2. 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, balanced and paranoid. (To be discussed)
    • Cargo feature would then be checks-fast-unsafe.
    • Conditional compilation would be #[cfg(checks_at_least = "balanced")]. Let's avoid not if possible.

@Yarwin
Copy link
Contributor

Yarwin commented Aug 17, 2025

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"?).

gdext/godot-ffi/src/lib.rs

Lines 288 to 293 in 0dde85e

fn print_preamble(version: GDExtensionGodotVersion) {
let api_version: &'static str = GdextBuild::godot_static_version_string();
let runtime_version = read_version_string(&version);
println!("Initialize godot-rust (API {api_version}, runtime {runtime_version})");
}


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 PartialEq for Gd<T>:

gdext/godot-core/src/obj/gd.rs

Lines 1078 to 1087 in aaf3ed5

impl<T: GodotClass> PartialEq for Gd<T> {
/// ⚠️ Returns whether two `Gd` pointers point to the same object.
///
/// # Panics
/// When `self` or `other` is dead.
fn eq(&self, other: &Self) -> bool {
// Panics when one is dead
self.instance_id() == other.instance_id()
}
}

instance_id() checks for object validity, while it could be self.instance_id_unchecked() == other.instance_id_unchecked() (compare potentially dead objects) in fast profile level (or even balanced (2)? It won't cause UB, but may cause follow-up logic errors and panics 🤔).

(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)

@Bromeon
Copy link
Member

Bromeon commented Aug 17, 2025

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:

  • in Debug mode: strict/paranoid/extensive checks (highest level)
  • in Release mode: balanced checks (middle level)

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...

@beicause beicause force-pushed the safety-level-config branch 3 times, most recently from 793ac8b to 99e3534 Compare August 18, 2025 05:28
@Bromeon Bromeon force-pushed the master branch 2 times, most recently from 779c043 to ddc5b76 Compare August 18, 2025 19:16
@beicause beicause force-pushed the safety-level-config branch from 99e3534 to 37b86cd Compare August 19, 2025 05:41
@beicause beicause force-pushed the safety-level-config branch from 37b86cd to 12a3cce Compare August 19, 2025 05:44
@Bromeon
Copy link
Member

Bromeon commented Aug 19, 2025

Hm, 6 new Cargo features is quite a lot, although I see the dilemma.

What would the alternatives be?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
feature Adds functionality to the library
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants