dlemstra / Magick.NET

The .NET library for ImageMagick
Apache License 2.0
3.36k stars 407 forks source link

Crash when creating MagickImage in a project using GtkSharp on Linux #1126

Open katrina-krings opened 2 years ago

katrina-krings commented 2 years ago

Description

This issue affects Linux specifically, Windows is not impacted.

This issue also is in regard to working with another library with C/C++ bindings, GtkSharp. I opened the issue in this repository, as I believe the problem is more likely in Magick.NET than in GtkSharp, as all GtkSharp objects create fine.

In a project utilizing GtkSharp (the modern one, not mono's), creating a MagickImage (from a file or even an empty one) will result in a warning by GLib-GObject and then kill the program after an assertion fails later.

Steps to Reproduce

Create a .NET 6 console project, and add packages Magick.NET-Q8-AnyCPU and GtkSharp (versions used below) Place the following in Program.cs, and then dotnet run

using System;
using Gtk;
using ImageMagick;

namespace Test{

    class Program{
        [STAThread]
        public static void Main(string[] args){
            Application.Init();
            var app = new Application("org.Test.Test", GLib.ApplicationFlags.None);
            app.Register(GLib.Cancellable.Current);

            var win = new Test();
            app.AddWindow(win);

            win.Show();
            Application.Run();
        }
    }

    class Test : Window{
        public Test() : base("Test Window"){
            new MagickImage();
            ShowAll();
        }
    }
}

The following error will be produced, and then the application will die

(test:120621): GLib-GObject-WARNING **: 09:50:52.201: cannot register existing type 'gchar'
**GLib-GObject:ERROR:../gobject/gvaluetypes.c:455:_g_value_types_init: assertion failed: (type == G_TYPE_CHAR)
Bail out! GLib-GObject:ERROR:../gobject/gvaluetypes.c:455:_g_value_types_init: assertion failed: (type == G_TYPE_CHAR)

System Configuration

dlemstra commented 2 years ago

It looks like this warning is raised inside GtkSharp. I checked the code that is statically linked inside Magick.NET the error message should be this: cannot register existing fundamental type '%s' (as '%s').

I don't know why this happening and I also don't know how I can debug this.

katrina-krings commented 2 years ago

I gave a poke around myself. I suppose it'd just start with stepping through and figuring out what C function is being called by .NET right before this happens, and look through what's going on there. I put this to the side, as Linux support is not immediately important to what I am doing, but if you can't think of anything, I may give a deeper look if I can.

Certainly if two-language debugging gets involved, it would be messy.

katrina-krings commented 2 years ago

I'm still looking into this on and off. It's quite bizarre, but right now I have reason to suspect Magick.Native, as it seems to include glib 2.64.3 I'm not intimately familiar with exactly how .NET's native interop works. However, I dug around and those warnings and subsequent failed assertions come right from the start of glib's type registration code. Perhaps two glibs trying to register types on top of each other is causing the second one to have problems. This wouldn't explain why it works fine on Windows, however, as Magick.Native seems to include that on windows too.

I can't seem to find where glib is currently being used by Magick.NET, and I wasn't able to find any usage upstream in ImageMagick. I tried to import Magick.NET's source into my project, just to debug, but some preprocessor macros influenced by platform/configuration seem to be nonfunctional in my Linux environment.

Expect everything I said to be wrong, but it might at least provide a few clues as to what is going on here.

katrina-krings commented 2 years ago

It does actually seem that Magick.NET is capable of running in a separate thread to GtkSharp without crashing. So a potential workaround is to separate every single call to Magick.NET into a task. This has to be call-only, however, and can't even reference a single context that GtkSharp is active in (even if not accessing any GtkSharp values/functions).

I'd say I'm more confident in my assertion that it's two incompatible, statically linked versions of glib that are trying to load in the same memory space and clashing with each other. The only possible fix I can think of for Linux is to dynamically link to system libraries, but this would also require code change to GtkSharp to do the same.

I still am not sure why this doesn't impact NT, but it's probably just down to how native interop works in .NET on that platform.