ldc icon indicating copy to clipboard operation
ldc copied to clipboard

Stub TypeInfo with changed member types silently leads to infinite codegen loop

Open JinShil opened this issue 11 years ago • 5 comments

Here's my reduced test case:

// dmain.d
module dmain;

private extern(C) void _start()
{ }
// object.d
module object;

alias size_t    = typeof(int.sizeof);
alias ptrdiff_t = typeof(cast(void*)0 - cast(void*)0);
alias string    = immutable(char)[];

extern(C) __gshared void* _Dmodule_ref;

struct ModuleInfo
{ 
    uint _flags;
    uint _index;
}

class Object
{ }

class TypeInfo 
{ }

class TypeInfo_Struct : TypeInfo 
{
    ubyte[120] ignore;
}

class TypeInfo_Class : TypeInfo 
{
    ubyte[125] ignore;
    ubyte[1] ignore1;
    ubyte[1] ignore2;
    ubyte[1] ignore3;
    ubyte[1] ignore4;
    ubyte[1] ignore5;
    ubyte[1] ignore6;
    ubyte[1] ignore7;
    ubyte[1] ignore8;
    ubyte[1] ignore9;
    ubyte[1] ignore10;
    ubyte[1] ignore11;
}

class TypeInfo_AssociativeArray : TypeInfo
{
    ubyte[16] ignore;
}

compile with ldc2 -c -singleobj -defaultlib= dmain.d object.d -of=test. This will never exit and produce an ever-growing .o file.

output of ls -al

-rw-r--r--  1 mike users 286892032 Nov  9 12:54 test.o

Tested with LDC 0.14.0 and 0.15.0 alpha1 in Arch Linux 64.

JinShil avatar Nov 09 '14 03:11 JinShil

I'm still not sure what's causing this, but I compiled with -v and -v-cg and it hangs here:

...
codegen: main (app/main.d)
codegen: __entrypoint (__entrypoint.d)

JinShil avatar Nov 30 '14 03:11 JinShil

I did a little more debugging to find out what's going on here. It seems to be hanging in toobj.cpp:94, Passes.run(m) on the first module. It doesn't seem to matter which module it is.

This is getting beyond me now, as that appears to be LLVM code. Anyway, I hope this information is useful for someone who wishes to look a little deeper into this.

JinShil avatar Nov 30 '14 05:11 JinShil

@JinShil - Mike, I think this is because TypeInfo_Class initializer generated by gen/classes.cpp is hardcoded to types specified in regular druntime/src/object_.d. Since TypeInfo_Class in above object.d just tries to match sizeof, this leads to a type mismatch in IR. It can be seen by compiling to IR and then using llc.

$ ldc2 -c -singleobj -defaultlib= dmain.d object.d -of=test -output-ll
$ llc test.ll
llc: test.ll:38:53: error: element 2 of struct initializer doesn't match struct element type
@_D6Object7__ClassZ = global %object.TypeInfo_Class { %object.TypeInfo_Class.__vtbl* @_D14TypeInfo_Class6__vtblZ, i8* null, { i64, i8* } { i64 16, i8* bitcast (%object.Object_init* @_D6Object6__initZ to i8*) }, { i64, i8* } { i64 13, i8* getelementptr inbounds ([14 x i8]* @.str1, i32 0, i32 0) }, { i64, i8** } { i64 1, i8** bitcast (%object.Object.__vtbl* @_D6Object6__vtblZ to i8**) }, [1 x i8] zeroinitializer, %object.TypeInfo_Class* null, i8* null, [1 x i8] zeroinitializer, i32 34, i8* null, [1 x i8] zeroinitializer, [1 x i8] zeroinitializer, i8* null }

Not sure why this LLVM error doesn't show up when going directly to object code, perhaps assertions need to be enabled in LLVM.

Anyway, if I take your example object.d above but change just declaration of TypeInfo_Class to following, then it all compiles.

class TypeInfo_Class : TypeInfo
{
    byte[]      init;
    string      name;
    void*[]     vtbl;
    void*[] interfaces;
    TypeInfo_Class   base;
    void*       destructor;
    void function(Object) classInvariant;
    uint m_flags;
    void*       deallocator;
    void*[] m_offTi;
    void function(Object) defaultConstructor;   // default Constructor
    immutable(void)* m_RTInfo;        // data for precise GC
}

smolt avatar May 05 '15 06:05 smolt

We should see if we can't introduce a proper frontend error/ICE for such mismatches, no matter what solution we end up with for Mike's use case.

dnadlinger avatar May 05 '15 18:05 dnadlinger

AFAIK, we check the number of fields, but not their type.

kinke avatar Jun 27 '21 01:06 kinke