Repository: godotengine/godot (language: cpp)

Issue:
Godot crashes when editing style boxes of `TabContainer`
### Tested versions

- Not reproducible in: Godot v4.2.2.stable, Godot v4.3-dev1, 3, 4, 5
- Reproducible in: Godot v4.3.stable, v4.3-rc1, v4.3-beta2 & 1, v4.3-dev6

### System information

Godot v4.3.stable unknown - Arch Linux #1 SMP PREEMPT_DYNAMIC Thu, 19 Dec 2024 21:29:01 +0000 - Wayland - Vulkan (Forward+) - integrated Intel(R) HD Graphics 5500 (BDW GT2) - Intel(R) Core(TM) i5-5200U CPU @ 2.20GHz (4 Threads)

### Issue description

https://github.com/user-attachments/assets/a600fc99-e4dc-4dc2-b63c-c3f8037e51f2

Verbose output (normal output doesn't have a backtrace): [godot_save3.log](https://github.com/user-attachments/files/18233105/godot_save3.log)


### Steps to reproduce

The video above shows how to make godot crash, but I'll write it anyways.

- Open the MRP (the warning that appears can be ignored);
- Open `settings_window.tscn`;
- Open the theme editor;
- Resize the Godot window horizontally to the minimum, and vertically until both tabs are visible;
- Click on either tab and Godot will crash

### Minimal reproduction project (MRP)

[mrp.tgz](https://github.com/user-attachments/files/18233191/mrp.tgz)



Discussion / hints:
I was unable to reproduce this issue on windows 10, the only thing different that happened was two errors poping about a parser error in some script when i opened the theme editor:

```
res://scripts/notes_panel.gd:22 - Parse Error: Preload file "res://scenes/note_button.tscn" does not exist.
modules/gdscript/gdscript.cpp:2936 - Failed to load script "res://scripts/notes_panel.gd" with error "Parse error". (User)
```

Godot v4.3.stable - Windows 10.0.19045 - Vulkan (Forward+) - dedicated AMD Radeon RX 580 2048SP (Advanced Micro Devices, Inc.; 31.0.21921.1000) - AMD Ryzen 5 3600 6-Core Processor (12 Threads)
@matheusmdx I removed those scripts from the MRP since they weren't necessary for the crash to happen.
After doing some testing I've found that this crash is a regression that started with v4.3-dev6.

I've also updated the steps to reproduce with what actually causes the crash to happen, that being one of the tabs pushing the other one out of view, this is properly handled in versions earlier than v4.3-dev6.

@matheusmdx could you try to reproduce this crash again with the correct instructions?
With the new steps i was able to replicate the issue, you don't need to click the tab, just hover the mouse in the second tab is enough to crash. This trigger an infinite recursion between `TabBar::_update_cache` and `TabBar::_update_hover`:

![Image](https://github.com/user-attachments/assets/4b3c3776-9c32-4d27-a441-171e1c8140e6)

<br>

In my case i was able to reproduce this issue from 4.1.2, bisecting points for commit 3bb05da from pr #81202 as the culprit:

![Image](https://github.com/user-attachments/assets/c07a0746-44a2-4cb7-9626-a43878c80adc)

<br>

@em-s-h Can you test if you're able to reproduce this issue in 4.1.2 and if works without crash in 4.1.1. If you crash in the 4.1.2 too i'll ping the pr author, otherwise i'll open a separated issue.
@matheusmdx I wasn't able to reproduce this crash in 4.1.2 or 4.1.1

Fix patch:
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index e8ff6420018e..65e3d23c0bf1 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -1488,8 +1488,8 @@ int TabBar::get_tab_width(int p_idx) const {
 		style = theme_cache.tab_disabled_style;
 	} else if (current == p_idx) {
 		style = theme_cache.tab_selected_style;
-		// Use the unselected style's width if the hovered one is shorter, to avoid an infinite loop when switching tabs with the mouse.
-	} else if (hover == p_idx && theme_cache.tab_hovered_style->get_minimum_size().width >= theme_cache.tab_unselected_style->get_minimum_size().width) {
+		// Always pick the widest style between hovered and unselected, to avoid an infinite loop when switching tabs with the mouse.
+	} else if (theme_cache.tab_hovered_style->get_minimum_size().width > theme_cache.tab_unselected_style->get_minimum_size().width) {
 		style = theme_cache.tab_hovered_style;
 	} else {
 		style = theme_cache.tab_unselected_style;


Test patch: