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

Add DISABLE_OBJECT_BINDING_GUARD compiler flag #1585

Closed
wants to merge 1 commit into from

Conversation

dmlary
Copy link

@dmlary dmlary commented Sep 15, 2024

The guard in Wrapped::Wrapped(const StringName) detects the partial initialization of godot::Object subclasses. This is needed because using new to allocate a godot::Object subclass will result in unexpected crashes because the bindings for the instance have not been set.

The side effect of this guard is that it also prevents any use of a godot::Object subclass on the stack.

There are godot native types such as godot::RegEx that are safe to use on the stack, and are used that way throughout the godot source. Similarly, custom classes that subclass godot::Object may also be used safely on the stack1.

In this commit, I add a compiler flag to disable this guard. This will allow godot-cpp users who understand the safety implications to use godot::Object subclasses on the stack.

Footnotes

  1. https://github.com/godotengine/godot-cpp/pull/1446#issuecomment-2351331480

The guard in `Wrapped::Wrapped(const StringName)` detects the partial
initialization of `godot::Object` subclasses.  This is needed because
using `new` to allocate a `godot::Object` subclass will result in
unexpected crashes because the bindings for the instance have not been
set.

The side effect of this guard is that it also prevents any use of a
`godot::Object` subclass on the stack.

There are godot native types such as `godot::RegEx` that are safe to use
on the stack, and are used that way throughout the godot source.
Similarly, custom classes that subclass `godot::Object` may also be used
safely on the stack[^1].

In this commit, I add a compiler flag to disable this guard.  This will
allow godot-cpp users who understand the safety implications to use
`godot::Object` subclasses on the stack.

[^1]: godotengine#1446 (comment)
@Naros
Copy link
Contributor

Naros commented Sep 16, 2024

Could this be applied surgically so that it isn't globally enabled but per concrete type? Perhaps as a specialization of a new GDREGISTER_STACK_CLASS macro that sets some state that would skip the check in the ctor?

My main concern with a compiler flag is that this disables this check globally. I think that it's better to be explicit for which classes can be used in this fashion versus those that cannot, allowing those that shouldn't to continue to throw the memnew() guard error when used inappropriately.

@dsnopek
Copy link
Collaborator

dsnopek commented Sep 16, 2024

There are godot native types such as godot::RegEx that are safe to use on the stack, and are used that way throughout the godot source.

If you used a godot::RegEx on the stack in godot-cpp, it would "safe" in-so-far as it wouldn't crash, but it would leak memory.

This isn't the case within Godot itself - the implications of not using memnew() or Ref<T> in Godot are different than in godot-cpp, but in both cases, there are things that won't work as expected if you skip using them.

As I've said over on #1446, I'm of the opinion that the cases where Godot is creating classes that descend from Object on the stack are bugs that should be fixed in Godot, not something we should be attempting to allow from godot-cpp.

dmlary added a commit to dmlary/godot-hex-map that referenced this pull request Sep 21, 2024
Have two approches, C++ class and GDScript wrapper class `HexMapCellId`
and `HexMapCellIdRef`, or unified class in `HexMapIterAxial`.  The
unified approach requires an upstream change[^1] to allow stack
allocation of `godot::Object` classes.

`HexMapIterAxial` being an Object means all the doctest tests are now
broken, as it cannot find the `godot::String` implementation pointers.
The tests crash currently because of this.

We do have tests in the godot demo project, using GUT.  They confirm
that `HexMapCellId.get_neighbors()` is properly working from GDScript.

I'm not sure which direction I'll go in the long term.

I'd like to be able to unit test in C++ and GDScript, but I don't want
to have to maintain a pile of pass-through proxy methods in the wrapper
class.  I made one suggestion[^2] in godot-cpp to allow binding methods
to class instance methods, but I don't even know if that's possible.

[^1]: godotengine/godot-cpp#1585
[^2]: godotengine/godot-cpp#1446 (comment)
@dsnopek
Copy link
Collaborator

dsnopek commented Oct 16, 2024

Per this note:

Ok, it seems y'all are pretty fixed on preserving the guard. I can accept that.

... I'm going to close this PR.

@dsnopek dsnopek closed this Oct 16, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants