bmx-ng / bcc

A next-generation bcc parser for BlitzMax
zlib License
33 stars 12 forks source link

Overloaded new(params) on grandparent type leads to invalid properties #595

Closed GWRon closed 2 years ago

GWRon commented 2 years ago

Scaremonger wrote on discord about a segfaulting issue (and I adjusted the sample code for "ready to run"):

SuperStrict
Framework SDL.GL2SDLMax2D

Type TGameNode
    Field X:Int, Y:Int
    Method render() ; End Method
End Type

Type TItem Extends TGameNode
    Field image:TImage
    Method New( X:Int, Y:Int, image:String ); End Method
    Method render()
        If image DrawImage( image, X, Y )
    End Method
End Type

Type TActor Extends TItem
    Field hilite:TImage
    'enable this and it works as expected
    'without it, `new TActor` (or `new TInfantry`) incorrectly
    'initializes custom properties with "not null but $00000..."
    'Method New( X:Int, Y:Int, image:String ); End Method
End Type

Type TInfantry Extends TActor
    Method render()
        If image; DrawImage( image, X, Y )
        If hilite; DrawImage( hilite, X, Y )
    End Method
End Type

DebugStop
Local soldier:TInfantry = New TInfantry( 10, 10, "four.png" )
Print "IMAGE:  "+[ "NOT NULL", "Null" ][(soldier.image=Null)]
Print "HILITE: "+[ "NOT NULL", "Null" ][(soldier.hilite=Null)]
soldier.render()

When executing it, "HILITE: NOT NULL" will be printed ... and the address of "soldier.hilite" resembles a "0" memory address: image


My assumptions on this are the following:

So the sample code actually does call the "overloaded new()" of a parent type. Seems this incorrectly initializes the extending type instance. Either should "new(param)" of the parent class not be reachable from the extending class - or it should correctly initialize the propery (here "field hilite:TImage")

Seems the C-code contains this here as "overloaded new" for the TInfantry type:

#line 26 "/home/ronny/Arbeit/Tools/BlitzMaxNG/tmp/untitled1.bmx"
void __m_untitled1_TInfantry_New_iiS(struct _m_untitled1_TInfantry_obj* o,BBINT bbt_X,BBINT bbt_Y,BBSTRING bbt_image) {
    __m_untitled1_TItem_New_iiS(o, bbt_X, bbt_Y, bbt_image);
    o->clas = &_m_untitled1_TInfantry;
}```
So it calls the overloaded new from `TItem` -- but NOT the overloaded revision of `TActor` - which would initialize the property correctly:
```C
void __m_untitled1_TActor_New_iiS(struct _m_untitled1_TActor_obj* o,BBINT bbt_X,BBINT bbt_Y,BBSTRING bbt_image) {
    __m_untitled1_TItem_New_iiS(o, bbt_X, bbt_Y, bbt_image);
    o->clas = &_m_untitled1_TActor;
    o->__m_untitled1_tactor_hilite = (struct brl_max2d_image_TImage_obj*)((struct brl_max2d_image_TImage_obj*)&bbNullObject);
}

So shouldnt:

void __m_untitled1_TInfantry_New_iiS(struct _m_untitled1_TInfantry_obj* o,BBINT bbt_X,BBINT bbt_Y,BBSTRING bbt_image) {

actually call:

    __m_untitled1_TActor_New_iiS(o, bbt_X, bbt_Y, bbt_image);
    o->clas = &_m_untitled1_TInfantry;

instead of:

    __m_untitled1_TItem_New_iiS(o, bbt_X, bbt_Y, bbt_image);
    o->clas = &_m_untitled1_TInfantry;

?