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

Fix a crash when plugin tries to call make_mesh_previews on enable #81121

Merged

Conversation

jsjtxietian
Copy link
Contributor

@jsjtxietian jsjtxietian commented Aug 29, 2023

Fixes #80333
When we update the plugin list, we should check the tree is blocked or not, if blocked, create_item will return nullptr and thus cause crash.

@jsjtxietian jsjtxietian requested a review from a team as a code owner August 29, 2023 11:32
@akien-mga akien-mga added this to the 4.2 milestone Aug 29, 2023
@akien-mga akien-mga added the cherrypick:4.1 Considered for cherry-picking into a future 4.1.x release label Aug 29, 2023
@YuriSizov
Copy link
Contributor

That doesn't look like a good fix. We just end up not updating the list when it is requested because a tree is propagating mouse events. It seems to me that such situation should never arise in the first place, otherwise every tree is potentially error-prone (you either crash or miss an update that you need).

What the solution would look like I'm not sure. For this particular case, though, we should find a way to block make_mesh_previews from running in the same frame as the plugin node is getting ready.

@jsjtxietian
Copy link
Contributor Author

jsjtxietian commented Aug 30, 2023

I agree this is not the perfect solution for this, and such situation should never arise in the first place.

But I find it hard to break the chain, Tree::propagate_mouse_event -> EditorNode::add_editor_plugin -> _gdvirtual__ready_call -> make_mesh_previews -> make a progress bar and destruct -> the window receives NOTIFICATION_WM_WINDOW_FOCUS_IN -> call update_plugins .

It seems like delay any of this chain's function to next frame is dangerous and non trivial. make_mesh_previews is in _ready, and user may ask for it's result for later use, not sure how to do it the easy way.

And in this particular case I think my fix is fine because the update_plugins will be called many times, miss this one won't cause problem. Or maybe we should not call update_plugins so often? What this function actually do is rebuild plugin list instead of update. Have a filewatcher and only update the plugin list when files change instead of every time the window gains focus.

@YuriSizov
Copy link
Contributor

It seems like delay any of this chain's function to next frame is dangerous and non trivial. make_mesh_previews is in _ready, and user may ask for it's result for later use, not sure how to do it the easy way.

That is a problem in and of itself. This method internally moves the main loop two frames ahead. This already can result in unexpected behavior.

@jsjtxietian
Copy link
Contributor Author

jsjtxietian commented Aug 31, 2023

Or we can remove the EditorProgress (maybe will result in usability problem) and the following code inside make_mesh_preview

DisplayServer::get_singleton()->process_events();
Main::iteration();
Main::iteration();

The code does look suspicious to me.

@YuriSizov
Copy link
Contributor

We can remove EditorProgress, yeah. It's notorious and we had to do this in past to fix various issues. As a temporary solution this would be more acceptable, I think.

Ideally, make_mesh_preview should probably work asynchronously, just like the resource preview generator does. That would be a breaking compatibility change, but the current implementation is pretty problematic. cc @KoBeWi who's recently worked on make_mesh_preview.

@KoBeWi
Copy link
Member

KoBeWi commented Aug 31, 2023

The easiest and least invasive fix is adding CONNECT_DEFERRED to this line:
https://github.com/godotengine/godot/blob/549fcce5f8f7beace3e5c90e9bbe4335d4fd1476/editor/editor_plugin_settings.cpp#L248C11-L248C11

@jsjtxietian
Copy link
Contributor Author

jsjtxietian commented Sep 1, 2023

Apply @KoBeWi 's suggestion, godot will complain about “Do not use progress dialog (task) while flushing the message queue or using call_deferred()!”, it seems we still need to remove EditorProgress.

Also,

This method internally moves the main loop two frames ahead. This already can result in unexpected behavior.

The code will make the mrp project with plugin enabled crash at start. Without them it's fine. Should I remove them too?

@jsjtxietian jsjtxietian force-pushed the fix-crash-in-make_mesh_previews branch from c5719fa to eaa452a Compare September 5, 2023 07:57
@KoBeWi
Copy link
Member

KoBeWi commented Sep 5, 2023

Apply @KoBeWi 's suggestion, godot will complain about “Do not use progress dialog (task) while flushing the message queue or using call_deferred()!”

It does not crash though, so the error is harmless. I'd say the original issue comes from the wrong usage of make_mesh_previews(). We should make sure that the editor does not crash, but errors are fine.

@YuriSizov
Copy link
Contributor

I'd say the original issue comes from the wrong usage of make_mesh_previews().

What do you think about making it asynchronous, like EditorResourcePreview? That should avoid any unexpectedness on the architectural level.

@KoBeWi
Copy link
Member

KoBeWi commented Sep 5, 2023

That could work, but it would require a signal for finishing and it's a compatibility breakage (on behavior level).
The Main::iteration() thing caused me some problems in another PR, so I'd be in favor of removing it if it's possible.

@jsjtxietian
Copy link
Contributor Author

Based on your discussion, I guess for this crash we can just add CONNECT_DEFERRED to update_plugins.

Should I remove Main::iteration() too? Why do we have it in the first place, to make the editor progress bar more responsive?

@KoBeWi
Copy link
Member

KoBeWi commented Sep 6, 2023

Main::iteration is required to render the meshes. It forces the MainLoop to progress as if a frame has passed.
Removing it would make the deferred flag unnecessary (at least for the purpose of this fix), but it would also require adjusting the make_mesh_previews() behavior.

The bug happens when plugin tree is propagating mouse events
(so it is blocked), but EditorProgress's dtor will make main editor
focused and call update_plugins immediately
 which will update the blocked tree.
@jsjtxietian jsjtxietian force-pushed the fix-crash-in-make_mesh_previews branch from eaa452a to 7e3a762 Compare September 6, 2023 03:11
@YuriSizov
Copy link
Contributor

Should I remove Main::iteration() too? Why do we have it in the first place, to make the editor progress bar more responsive?

For the record, the progress dialog makes itself responsive by also calling Main::iteration(); every time you progress it to the next step. Which only adds to the mess here.

Copy link
Member

@KoBeWi KoBeWi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's basically a temporary fix, but it's harmless, so probably fine.

Copy link
Contributor

@YuriSizov YuriSizov left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This fixes the crash, though I'm not sure make_mesh_previews is working as expected in the MRP. On the first call it doesn't seem to return anything.

But that's a bigger problem, as discussed. This should be fine for now to prevent the most problematic part of it.

@YuriSizov YuriSizov merged commit 102f42a into godotengine:master Sep 6, 2023
15 checks passed
@YuriSizov
Copy link
Contributor

Thanks!

@YuriSizov YuriSizov removed the cherrypick:4.1 Considered for cherry-picking into a future 4.1.x release label Sep 20, 2023
@YuriSizov
Copy link
Contributor

Cherry-picked for 4.1.2.

@jsjtxietian jsjtxietian deleted the fix-crash-in-make_mesh_previews branch September 21, 2023 02:10
@YuriSizov YuriSizov changed the title Fix a crash when enable a tool plugin uses make_mesh_previews Fix a crash when plugin tries to call make_mesh_previews on enable Sep 21, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

make_mesh_previews() crashes Godot
4 participants