Page MenuHome

Segfault populating popup menu with specific structure, `scale_x`, and element count. (GPUOffScreen buffer too large?)
Confirmed, NormalPublic

Description

System Information
Operating system: Linux
Graphics card: Intel

Blender Version
Broken: 2.93.0

Short description of error

I have a very specific UI hierarchy and settings that are consistently causing segfaults for me.

I think the short draw code is the best way to explain it:

def draw(self, context):
		layout = self.layout
		row = layout.row(align=True)
		row.scale_x = 2 # Needed for crash.
		col1 = row.column(align=True)
		col2 = row.column(align=True)
		for i in range(40): # Crashes with 40 and 39, but not with 20, 50, or 100.
			col1.label(text=str("a"*20)) #Doesn't matter, I think.
			col2.label(text=str("b"*20))

bpy.context.window_manager.popup_menu(draw, title="")

.scale_x = 2 is needed for the crash. The number of items from the range() also matters, and won't crash with too few or too many. I don't think the lengths of the labels matter.

  • Also happens with column/row layout convoluted/zipped.
  • Also happens with .ui_units_x = 40 replacing .scale_x = 2 (but not with all other values of .ui_units_x).
  • Actually seems to happen with some number (but not all numbers) of elements for any combination of UI dimensions in .popup_menu.
  • Note: Even when it doesn't segfault, the popup menu will often be an obvious rendering error with lots of tearing and such.

Exact steps for others to reproduce the error

Run the script:

Related Objects

Event Timeline

Will (WCN) updated the task description. (Show Details)Sun, Jul 11, 6:42 AM
Will (WCN) updated the task description. (Show Details)Sun, Jul 11, 2:34 PM
Philipp Oeser (lichtwerk) changed the task status from Needs Triage to Confirmed.Mon, Jul 12, 3:21 PM

Can confirm.

note: does not happen if scale_x stays below 1 (at least here on my end)

Read blend: /ScaleXCrash.blend
./bin/blender(BLI_system_backtrace+0x26) [0x1030274e]
./bin/blender(_BLI_assert_print_backtrace+0x16) [0x101d669e]
./bin/blender(BLI_vsnprintf+0x24) [0x102f65da]
./bin/blender(BLI_snprintf+0xaa) [0x102f688c]
./bin/blender(GPU_offscreen_create+0x10f) [0xe1e34c1]
./bin/blender() [0x3d1ec83]
./bin/blender() [0x3d1f97b]
./bin/blender() [0x3d1fe02]
./bin/blender(wm_draw_update+0xc5) [0x3d2043a]
./bin/blender(WM_main+0x48) [0x3d1ca65]
./bin/blender() [0x36c665a]
/lib64/libc.so.6(+0x2b7e0) [0x7fc3290897e0]
/lib64/libc.so.6(__libc_start_main+0x7c) [0x7fc32908988c]
./bin/blender(_start+0x25) [0x36c6035]
BLI_assert failed: source/blender/blenlib/intern/string.c:218, BLI_vsnprintf(), at 'buffer != ((void *)0)'

It is just that the GPUOffScreen buffer would be too large it seems and cannot be created.

The assert can be avoided by the following (but still -- this should be safeguarded against more thoroughly since this gets blender into total unstable land):

1
2
3diff --git a/source/blender/windowmanager/intern/wm_draw.c b/source/blender/windowmanager/intern/wm_draw.c
4index 0922aaaee53..6c3cd357232 100644
5--- a/source/blender/windowmanager/intern/wm_draw.c
6+++ b/source/blender/windowmanager/intern/wm_draw.c
7@@ -454,8 +454,9 @@ static void wm_draw_region_buffer_create(ARegion *region, bool stereo, bool use_
8 /* Allocate offscreen buffer if it does not exist. This one has no
9 * depth or multisample buffers. 3D view creates own buffers with
10 * the data it needs. */
11+ char err_out[256] = "unknown";
12 GPUOffScreen *offscreen = GPU_offscreen_create(
13- region->winx, region->winy, false, false, NULL);
14+ region->winx, region->winy, false, false, err_out);
15 if (!offscreen) {
16 return;
17 }

@Germano Cavalcante (mano-wii): is this something you can look into?

Philipp Oeser (lichtwerk) renamed this task from Segfault populating popup menu with specific structure, `scale_x`, and element count. to Segfault populating popup menu with specific structure, `scale_x`, and element count. (GPUOffScreen buffer too large?).Mon, Jul 12, 3:52 PM

The error is in the internals of the GPU module. Not much related to the python API
The crash happens because the offscreen texture has dimensions above the OpenGL limit, and GPU_offscreen_create requires a non-NULL err_out arg.
Checking if the err_out is NULL would do the trick too.

It can also be interesting to raise an error message in the interface.
I will propose a patch.

Hm. There isn't any way to specify the popup menu size from the Python API though, AFAICT.

In fact, the example code produces a menu that's several times wider than it needs to be, with the majority of the menu being blank space.