Search code examples
csegmentation-faultvala

Vala: warning and segmentation fault with to_utf32_fast method


I got a warning and a segmentation fault when compiling and running roughly the following code, which uses the to_utf32_fast method on a string and should return the number of UTF-32 characters encoded in the codepoint_count variable. This method transpiles to the C function g_utf8_to_ucs4_fast and somehow out codepoint_count ends up as long * * argument instead of the expected long *.

I do have a workaround, so this isn't urgent.

int main (string[] args) {
    string test = "abc";
    long codepoint_count;
    string utf32_version = test.to_utf32_fast(-1, out codepoint_count).to_string();
    stdout.printf("success");
    return 0;
}

The relevant part of the output:

C:/msys64/usr/src/outerror.vala.c: In function '_vala_main':
C:/msys64/usr/src/outerror.vala.c:78:50: warning: passing argument 3 of 'g_utf8_to_ucs4_fast' from incompatible pointer type [-Wincompatible-pointer-types]
  _tmp2_ = g_utf8_to_ucs4_fast (test, (glong) -1, &_tmp1_);
                                                  ^
In file included from C:/msys64/mingw64/include/glib-2.0/glib/gstring.h:33:0,
                 from C:/msys64/mingw64/include/glib-2.0/glib/giochannel.h:34,
                 from C:/msys64/mingw64/include/glib-2.0/glib.h:54,
                 from C:/msys64/usr/src/outerror.vala.c:5:
C:/msys64/mingw64/include/glib-2.0/glib/gunicode.h:798:12: note: expected 'glong * {aka long int *}' but argument is of type 'glong ** {aka long int **}'
 gunichar * g_utf8_to_ucs4_fast (const gchar      *str,
            ^~~~~~~~~~~~~~~~~~~

I looked at the transpiled C source code and the third argument to g_utf8_to_ucs4_fast is the address of an uninitialized pointer to long which is later freed with g_free. This triggers a segfault when the program is run.

Am I doing something wrong in the way I'm calling this function? It's declared as public string32 to_utf32_fast (long len = -1, out long? items_written = null).

I'm new to Vala (more familiar with C) and not sure I grasp the argument annotations. The second argument shouldn't be transpiled to C as long ** rather than long *, but maybe the nullability marker ? or the default value = null leads Vala to think that the variable items_written is a pointer to long (or the Vala equivalent thereof) rather than long. If so, then maybe there is an error in the declaration of the method or an ambiguity in Vala syntax.


Solution

  • The declaration is wrong. This code works just fine:

    [CCode (cname = "g_utf8_to_ucs4_fast")]
    public extern string32 to_utf32_fast_ (string s, long len = -1,
        out long items_written);
    
    int main (string[] args) {
        string test = "abc";
        long codepoint_count;
        string32 utf32_version = to_utf32_fast_(test, -1, out codepoint_count);
        stdout.printf("success");
        return 0;
    }
    

    In the original declaration from glib-2.0.vapi the items_written parameter would be a glong** in C, but it actually is a glong*.

    I have reported this as a bug:

    https://gitlab.gnome.org/GNOME/vala/issues/634