문제

4 년 된 VC ++ 6.0 프로그램에 향상을 추가하려고합니다. 디버그 빌드는 명령 줄에서 실행되지만 디버거에서는 실행되지 않습니다. printf () 내부의 액세스 위반으로 충돌합니다. printf를 건너 뛰면 malloc () (fopen () 내에서 호출)에서 충돌하고 그것을 건너 뛸 수 없습니다.

이것은 디버거에서 실행할 수 없으며 기존 Printf 문에 의존하여 무슨 일이 일어나고 있는지 확인해야합니다. 이것은 분명히 훨씬 더 어렵게 만듭니다.

VC ++ 디버거 아래에서 실행될 때 Printf () 및 Malloc ()가 실패하는 이유는 무엇입니까? 나는이 낮은 수준의 물건을 잘 못합니다!

액세스 위반 후 통화 스택은 다음과 같습니다.

_heap_alloc_dbg(unsigned int 24, int 2, const char * 0x0046b3d8 `string', int 225) line 394 + 8 bytes
_nh_malloc_dbg(unsigned int 24, int 0, int 2, const char * 0x0046b3d8 `string', int 225) line 242 + 21 bytes
_malloc_dbg(unsigned int 24, int 2, const char * 0x0046b3d8 `string', int 225) line 163 + 27 bytes
_lock(int 2) line 225 + 19 bytes
_getstream() line 55 + 7 bytes
_fsopen(const char * 0x00468000 `string', const char * 0x00466280 `string', int 64) line 61 + 5 bytes
fopen(const char * 0x00468000 `string', const char * 0x00466280 `string') line 104 + 15 bytes
open_new_log(const char * 0x00468000 `string') line 66 + 14 bytes
log_open(const char * 0x00468000 `string', int 0) line 106 + 9 bytes
Xlog_open(const char * 0x00468000 `string', int 0) line 51 + 13 bytes
service_start(unsigned long 1, char * * 0x009a0e50) line 3152 + 12 bytes
service_init2(char * 0x00471fcc char * NTPROGRAM, char * 0x004723c4 char * NTSERVICE, char * 0x00466540 `string', unsigned long 1, char * * 0x009a0e50) line 508 + 13 bytes
service_init(char * 0x00471fcc char * NTPROGRAM, char * 0x004723c4 char * NTSERVICE, unsigned long 2, char * * 0x009a0e50) line 548
main(unsigned long 2, char * * 0x009a0e50) line 3131
mainCRTStartup() line 206 + 25 bytes
KERNEL32! 7c817067()

다음은 실패한 작업에 대한 디버그 분해를 다음과 같습니다.

0041EA7E   jmp         _heap_alloc_dbg+2B3h (0041eb23)
0041EA83   mov         edx,dword ptr [_lTotalAlloc (004b4294)]
0041EA89   add         edx,dword ptr [nSize]
0041EA8C   mov         dword ptr [_lTotalAlloc (004b4294)],edx
0041EA92   mov         eax,[_lCurAlloc (004b429c)]
0041EA97   add         eax,dword ptr [nSize]
0041EA9A   mov         [_lCurAlloc (004b429c)],eax
0041EA9F   mov         ecx,dword ptr [_lCurAlloc (004b429c)]
0041EAA5   cmp         ecx,dword ptr [_lMaxAlloc (004b42a0)]
0041EAAB   jbe         _heap_alloc_dbg+249h (0041eab9)
0041EAAD   mov         edx,dword ptr [_lCurAlloc (004b429c)]
0041EAB3   mov         dword ptr [_lMaxAlloc (004b42a0)],edx
0041EAB9   cmp         dword ptr [_pFirstBlock (004b4298)],0
0041EAC0   je          _heap_alloc_dbg+25Fh (0041eacf)
0041EAC2   mov         eax,[_pFirstBlock (004b4298)]
0041EAC7   mov         ecx,dword ptr [pHead]
0041EACA   mov         dword ptr [eax+4],ecx

다음은 fopen ()을 호출하고 malloc ()에서 실패한 소스입니다.

FILE *open_new_log( const char *logfile )
{
    FILE *fp;
    int retry = 0;

    while( ( fp = fopen( logfile, "w" ) ) == NULL && ++retry < 300 )
        Sleep( 1000 );

    return( fp );
}

내가 얻는 오류는

Unhandled exception inPISCOOP.exe: 0xC00000005: Access Violation

문안 인사,

--- Alistair.

도움이 되었습니까?

해결책

당신이 사용할 수있는 _CrtSetDbgFlag() 유용한 힙 디버깅 기술을 활성화합니다. 다른 사람이 있습니다 CRT 디버깅 기능 문제가있는 곳을 추적하는 데 도움이 될 수 있습니다.

다른 팁

디버거에서 실행되면 다른 힙이 사용됩니다. 이것은 디버그 힙. 이것은 디버거 외부에서 사용되는 힙과 다른 행동을 가지고 있으며, 이와 같은 문제를 해결하는 데 도움이됩니다.

Win32 "디버그 힙"은 VC ++ "디버그 힙"과는 다릅니다. 그러나 둘 다 동일한 일을하기위한 것입니다. 보다 이 기사 디버거 아래에서 앱을 실행할 때 동작의 차이를 설명합니다.

이 경우 힙 블록의 시작 또는 시작을 기록 하여이 기능을 호출하기 전에 힙을 손상 시켰을 것입니다.

가장 쉬운 접근 방식 (애플리케이션이 메모리를 너무 광범위하게 사용하지 않는 경우)은 전체 페이지 힙 확인을 활성화하는 것입니다 (메모리 페이지 후에 소위 가드 페이지를 배치 할 예정입니다. 부패가 발생하는 코드에 배치하십시오).

당신이 가지고 있다는 것을 감안할 때 Windows 디버깅 도구 편리한, 다음 gflags 명령을 실행하여 전체 페이지 힙을 구성하십시오.

gflags[.exe] /p /enable yourapp.exe /full

실행 가능 이름을 제공해야합니다 홀로 (즉, 경로 접두사없이!)
그런 다음 디버거 아래에서 실행하십시오. 힙을 손상시키려는 첫 번째 시도로 깨질 것입니다. 여기서 차이점은 힙 손상이 대부분 (아마도) 유효한 힙 작동이 유효 할 때 나중에 스스로를 나타내는 지연된 결함이라는 것입니다.

참고, 또한 :

gflags[.exe] /p /enable yourapp.exe /full /backwards

추가로 할당하기 전에 가드 페이지를 배치합니다.

/p 스위치만으로 실행하면 현재 유효한 힙 옵션이 표시됩니다.

힙 손상 버그가있을 수 있습니다. 응용 프로그램이 이전에 힙을 손상 시켰을 수 있습니다 open_new_log() 호출됩니다.

Jmattias가 옳다고 생각합니다. 문제의 근본 원인은 충돌하는 곳 이외의 다른 곳에있을 수 있습니다.

많은 것들이 힙 부패를 일으킬 수 있습니다.

  • 할당 된 메모리 블록의 끝 (또는 시작)을지나 쓰는 것.
  • 포인터를 두 번 제거하거나 할당되지 않은 포인터를 제거합니다.
  • 프로그램을 멀티 스레딩하고 단일 스레드 (스레드 안전하지 않음) RTL과 연결합니다.
  • 하나의 힙에서 메모리를 할당하고 다른 힙에 제거합니다.
  • 등 등,

Visual C ++를 사용하고 있으므로 디버그 힙의 _CRTSETDBGFLAG () 기능을 사용하여 오류 확인을 설정할 수 있습니다. Malloc 또는 무료 호출마다 힙의 무결성을 확인하도록 설정할 수 있습니다. 그것은 매우 느리게 실행되지만 버그가 어디에 있는지 정확히 찾아야합니다.

컴파일러 문서에서 _crtsetdbgflag를 검색하십시오.

나머지 애플리케이션과 다른 버전의 C ++ 런타임으로 컴파일 된 DLL이 있다고 의심합니다. 이로 인해 "주소에서의 메모리 XXX는 '읽기'/'작성된'"위반이 발생합니다.

라이센스 : CC-BY-SA ~와 함께 속성
제휴하지 않습니다 StackOverflow
scroll top