I am getting a random compile failure due to use of a garbage datatype for a field which should be a ptr of a forward-declared type, in both x86 and x86_64 builds, in fbc 1.09 and 1.08.1. I briefly tried 1.06 but didn't see it there. The bug is presumably not in the C emitter, but using it exposes the bug because GCC throws an error due to the bad type.
Testcase:
TYPE NodePtr as Node ptr
TYPE Doc
'The order of these fields doesn't matter
root as NodePtr
fileName as string 'Cause ctor to be emitted
y as any ptr 'For comparison
END TYPE
TYPE Node
x as integer
END TYPE
Function CreateDocument() as Doc Ptr
return New Doc 'Doing this at file scope does not seem to trigger the bug
End function
compiled with fbc -c -R -gen gcc testcase.bas this usually produces:
static void _ZN3DOCC1Ev( struct $3DOC* THIS$1 )
{
__builtin_memset( (__builtin_va_list**)THIS$1, 0, 4 );
__builtin_memset( (FBSTRING*)((uint8*)THIS$1 + 4), 0, 12 );
__builtin_memset( (void**)((uint8*)THIS$1 + 16), 0, 4 );
label$2:;
label$3:;
}
static void _ZN3DOCaSERKS_( struct $3DOC* THIS$1, struct $3DOC* __FB_RHS__$1 )
{
label$4:;
*(__builtin_va_list**)THIS$1 = *(__builtin_va_list**)__FB_RHS__$1;
fb_StrAssign( (void*)((uint8*)THIS$1 + 4), -1, (void*)((uint8*)__FB_RHS__$1 + 4), -1, 0 );
*(void**)((uint8*)THIS$1 + 16) = *(void**)((uint8*)__FB_RHS__$1 + 16);
label$5:;
}
Note that __builtin_va_list** is nonsense, but it's of the same size as a Node ptr, so this code compiles correctly. However randomly a minority of the time instead of __builtin_va_list** it uses void**, which also compiles, or very rarely __builtin_va_list*, which cases gcc to throw "error: assignment to expression with array type".
I'm completely unfamiliar with fbc's AST code, but I had a look around since it might be hard for others to reproduce. In hCallFieldCtor called from inside hCallCtors from inside hAddCtorBody I noticed that the dtype seems to be garbage on this_. Maybe this dtype is not meant to be initialised but the problem is that it gets used although it shouldn't be because the root field (fld) doesn't have a valid dtype.
Breakpoint 1, HCALLFIELDCTOR (THIS_$1=0x7ffff796b220, FLD$1=0x7ffff7969690) at src/compiler/ast-node-proc.bas:958
958 ?"hCallFieldCtor ", *fld->id.name, iif(symbGetSubtype( fld )=NULL, "no subtype", *symbGetSubtype( fld )->id.name)
(gdb) n
hCallFieldCtor ROOT NODE
(gdb) p *THIS_$1
$20 = {CLASS = 1 [FB_SYMBCLASS_VAR], ATTRIB = 65664, PATTRIB = 0, STATS = 8, ID = {NAME = 0x7f5bbc "THIS", ALIAS = 0x0, MANGLED = 0x0}, TYP = 20 [FB_DATATYPE_VA_LIST], SUBTYPE = 0x7ffff7969540,
SCOPE = 1, MANGLING = 0, LGT = 16, OFS = 0, ....
(gdb) p *THIS_$1->SUBTYPE
$21 = {CLASS = 10 [FB_SYMBCLASS_STRUCT], ATTRIB = 0, PATTRIB = 0, STATS = 8388608, ID = {NAME = 0x7f5a0c "DOC", ALIAS = 0x0, MANGLED = 0x0}, TYP = 20 [FB_DATATYPE_VA_LIST], SUBTYPE = 0x0, ...
(gdb) p *FLD$1
$22 = {CLASS = 12 [FB_SYMBCLASS_FIELD], ATTRIB = 0, PATTRIB = 0, STATS = 0, ID = {NAME = 0x7f5a30 "ROOT", ALIAS = 0x0, MANGLED = 0x0}, TYP = 55 [FB_DATATYPE_FUNCTION + (1 shl FB_DT_PTRPOS)], SUBTYPE = 0x7ffff79692a0,
SCOPE = 0, MANGLING = 0, LGT = 4, OFS = 0, ...
(gdb) p *FLD$1->SUBTYPE
$24 = {CLASS = 14 [FB_SYMBCLASS_FWDREF], ATTRIB = 0, PATTRIB = 0, STATS = 0, ID = {NAME = 0x7f59c4 "NODE", ALIAS = 0x0, MANGLED = 0x0}, TYP = 2147483648 [FB_DATATYPE_INVALID], SUBTYPE = 0x0,
SCOPE = 0, MANGLING = 0, LGT = 0, OFS = 0,
Thank you for the excellent write up of the problem. I was able to reproduce the issue on x86_64 and find a cause.
Short answer: there was some left over and incorrectly used logic in fbc that tries to guess the va_list type. It was never removed as the cva_list code was developed and refactored. It was incorrectly replacing forward types with va_list types.
Longer answer:
The dtype value in FLD subtype is ok. The 2147483648 (aka &h80000000) value indicates that the type is invalid. And at the point where it is used, it's expected. When the parser sees 'END TYPE' for the 'TYPE Doc' structure it needs to build the default constructor, however, 'NODE' is not yet fully defined. So the INVALID data type makes sense. But fbc can still deal with it since it is a pointer only and default construction of a pointer type is known (set to NULL). Later and after 'TYPE NODE' is parsed, then the forward references are patched and the full type is known.
As a side note, for va_list types, fbc tracks the dtype as required for the size and type of the va_list type for a given platform. Bits stored in the "Mangle Modifier" field of the dtype indicate that the backend should replace the type with a builtin_va_list type during code generation.
The problem occurred that during the code generation fbc used bad logic to determine that the type should be replaced by the built in va_list type.
Fixed in fbc 1.10.0
commit: [61a0c5c3c6302fdee1d31d769ac56fd4dc2ba27f]
Related
Commit: [61a0c5]
Thanks for the fix and for the explanation! So the cause was deeper than I suspected, and I would have struggled to find it.