Search code examples
segmentation-faultvalagenie

Genie Segfaults on easy typecast


I have Valac 0.30 installed. Running the following code,

[indent=4]
init
    str : string
    str = "Hello World";
    data : array of uint8
    data = (array of uint8) str;
    print "%i\n", data.length;

I get a segfault. GDB tells me this:

Program received signal SIGSEGV, Segmentation fault.
__memcpy_sse2_unaligned ()
    at ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S:36
36  ../sysdeps/x86_64/multiarch/memcpy-sse2-unaligned.S: No such file or directory.

I've seen some other people with this problem, but none of them got solutions which have worked for me.


Solution

  • You are telling the compiler to hard cast a string into an array of uint8, however those types are not assignment compatible.

    Under the hood the simplified generated C code (which you can get with valac -C) looks like this:

    #include <glib.h>
    
    int main (void) {
            gchar* str = g_strdup ("Hello World");
            // Ouch: A negative number is used as length for g_memdup
            // This will produce a segfault, because the parameter is unsigned and will overflow to a very big number.
            // The string is only 11 bytes long however
            guint8* data = g_memdup (str, -1 * sizeof(guint8));
            int data_length1 = -1;
            g_print ("%i\n\n", data_length1);
            g_free (data);
            g_free (str);
            return 0;
    }
    

    The string data type has two properties that are meant for what you are trying to do (Vala syntax):

    public int length { get; }
    public uint8[] data { get; }
    

    So you could write your code like this:

    [indent=4]
    init
        str: string = "Hello World";
        print "%i\n", str.length;
    

    Or like this:

    [indent=4]
    init
        str: string = "Hello World";
        data: array of uint8 = str.data;
        print "%i\n", data.length;
    

    For completeness here is the gdb backtrace:

    (gdb) run
    Starting program: /home/user/src/genie/Test
    [Thread debugging using libthread_db enabled]
    Using host libthread_db library "/lib64/libthread_db.so.1".
    
    Program received signal SIGSEGV, Segmentation fault.
    __memcpy_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:245
    245             vmovdqu -0x80(%rsi,%rdx), %xmm5
    (gdb) bt
    #0  __memcpy_avx_unaligned () at ../sysdeps/x86_64/multiarch/memcpy-avx-unaligned.S:245
    #1  0x00007ffff78b66c6 in memcpy (__len=4294967295, __src=0x60cdd0, __dest=<optimized out>) at /usr/include/bits/string3.h:53
    #2  g_memdup (mem=0x60cdd0, byte_size=4294967295) at /usr/src/debug/dev-libs/glib-2.46.2-r2/glib-2.46.2/glib/gstrfuncs.c:392
    #3  0x00000000004007d6 in _vala_array_dup1 (self=0x60cdd0 "Hello World", length=-1) at /home/user/src/genie/Test.gs:6
    #4  0x000000000040085e in _vala_main (args=0x7fffffffdf78, args_length1=1) at /home/user/src/genie/Test.gs:6
    #5  0x00000000004008f5 in main (argc=1, argv=0x7fffffffdf78) at /home/user/src/genie/Test.gs:2
    

    So g_memdup is trying to copy 4294967295 bytes from an 11 byte string here.