xMRi
xMRi

Reputation: 15355

Exzessive stack usage for simple function in debug build

I have simple class using a kind of ATL database access. All functions are defined in a header file.

The problematic functions all do the same. There are some macros in use. The generated code looks like this

void InitBindings()
{ 
     if (sName)   // Static global char*   
         m_sTableName = sName;  // Save into member
     { AddCol("Name", some_constant_data... _GetOleDBType(...), ...); };
     { AddCol("Name1", some_other_constant_data_GetOleDBType(...), ...); };
     ...      
}

AddCol returns a reference to a structure, but as you see it is ignored.

When I look into the assembler code where I have a function that uses 6 AddCol calls I can see that the function requires 2176 bytes of stack space. I have functions that requires 20kb and more. And in the debugger I can see that the stack isn't use at all. (All initialized to 0xCC and never touched)

See assembler code at the end.

The problem can be seen with VS-2015, and VS-2017.
Only in Debug mode.
In Release mode the function reserves no extra stack space at all.

The only rule I see is; more AddCol calls, will cause more stack to be reserved. I can see that approximativ 500bytes per AddCol call is reserved.

Again: The function returns no object, it returns a reference to the binding information.

I already used the following pragmas in front of the function (but inside the class definition in the header):

__pragma(runtime_checks("", off)) __pragma(optimize("ts", on)) __pragma(strict_gs_check(push, off))

But no avail. This pragmas should turn optimization on, switches off runtime checks and stack checks. How can I reduce this unneeded stack space that is allocated. In some cases I can see stack overflows in the debug version, when this functions are used. No problems in the release version.

; 325  : BIND_BEGIN(CMasterData, _T("tblMasterData"))

    push    ebp
    mov ebp, esp
    sub esp, 2176               ; 00000880H
    push    ebx
    push    esi
    push    edi
    mov DWORD PTR _this$[ebp], ecx
    mov eax, OFFSET ??_C@_1BM@GOLNKAI@?$AAt?$AAb?$AAl?$AAM?$AAa?$AAs?$AAt?$AAe?$AAr?$AAD?$AAa?$AAt?$AAa?$AA?$AA@
    test    eax, eax
    je  SHORT $LN2@InitBindin
    push    OFFSET ??_C@_1BM@GOLNKAI@?$AAt?$AAb?$AAl?$AAM?$AAa?$AAs?$AAt?$AAe?$AAr?$AAD?$AAa?$AAt?$AAa?$AA?$AA@
    mov ecx, DWORD PTR _this$[ebp]
    add ecx, 136                ; 00000088H
    call    DWORD PTR __imp_??4?$CStringT@_WV?$StrTraitMFC_DLL@_WV?$ChTraitsCRT@_W@ATL@@@@@ATL@@QAEAAV01@PB_W@Z
$LN2@InitBindin:

; 326  : // Columns:
; 327  :    B$C_IDENT   (_T("Id"),          m_lId);

    push    0
    push    0
    push    1
    push    4
    push    0
    call    ?_GetOleDBType@ATL@@YAGAAJ@Z        ; ATL::_GetOleDBType
    add esp, 4
    movzx   eax, ax
    push    eax
    push    0
    push    OFFSET ??_C@_15NCCOGFKM@?$AAI?$AAd?$AA?$AA@
    mov ecx, DWORD PTR _this$[ebp]
    call    ?AddCol@CDBAccess@DB@@QAEAAUS_BIND@2@PB_WKGKW4TYPE@32@0_N@Z ; DB::CDBAccess::AddCol

; 328  :    B$C         (_T("Name"),        m_szName);

    push    0
    push    0
    push    0
    push    122                 ; 0000007aH
    mov eax, 4
    push    eax
    call    ?_GetOleDBType@ATL@@YAGQA_W@Z       ; ATL::_GetOleDBType
    add esp, 4
    movzx   ecx, ax
    push    ecx
    push    4
    push    OFFSET ??_C@_19DINFBLAK@?$AAN?$AAa?$AAm?$AAe?$AA?$AA@
    mov ecx, DWORD PTR _this$[ebp]
    call    ?AddCol@CDBAccess@DB@@QAEAAUS_BIND@2@PB_WKGKW4TYPE@32@0_N@Z ; DB::CDBAccess::AddCol

; 329  :    B$C         (_T("Data"),        m_data);

    push    0
    push    0
    push    0
    push    4
    push    128                 ; 00000080H
    call    ?_GetOleDBType@ATL@@YAGAAVCComBSTR@1@@Z ; ATL::_GetOleDBType
    add esp, 4
    movzx   eax, ax
    push    eax
    push    128                 ; 00000080H
    push    OFFSET ??_C@_19IEEMEPMH@?$AAD?$AAa?$AAt?$AAa?$AA?$AA@
    mov ecx, DWORD PTR _this$[ebp]
    call    ?AddCol@CDBAccess@DB@@QAEAAUS_BIND@2@PB_WKGKW4TYPE@32@0_N@Z ; DB::CDBAccess::AddCol

Upvotes: 0

Views: 77

Answers (1)

xMRi
xMRi

Reputation: 15355

It is a compiler bug. Already known in connect.

EDIT The problem seams to be fixed in VS-2017 15.5.1

The problem has to do with a bug in the built in offsetof.

It is not possible for me to #undef _CRT_USE_BUILTIN_OFFSETOF as written in this case.

For me it only works to #undef offsetof and to use one of this:

#define myoffsetof1(s,m)    ((size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
#define myoffsetof2(s, m)   ((size_t)&(((s*)0)->m))

#undef offsetof
#define offsetof myoffsetof1

All ATL DB consumers are affected.

Here is a minimum repro, that shows the bug. Set a breakpint on the Init function. Look into the assembler code and wonder how much stack is used!

// StackUsage.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include <string>
#include <list>
#include <iostream>

using namespace std;

struct CRec
{
    char    t1[20];
    char    t2[20];
    char    t3[20];
    char    t4[20];
    char    t5[20];
    int     i1, i2, i3, i4, i5;
    GUID    g1, g2, g3, g4, g5;
    DBTIMESTAMP d1, d2, d3, d4, d5;
};

#define sizeofmember(s,m)   sizeof(reinterpret_cast<const s *>(0)->m)
#define typeofmember(c,m)   _GetOleDBType(((c*)0)->m)

#define myoffsetof1(s,m)    ((size_t)&reinterpret_cast<char const volatile&>((((s*)0)->m)))
#define myoffsetof2(s, m)   ((size_t)&(((s*)0)->m))

// Undef this lines to fix the bug
// #undef offsetof
// #define offsetof myoffsetof1

#define COL(n,v)    { AddCol(n,offsetof(CRec,v),typeofmember(CRec,v),sizeofmember(CRec,v));     }

class CFoo
{
public:
    CFoo()
    {
        Init();
    }

    void Init()
    {
        COL("t1", t1);
        COL("t2", t2);
        COL("t3", t3);
        COL("t4", t4);
        COL("t5", t5);
        COL("i1", i1);
        COL("i2", i2);
        COL("i3", i3);
        COL("i4", i4);
        COL("i5", i5);
        COL("g1", g1);
        COL("g2", g2);
        COL("g2", g3);
        COL("g2", g4);
        COL("g2", g5);
        COL("d1", d1);
        COL("d2", d2);
        COL("d2", d3);
        COL("d2", d4);
        COL("d2", d5);
    }
    void AddCol(PCSTR szName, ULONG nOffset, DBTYPE wType, ULONG nSize)
    {
        cout << szName << '\t' << nOffset << '\t' << wType << '\t' << nSize << endl;
    }
};



int main()
{
    CFoo foo;
    return 0;
}

Upvotes: 1

Related Questions