www.digitalmars.com         C & C++   DMDScript  

digitalmars.D.bugs - [Issue 13726] New: Build Phobos and Druntime with stack frames

https://issues.dlang.org/show_bug.cgi?id=13726

          Issue ID: 13726
           Summary: Build Phobos and Druntime with stack frames enabled
                    (-gs)
           Product: D
           Version: D2
          Hardware: All
                OS: All
            Status: NEW
          Severity: enhancement
          Priority: P1
         Component: Phobos
          Assignee: nobody puremagic.com
          Reporter: thecybershadow gmail.com

Background: enabling stack frames causes the compiler to emit a few extra
prologue/epilogue instructions for each function which save the stack pointer
right near the function return address. This creates a linked list, which, when
traversed, provides information for each function's address in the call stack
(and where within the function it invokes the next function), and the size of
its stack frame.

Stack frames are a good debugging aid and have a minimal impact on performance.
I suggest to build Phobos and Druntime with these enabled.

An example use case where stack frames are useful is debugging
InvalidMemoryOperation errors. These errors are currently difficult to debug.
Consider the following program:

//////////// test.d ////////////
import core.memory;

class C
{
    ~this() { new ubyte[1024]; }
}

void faulty()
{
    foreach (n; 0..1000)
        new C();
    GC.collect();
}

void main()
{
    faulty();
}
////////////////////////////////

This program allocates in a destructor, which is not allowed. When ran, it only
prints core.exception.InvalidMemoryOperationError (0), because a stack trace is
purposefully not allocated for memory operations (and even if it was, it would
still be incorrect, as seen below).

When the program is launched from a debugger, on Windows, the runtime will
disable its own exception handler, and the program will break on the point
where the InvalidMemoryOperationError is thrown. However, the stack trace will
look as follows:

	KernelBase.dll!_RaiseException 16()  + 0x58 bytes	
test.exe!_D2rt3deh9throwImplFC6ObjectZv() + 0x1a bytes test.exe!_onInvalidMemoryOperationError() + 0xc bytes test.exe!_gc_malloc() + 0x1e bytes test.exe!_D2gc3gcx3Gcx11fullcollectMFZk() + 0x617 bytes test.exe!_D2gc3gcx2GC11fullCollectMFZk() + 0x45 bytes Because _gc_malloc does not create a stack frame, the stack trace is corrupt - it incorrectly shows that Gcx.fullcollect invokes gc_malloc. The stack trace ends abruptly at GC.fullCollect, and does not contain any useful information on why the problem occurred. If Phobos and Druntime are rebuilt with -gs, we see the following stack trace instead: KernelBase.dll!_RaiseException 16() + 0x58 bytes test.exe!_D2rt9deh_win329throwImplFC6ObjectZv() + 0x23 bytes test.exe!__d_throwc() + 0xc bytes test.exe!_D2gc2gc2GC12mallocNoSyncMFNbkkKkxC8TypeInfoZPv() + 0x1f bytes test.exe!_D2gc2gc2GC6mallocMFNbkkPkxC8TypeInfoZPv() + 0x51 bytes test.exe!_gc_malloc() + 0x21 bytes test.exe!__d_newclass() + 0x66 bytes test.exe!_rt_finalize2() + 0xee bytes test.exe!_D2gc2gc3Gcx11fullcollectMFNbZk() + 0x8c8 bytes test.exe!_D2gc2gc2GC11fullCollectMFNbZk() + 0x1f bytes test.exe!_gc_collect() + 0x16 bytes test.exe!_D4core6memory2GC7collectFNbZv() + 0x8 bytes
	test.exe!test.faulty()  Line 13	C
test.exe!D main() Line 17 + 0x5 bytes C (rest omitted) We don't see the destructor in the stack trace because of issue 13723. With issue 13725 fixed, onInvalidMemoryOperationError can be breakpointed instead (this approach also requires stack frames for a useful stack trace). --
Nov 12 2014