OK so looking into this more, it looks like the issue is that an RGBA struct is being freed twice for some reason as it is consistently failing on the RGBA destructor as per the stack trace below from GDB. In my code I allocate an RGBA array for the palette and this allocation seems to be triggering the D GC which in term calls the RGBA destructor and attempt to call gdkrgbafree.
I'm a bit confused on RGBA works in GTK since it is a struct and not a GObject, am I correct in assuming that it is not reference counted or is there something covert happening under the hood?
Also, how are references to this struct managed. For example, when I pass an RGBA to the VTE widget, who's responsible for calling gdkrgbafree, me (i.e. GtkD) or VTE? I checked the VTE source code and don't see any gdkrgbafree so I assume it's the caller?
If that's the case, does this mean I need to maintain persistent references to the RGBA class to ensure the RGBA class doesn't go out of scope and D garbage collects while a widget is still referencing the underlying struct?
#0 0x00007ffff71435f8 in raise () from /usr/lib/libc.so.6
#1 0x00007ffff7144a7a in abort () from /usr/lib/libc.so.6
#2 0x00007ffff1d74e18 in g_slice_free1 () from /usr/lib/libglib-2.0.so.0
#3 0x0000000000850c24 in gdk.RGBA.RGBA.~this() (this=0x7ffff7f1c220) at ../../../.dub/packages/gtk-d-3.2.0/src/gdk/RGBA.d:91
#4 0x0000000000a985bf in rt_finalize2 ()
#5 0x0000000000a986a2 in rt_finalizeFromGC ()
#6 0x0000000000a94336 in gc.gc.Gcx.sweep() ()
#7 0x0000000000a94ae5 in gc.gc.Gcx.fullcollect(bool) ()
#8 0x0000000000a92b7b in gc.gc.Gcx.smallAlloc(ubyte, ref ulong, uint) ()
#9 0x0000000000a90669 in gc.gc.GC.malloc(ulong, uint, ulong*, const(TypeInfo)) ()
#10 0x0000000000a6970f in gc_qalloc ()
#11 0x0000000000a978e5 in rt.lifetime.__arrayAlloc(ulong, const(TypeInfo), const(TypeInfo)) ()
#12 0x0000000000a6b8b2 in _d_newarrayU ()
#13 0x0000000000a6b935 in _d_newarrayT ()
#14 0x0000000000838017 in gx.terminix.terminal.terminal.Terminal.applyPreference(immutable(char)[]) (this=0x7ffff7f2f000, key=...) at source/gx/terminix/terminal/terminal.d:640
#15 0x000000000083a0fc in gx.terminix.terminal.terminal.Terminal.this(immutable(char)[]).__dgliteral4!(gio.Settings.Settings).__dgliteral4(immutable(char)[], gio.Settings.Settings) (this=0x7ffff7f23ae0, Settings=0x7ffff7eb2a00, key=...) at source/gx/terminix/terminal/terminal.d:1040
#16 0x000000000087df4b in gio.Settings.Settings.callBackChanged(gtkc.giotypes.GSettings*, char*, gio.Settings.Settings) (settingsStruct=0x11316b0,
key=0x124d825 "background-transparency-percent", _settings=0x7ffff7eb2a00) at ../../../.dub/packages/gtk-d-3.2.0/src/gio/Settings.d:1547
#17 0x00007ffff1226aca in g_cclosure_marshal_VOID__STRINGv () from /usr/lib/libgobject-2.0.so.0
In case it helps, here's my code for this section, line 640 in the stack trace corresponds to the RGBA[palette] = new RBA[colors.length] line.
case SETTINGS_PROFILE_FG_COLOR_KEY, SETTINGS_PROFILE_BG_COLOR_KEY, SETTINGS_PROFILE_PALETTE_COLOR_KEY,
SETTINGS_PROFILE_USE_THEME_COLORS_KEY, SETTINGS_PROFILE_BG_TRANSPARENCY_KEY:
RGBA fg;
RGBA bg;
if (gsProfile.getBoolean(SETTINGS_PROFILE_USE_THEME_COLORS_KEY)) {
vte.getStyleContext().getColor(StateFlags.ACTIVE, fg);
vte.getStyleContext().getBackgroundColor(StateFlags.ACTIVE, bg);
} else {
fg = new RGBA();
bg = new RGBA();
if (!fg.parse(gsProfile.getString(SETTINGS_PROFILE_FG_COLOR_KEY)))
trace("Parsing foreground color failed");
if (!bg.parse(gsProfile.getString(SETTINGS_PROFILE_BG_COLOR_KEY)))
trace("Parsing background color failed");
}
bg.alpha = to!double(100 - gsProfile.getInt(SETTINGS_PROFILE_BG_TRANSPARENCY_KEY)) / 100.0;
string[] colors = gsProfile.getStrv(SETTINGS_PROFILE_PALETTE_COLOR_KEY);
RGBA[] palette = new RGBA[colors.length];
foreach (i, color; colors) {
palette[i] = new RGBA();
if (!palette[i].parse(color)) trace("Parsing color failed " ~ colors[i]);
}
vte.setColors(fg, bg, palette);
break;