-
-
Notifications
You must be signed in to change notification settings - Fork 593
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
Regressions from PR #1044 and #1045 #1119
Comments
One thing that's missing from the above, and which was pointed out in godotengine/godot#69902 and #958:
This means, when calling virtual functions with arguments or return value of https://github.com/godotengine/godot/blob/56fc631/core/object/ref_counted.h#L249-L254 This is (I think) to ensure that refcount does not reach 0 when crossing the boundaries causing the objects to be freed. This is also why godotengine/godot#69902 added two functions to the gdextension interface to allow getting/setting the object referenced by an opaque pointer to a godot
My feeling on this is:
|
Thanks, @Faless! Probably one of the important next steps here is experimenting with ways to do solution nr 3, so we can see how complex it is to implement. I'll try and put some time into that! |
There was actually one special case where GDScript failed, which was fixed by godotengine/godot#72654. This was also something that had back and forth changes fixing one case while breaking another. To put it short, in some cases where IMO we should agree on a consistent behavior for the encoding of objects and use the same standard everywhere, otherwise we're always going to have this battle of "I think it works this way" without realizing it works in a different for other cases. It is the main source of these issues.
This seems like a problem in this method itself, it should return an I do take the blame for this since I implemented the This type of stuff has caused many problems already in the GDScript VM. It does beg the question why this is working fine though. Perhaps it goes back to
This seems like a bug in Godot to me, it should never send a Regarding the potential solutions.
If we change this, I would go with always using This is definitely disruptive but probably the best solution if we can make However, changing the virtual calls to use
This most likely requires changing
For me this is the last resort if we can't agree on changes in Godot itself, or don't have the time to implement those. |
I would like to share my thoughts on this topic because I was the person who initially reported the regression on #1045.
First of all, I feel suspicious about the current implementation where Variant is doing the refcounting, because a Variant class in general should work merely like a wrapper storage for multiple alternative types. We really shouldn't expect Variant to do some extra work like refcounting. If we really need to store refcounted objects to variant, the Variant type should accept Regarding the comment from @vnen, I think the latter choice makes more sense. We can't eliminate
Option 3 essentially means that we're accepting the current inconsistency on ABI. I have a really bad feeling about that, because the inconsistency is the principal cause of this recurring headache. FYI, this is not just the problem for I completely agree vnen for this for this point:
|
@vnen Thanks!
This is essentially option nr 2. I may have described them too verbosely, but basically: Option nr 1 = standardize everything on
I think it's also worth experimenting with changing |
I recently stumbled upon this with the rust bindings, where i solved this using option 3: godot-rust/gdext#275 I wasn't sure if this was an actual issue godot-cpp also faced, but it's interesting to know that you have the same issue. It should be pretty simple for us to adapt our code to fit whichever solution you go for. |
I attempted to implement option nr 2 in Godot PR godotengine/godot#77410 I'm sure I'm missing something (or, most probably a lot of somethings!) because the changes are really pretty minimal. I expect I'll have to update it a whole bunch once I have a better understanding of what this breaks. :-) However, when paired with godot-cpp PR #1123 it seems to fix the regressions (and the original issues that #1044 and #1045 were attempting to fix), although, I didn't test super in-depth. I'm really in disbelief at how easily these changes seemed to come together. I fully expect that I'm missing something big, or botched my tests somehow, because it can't be this easy. :-) |
I've just posted PR #1135 for godot-cpp that implements option nr 3: decoding the arguments differently depending on if it's a virtual or non-virtual method. Given that we're about 1 week passed the feature freeze and Godot PR godotengine/godot#77410 hasn't gotten review from any of the necessary stakeholders, this may end up being the way we need to go for Godot 4.1. |
Godot PR godotengine/godot#77410 was merged! After #1123 is merged, we should be able to close this :-) |
Fixed by #1123. |
These two recently merged PRs have led to a serious regression:
I'm making this issue to try and consolidate information about the regressions, hopefully leading to a PR to fix them!
Overview
Both of those PRs aim to fix calling methods defined in GDExtension (godot-cpp) from GDScript. Before merging the PRs, calling any non-virtual method that took
Object *
orRef<T>
as a parameter would lead to a crash.However, now calling any virtual method that takes an
Object *
orRef<T>
as a parameter will lead to a crash!Both PRs change
PtrToArg<>::convert()
for their respective types, in the same way: where they previously assumed they were receiving anObject **
, the PRs switched to the assumption that they are receiving anObject *
.So, it seems that calling a non-virtual method from GDScript passes an
Object *
and calling a virtual method passesObject **
.Where does the difference come from?
As @zhehangd points out, in the GDScript VM we have
For an object,
VariantInternal::get_opaque_pointer()
returns a plainObject *
. Hence, we're encoding anObject *
asObject *
.However, when we look at the macros in gdvirtual.gen.inc (which generate the code that calls virtual methods) we've got:
This is a little trickier to decipher.
PtrToArg<Object *>::EncodeT
isObject *
, so it's making a local variable with theObject *
. And then it's putting a pointer to that local variable (so, anObject **
) into theargptrs
array. That appears to be how we're getting theObject **
Possible solutions
Well, first of all, since
PtrToArg<>
on the godot-cpp side is supposed to round-trip encode/convert the data fromPtrToArg<>
on the Godot side, they are now out-of-sync. So, no matter what solution we end up pursuing, we should make sure thatPtrToArg<>
is doing the same thing in both godot-cpp and Godot again.Here's some possible solutions:
Object *
), and changing Godot'sPtrToArgs<>
to match godot-cpp's, as well as altering the macros in gdvirtual.gen.inc. This would be a breaking change to GDExtensions ABI (in a way that we don't have a system to provide compatibility), and may affect how C# works? (I really have no idea how the C# binding works, so that's just a guess. If it doesn't call virtual methods through those same macros, then it wouldn't be affected, but I suspect it does?)Object *
asObject **
and then revert the two godot-cpp PRs. However, since GDScript was able to call all sorts of methods just fine (just not non-virtual ones defined in GDExtension), I'm assuming this would break things in other places?Object *
's differently depending on whether or not the method being called is a virtual method or not. This is the least disruptive change because it's all in godot-cpp, but I haven't tried to implement it yet, so I'm not sure how messy it would be.What do you think?
We really need some solution to this before Godot 4.1 is released, because godot-cpp is pretty broken at the moment.
The text was updated successfully, but these errors were encountered: