2017-12-01 9 views
0

私は、ATLデータベースアクセスの種類を使用して簡単なクラスを持っています。 すべての関数は、ヘッダファイルで定義されています。デバッグビルドの単純な関数のための積極的なスタック使用

問題のある機能はすべて同じです。使用中のマクロがいくつかあります。この

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は構造体への参照を返すように生成されたコードは見えますが、あなたが見るように、それは無視されます。

6つのAddCol呼び出しを使用する関数を持つアセンブラコードを調べると、この関数には2176バイトのスタック領域が必要であることがわかります。私は20kb以上を必要とする機能を持っています。デバッガでは、スタックがまったく使用されていないことがわかります。 (すべて0xCCに初期化され、決して触れられません)

最後にアセンブラコードを参照してください。

この問題は、VS-2015およびVS-2017で確認できます。
デバッグモードのみ。
リリースモードでは、この機能は余分なスタックスペースをまったく予約しません。

唯一のルールは次のとおりです。より多くのAddCol呼び出しは、より多くのスタックを予約する原因になります。 AddColコールあたりのおよそ500バイトが予約されていることがわかります。

また、この関数はオブジェクトを返しません。バインディング情報への参照を返します。

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

しかし無駄:

Iは既に機能(ただし、ヘッダ内のクラス定義内)の前に以下のプラグマを使用しました。このプラグマは、最適化をオンにし、ランタイムチェックとスタックチェックをオフにする必要があります。割り当てられた不要なスタック領域をどのように減らすことができますか。場合によっては、この関数が使用されているときに、デバッグバージョンでスタックオーバーフローが発生することがあります。リリース版で問題はありません。

; 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 [email protected][email protected]@?$AAt?$AAb[email protected] 
    test eax, eax 
    je SHORT [email protected] 
    push OFFSET [email protected][email protected]@?$AAt?$AAb[email protected] 
    mov ecx, DWORD PTR _this$[ebp] 
    add ecx, 136    ; 00000088H 
    call DWORD PTR [email protected][email protected][email protected][email protected]@@@@@[email protected]@[email protected][email protected] 
[email protected]: 

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

    push 0 
    push 0 
    push 1 
    push 4 
    push 0 
    call [email protected]@@[email protected]  ; ATL::_GetOleDBType 
    add esp, 4 
    movzx eax, ax 
    push eax 
    push 0 
    push OFFSET [email protected][email protected][email protected] 
    mov ecx, DWORD PTR _this$[ebp] 
    call [email protected]@[email protected]@[email protected]@[email protected]@[email protected] ; 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 [email protected]@@[email protected]  ; ATL::_GetOleDBType 
    add esp, 4 
    movzx ecx, ax 
    push ecx 
    push 4 
    push OFFSET [email protected][email protected][email protected] 
    mov ecx, DWORD PTR _this$[ebp] 
    call [email protected]@[email protected]@[email protected]@[email protected]@[email protected] ; DB::CDBAccess::AddCol 

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

    push 0 
    push 0 
    push 0 
    push 4 
    push 128     ; 00000080H 
    call [email protected]@@[email protected]@@Z ; ATL::_GetOleDBType 
    add esp, 4 
    movzx eax, ax 
    push eax 
    push 128     ; 00000080H 
    push OFFSET [email protected][email protected][email protected] 
    mov ecx, DWORD PTR _this$[ebp] 
    call [email protected]@[email protected]@[email protected]@[email protected]@[email protected] ; DB::CDBAccess::AddCol 

答えて

1

これはコンパイラのバグです。すでにconnectで知られています。

EDIT問題はoffsetofは内蔵のバグに関係していVS-2017 15.5.1で修正される問題の縫い目

このケースでは、#undef _CRT_USE_BUILTIN_OFFSETOFには対応できません。

私にとっては唯一#undef offsetofに動作し、これのいずれかを使用する:

#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 

をすべてのATL DBの消費者が影響を受けます。

これは、バグを示す最小限のreproです。 Init関数にブレークポイントを設定します。アセンブラコードを見て、どのくらいのスタックが使われているのだろうか疑問に思ってください!

// 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; 
} 
関連する問題