2017-12-01 22 views
0

ATL 데이터베이스 액세스를 사용하는 간단한 클래스가 있습니다. 모든 기능은 헤더 파일에 정의되어 있습니다.디버그 빌드에서 간단한 함수에 대한 Exzessive 스택 사용

문제가있는 기능은 모두 동일합니다. 일부 매크로가 사용 중입니다. 이

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)) 

하지만 아무 소용이 :

은 이미 기능 (그러나 헤더의 클래스 정의 내부)의 앞에 다음 pragma를 사용했다. 이 pragma는 최적화를 실행하고 런타임 검사 및 스택 검사를 중단합니다. 어떻게 할당 된이 불필요한 스택 공간을 줄일 수 있습니다. 어떤 경우에는이 함수가 사용될 때 디버그 버전에서 스택 오버 플로우를 볼 수 있습니다. 릴리스 버전에는 문제가 없습니다.

; 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 문제 솔기 VS-2017 문제는 offsetof를 내장에서이 문제를 함께 할 수있다 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 소비자가 영향을받습니다.

다음은 버그를 보여주는 최소 재현입니다. Init 함수에 breakpint를 설정하십시오. 어셈블러 코드를보고 얼마나 많은 스택이 사용되는지 궁금해하십시오!

// 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; 
}