ZScript crash (very fatal error, 100% repro)

Fri Sep 24, 2021 8:09 am

Sorry, I have no idea how I can be more specific in the thread title. The following ZScript can be used to reliably crash GZDoom with a very fatal error:

Code:
class TestInv : Inventory
{
    override bool TryPickup(in out Actor toucher)
    {
        let d = new('Derived');
       
        d.test = "12345";
        d.F1();
   
        GoAwayAndDie();
        return true;
    }
}

class Base abstract
{
    MyStruct s;

    void F1()
    {
        s.Value1 = 1;
        F2();
    }
   
    protected abstract void F2();
}

class Derived : Base
{   
    String test;
   
    override void F2()
    {
        Console.Printf("Calling F2");
        Console.Printf(test); // BOOM
    }
}

struct MyStruct
{
    int Value1;
    MyInnerStruct Inner;
}

struct MyInnerStruct
{
    int Value2;
}

To reproduce, load the script file and go to any map, then type give testinv in the console. The crash will happen immediately when the engine attempts to print the value of test during the call to Derived::F2.

Tested in GZDoom 4.7.0 and g4.8pre-4-g3ef60a40a.
You do not have the required permissions to view the files attached to this post.

Re: ZScript crash (very fatal error, 100% repro)

Thu Sep 30, 2021 1:14 am

Here's some additional information about this issue that might be useful in resolving it:

  1. It doesn't have to do anything with abstract functions (replacing abstract with virtual and adding an empty body does not change the behavior).
  2. It has something to do with structs.
  3. In particular, it has something to do with structs that have other structs as members.
  4. It also has something to do with the order in which the structs are defined (moving the definition of MyInnerStruct to before MyStruct resolves the crash).
  5. The crash itself appears to be a side-effect of memory corruption (crashes somewhere in the FString code, complaining about invalid pointers).
  6. The crash might have something to do with inheritance, or it could be just a more efficent way of triggering it (merging the classes Base and Derived, in this case, resolves the crash).
I first encountered this issue while rewriting the UI code in my project to use structs (to work around this bug, as it seems that it's not going to get fixed in the foreseeable future), and then had quite a difficult time attempting to isolate it. Aside from this particular issue, user-defined structs in ZScript do seem to suffer from several other drawbacks, and are thus not suitable for production use yet (IMHO).

Re: ZScript crash (very fatal error, 100% repro)

Thu Sep 30, 2021 1:12 pm

Some simple tests show this is affected by definition order. That indicates something's hitting one of the structs when it hasn't had its size calculated yet and messing the type's fields' alignment and the type's size because of that.

Re: ZScript crash (very fatal error, 100% repro)

Thu Sep 30, 2021 1:48 pm

It seems the cause is this conditional. Partially-sized classes get their size changed from TentativeClass, which screws this conditional up and makes it start compiling a class whose parent hasn't been fully sized yet.