-
-
Notifications
You must be signed in to change notification settings - Fork 21.4k
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
Reference to freed object can return a random different one #32383
Comments
Oooh, it had totally the same thing. Good to know I'm not alone ;_; In my case, I had a Control node with script that calls
And it raised an error ~ "No method do_stuff in class ParticleMaterial". Like, what XD Ultimately I ended with this ;_;
|
Could it be that the object ID got re-used? Also, are there threads involved? (I mean, anywhere, not just scripts). |
Can confirm on a game I made some time ago without threads. func ....():
if target == null or not is_instance_valid(target):
var players = get_tree().get_nodes_in_group("player")
if players.size() == 0: return
target = players[randi() % players.size()] It worked -- enemies targeted random players, and switched when their target died. |
This is a known problem, but it requires some major changes to fix. 4.0 will change the way objects are referenced so this (and other similar issues) can be properly fixed. |
Thanks for the update. I think if this is going to be a 4.0 issue I had better remove is_instance_valid from my project. I've only used it 11 times so far. Normally its AI's keeping track of enemy its following or shooting at. It could lead to very subtle wired bugs with AI's walking off in random directions or shooting at the wrong thing. I might try and implement a "about_to_free" signal and emit it before calling queue_free. Then anybody with a reference can listen for the signal and set the var holding the instance to null. We might consider removing is_instance_valid in 3.2, or having a warning when you use it, or at the very least update the help. All it says at the moment is "Returns whether instance is a valid object (e.g. has not been deleted from memory)." which is not true. |
Pretty sure there's already a report about this. Edit: it's this one: #22395 |
I found a workaround for some cases. Let's say you have an object stored in a variable called
Then instead of using |
I wrote a little helper class and now try never to save a reference to a node directly.
Then to use this you have some code that looks something like this.
|
See #22395 for other example projects that reproduce it. It sucks that we can't have a proper fix for this before 4.0 :/ |
When I tried jaykyburz's test project I found that using WeakRef instead of a raw object pointer also fixed it for me. i.e.
WeakRef internally uses an ObjectID rather than pointer, which is looked up when you call get_ref(). If you store both the original pointer and a weakref in the test project, if you remote debug it, you can clearly see the point at which the pointer starts pointing to the wrong object. |
Agreed. Maybe it would be good to add some warnings to the 3.x docs? I would expect to find such warnings in these places:
|
I had an ultimate case in my game. I was not aware of such a thing before reading about this dangling var issue. My script was "queue_free()"ing multiple objects and reasigning new objects to those same variables. Took me pretty long time to find out what was wrong. Documenting this somewhere, if not fixing it, might help people a lot. |
I'm running into this again and wondering if the docs shouldn't be improved. @lawnjelly mentions that weakref works in this case (does it?) (#32383 (comment)) but the doc for
It is not clear what "still works" means. Does |
EDIT: outdated, it seems the issue is fixed, and remram is likely using an outdated version of the engine. |
This issue is the reason I moved away from Godot and the fact that it's still not fixed is why I won't come back. I really love what Godot could have been, but such a serious issue lingering for years is really unprofessional. And then to double down and make debug and release have different behaviors is unbelievable. |
In GDScript at least, weakref is not needed (and even degenerate) when the referenced object is an Object (and not a Reference). Either way, Also I believe the title of this issue was fixed in 4.0? (3.x couldn't do it because it's a significant core change?) |
EDIT: outdated, it seems the issue is fixed, and remram is likely using an outdated version of the engine. |
From what I understood of the underlying issue, even WeakRef was subject to this because the problem lies into how ObjectID is looked up? (i.e a given ObjectID can be later re-used) or maybe that was applying to pointer lookups only? |
EDIT: outdated, it seems the issue is fixed, and remram is likely using an outdated version of the engine. |
AFAIK this issue has been fixed in |
Ah maybe @remram44 is using an old version of the engine, sorry for confusion. 👍 |
The "old version" I use is the latest stable, 3.3. The problem is fixed in 4.0, but in 3.3 it is possible for a non-weakref pointer to suddenly point to a different object, which is what this issue is about. |
… not behaving correctly. # godotengine/godot#32383 # godotengine/godot#43422
Unfortunately, this particular behavior (freed references pointing to random other objects) is NOT fixed in 3.3. If you're referring to the dangling pointer fix (#38119 by @RandomShaper ), I'm not entirely sure I understand what it was fixing, but it did not fix this issue. This seems like a fairly critical issue, and does not break or provide any error or warning in debug, but exhibits this unexpected behavior and problematic behavior in release (references pointing to random other objects). I can provide a sample project if needed. From what I've read of @reduz comments elsewhere, this may be impossible to fix in 3.x. If so, is there a document that explains what the best, safest way to store a reference to a node is then? Thanks everyone! |
It's fixed in 3.x for run in the editor. About extending it to release builds (and debug without debugger attached), I opened this: godotengine/godot-proposals#1589 If you have a case where it fails running from the editor, please report. |
I thought the fix was to use |
This issue killed Godot for me, as well as reduz attitude that its no big deal. And then to double down and allow a release to go out where debug is different to release just shows the folks running the show here really have no idea what its like to ship and maintain a real game. You just can't trust the foundations of this engine, no matter how nice the graphics are. You can't trust the people that guide its development to make good decisions. You would have to be crazy to try and build a business on Gotdot. Can you imagine shipping something on Steam and then getting reports of random crashes in literately any place in your game because object references are reused. Then you spend days and weeks try to reproduce the issue in a debug build so you can try and work out what is going on, but it doesn't happen in debug. |
Totally. This is me getting owned in playstore. Dev attitude is incredible on this one like it is some non important issue. But you never know when it would crash your game without throwing anything, then days and nights to find it. I loved godot man.. I really did, but my game dev career ended before it began. |
@RandomShaper I think the big issue is that it works silently in Debug, but causes game-breaking bugs in Release. This difference of behavior combined with the fact that Debug does not give any warning or error makes for a really frustrating situation. I guess that means I wholeheartedly support your proposal to make release behavior the same as debug! Thanks for that proposal. @remram44 I sounds like that might be a work-around. I haven't found any real official documentation that states this is how you should be storing references to nodes. Instead, everywhere I've seen (official and unofficial) promotes storing a direct reference like @jaykyburz @Yekez I still love Godot, but I am only a hobbyist. I can imagine how frustrating this issue would be when trying to release a production game. Especially if you didn't know of this footgun from the beginning. Sorry to open this can of worms again everyone! I'll go over and support @RandomShaper's proposal. |
There is #50968 now. |
@Calinou I don't know the technical details, but that sounds like a different issue. Is it due to the same functionality in the backend? |
Regarding how to store references to nodes, the standard practice is just that. |
@RandomShaper maybe I am misunderstanding but I do have a situation where I am not getting any error or warning in debug, but a game-breaking bug in release: In debug, I apologize if I'm not being clear. I can upload my sample project later this afternoon if that would help. |
|
@RandomShaper I understand. It doesn't make sense for debug to throw a warning every time you use Regardless, I think we both agree that your proposal to make release work the same as debug should be accepted ASAP. Is there anything we can do as users to help that happen? |
I believe the best thing is to add your real use case issues to the proposal, but I think you've already done it. If anything, this last specific part about |
So what is the current best way to handle checking if an object is deleted if I can't reliably trust |
I have stored the node's instance ID (retrieved from I would be interested to what a developer or someone more intimate with the inner workings of Godot has to say though. Note there is a PR (#51796) to unify this behavior this so fingers crossed, it may become a non-issue. |
Your approach is correct and safe. Regarding performance, that's interesting, and a bit surprising. |
Godot version & OS/device including version:
3.1.1 Windows 10.
Issue description:
I think this is a simple explanation of an issue I have on my project. I have raised this issue without an example project because it will take some time to reproduce in a simple form and I would like some godot experts to look at what I am describing, and let me know if the issue is already logged and known (and perhaps fixed) before I spend more time working on a reproduction cases
Say I have a RobotFactory class and it can instantiate Robots, but it is only allowed to have one active in the world at once. It saves the instantiated robot in a var.
var my_robot = RobotScene.instance()
The robot walks around the world for a while an then is destroyed by something so in its own script it calls queue_free() on itself.
Sometime later in the RobotFactory we call is_instance_valid(my_robot) to see if we should create a new robot.
In my project I have found that sometimes is_instance_valid(my_robot) returns true after my_robot has been freed, but that it is pointing to some other random object in the scene that has been instantiated. Perhaps sometime after the queue_free, but before is_instance_valid call.
The only thing I think could be happening is that there is some kind of underlying pooling system and my_robot is pointing to somewhere that is being reused after the robot is freed.
Please let me know if this is a known issue, is already logged, or if I should do some more work to explain the issue better.
Bugsquad edit: Keyword: previously freed instance
The text was updated successfully, but these errors were encountered: