• 카테고리

    질문 & 답변
  • 세부 분야

    프로그래밍 언어

  • 해결 여부

    해결됨

[(14. 구조체) - 9.구조체와 할당 메모리] - scanf()와 malloc()의 실행 순서에 따른 Heap Corruption Detected 오류

22.05.17 04:47 작성 조회수 769

0

[강의 화면 사이드에서 이 질문을 보시는 분들은 [여기 (클릭하면 현재 강의 화면 페이지에서 이동하므로 주의)]서 보시면 따배씨 질문 페이지에서 조금 더 큰 화면으로 보실 수 있습니다.]

안녕하세요. 해당 강의에서 연습 문제를 직접 만들어보던 중에 getintfo()함수에서 runtime error가 발생하여 질문 드립니다.

 scanf() code line이 malloc()보다 먼저 실행되어야, 동적 할당 메모리를 해제할 때, runtime error가 발생하지 않는데 왜 그런 것인지 궁금합니다.

 

우선 제가 처음에 만들고나서 runtime error 발생 지점을 확인하기 위해 만든 code는 아래와 같습니다.

getinfo() 함수 부분을 보시면, malloc()으로 동적 메모리 할당을 먼저 받은 다음에, scanf()함수로 char buffer[SLEN]에 입력을 받도록 했었습니다.

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>	// malloc(), free()
#include <string.h>	// strlen(), strcpy()

#define SLEN 81

struct namect {
	char* fname;	// Use malloc()
	char* lname;	// Use malloc()
	int letters;
};

void getinfo(struct namect*);		// Allocate memory
void makeinfo(struct namect*);
void showinfo(const struct namect*);
void cleanup(struct namect*);		// Free memory when it is done

int main()
{
	struct namect person;

	getinfo(&person);
	makeinfo(&person);
	showinfo(&person);
	cleanup(&person);

	return 0;
}

void getinfo(struct namect* ptr_nct)
{
	char buffer[SLEN] = { 0, };
	int flag = 0;

	ptr_nct->fname = (char*)malloc(strlen(buffer) + 1);	// Dynamic memory allocation for pointer 'fname'
	if (ptr_nct->fname != NULL)
	{
		printf("\nDynamic memory allocation for 'fname' is completed.\n");

		printf("Please enter your first name.\n>> ");
		flag = scanf("%[^\n]%*c", buffer);				// Taking string input into 'buffer'
		strcpy(ptr_nct->fname, buffer);					// Copy of string by pointer from 'buffer' to 'fname`
	}
	else
		printf("\nDynamic memory allocation for 'fname' is NOT completed.\n");


	ptr_nct->lname = (char*)malloc(strlen(buffer) + 1);	// Dynamic memory allocation for pointer 'lname'
	if (ptr_nct->lname != NULL)
	{
		printf("\nDynamic memory allocation for 'lname' is completed.\n");

		printf("Please enter your last name.\n>> ");
		flag = scanf("%[^\n]%*c", buffer);				// Taking string input into 'buffer'
		strcpy(ptr_nct->lname, buffer);					// Copy of string by pointer from 'buffer' to 'lname`
	}
	else
		printf("\nDynamic memory allocation for 'lname' is NOT completed.\n");
}

void makeinfo(struct namect* ptr_nct)
{
	ptr_nct->letters = strlen(ptr_nct->fname) + strlen(ptr_nct->lname);
}

void showinfo(const struct namect* ptr_nct)
{
	printf("%s %s, your name contains %d letters.\n", ptr_nct->fname, ptr_nct->lname, ptr_nct->letters);
}

void cleanup(struct namect* ptr_nct)
{
	// Deallocation of dynamically allocated memories
	printf("\nTime to free the allocated memory for 'fname'\n");
	free(ptr_nct->fname);	// Runtime error occurs in Visual Studio
	printf("Deallocation for 'fname' is completed!\n");

	printf("\nTime to free the allocated memory for 'lname'\n");
	free(ptr_nct->lname);	// Runtime error occurs in Visual Studio
	printf("Deallocation for 'lname' is completed!\n");
}

 

 

실행해보니, Heap Corruption Detected라는 error가 발생했습니다.

우선 어떤 code line에서 error가 발생한 것인지 확인해보기 위해, debugger로 line마다 확인해봤습니다.


cleanup()함수의 free()를 실행할 때, error가 발생하는 것을 확인했습니다.

그렇다면, 동적 메모리 할당은 정상적으로 수행되었는데, 해제를 할 때 문제가 발생한 것이라고 판단했습니다.

Google에 해당 error를 검색해보면, 이 Error가 발생하는 것에는 아래의 이유가 있다고 합니다.

  • 메모리 할당이 되지 않은 포인터(NULL Pointer)에 값을 넣음
  • 할당치를 초과하여 데이터가 입력됨

그런데, 제 경우 분명히 정상적으로 동적 할당을 먼저 받았으므로, fname과 lname을 입력할 수 있었습니다.

혹시라도 동적할당이 되지 않았는지, 체크하기 위해 동적 할당이 완료되었다는 메세지를 출력하도록 했습니다. 그리고 제가 입력한 string은 buffer + 1의 size인 82 bytes를 초과하지도 않았습니다.

도대체 왜 메모리 해제에서 문제가 발생하는지 고민하다가,

다른 compiler에서도 작동하는지 확인해보기 위해 GCC Compiler를 사용하도록 설정한 VS Code와, Online C Compiler에서 시도해봤습니다.


VS Code에서는 동적 할당 메모리가 해제되면서 프로그램이 정상적으로 종료됩니다.


Online C Compiler에서도 프로그램이 정상적으로 작동합니다.


하지만 Visual Studio에서 실행해보면, free()에서 더 이상 진행되지 않고, error가 발생한 것을 재차 확인했습니다.

 

그러다가buffer에 입력을 받는 scanf()의 code line이 malloc()보다 먼저 실행되도록 수정해봤습니다.

 

 

정상적으로 작동하는 것을 확인했습니다.

 

Q. 왜 scanf() code line이 malloc()보다 먼저 실행되어야, 동적 할당 메모리를 해제할 때, 문제가 없는 것인가요??

 

답변 1

답변을 작성해보세요.

0

swing-by님의 프로필

swing-by

질문자

2022.05.17

자문자답합니다!

 

malloc()을 할 때, strlen()함수의 연산 결과값 때문에 scanf()함수를 먼저 사용해야 했던 거네요 ;;

무의식적으로 sizeof()처럼 생각한 실수였어요...

 

위의 source code처럼 scanf()를 malloc()보다 나중에 call하게되면, strlen(buffer + 1) 의 연산 결과값은 1 byte가 나오게 됩니다. _msize()함수로 할당된 메모리의 크기를 구해보면 1이 나오는 것을 확인할 수 있습니다.

그러고나서 scanf() 함수로 string을 입력받게되면, strcpy()를 call했을 때, 할당받은 메모리를 초과해서 string을 복사하게 됩니다.

즉 할당 받은 heap memory의 size를 초과하게 됩니다.

그러므로 free()로 해제했을 때, 문제가 발생하는 것이었네요.

 

반면에, scanf()로 먼저 string을 입력받으면, strlen(buffer + 1)입력받은 문자의 수 + \0 만큼의 size를 연산 결과값으로 내놓게 되고, 이 만큼의 size로 heap에 확보됩니다.

이 경우에 _msize()함수로 할당된 메모리의 크기를 구해보면, 입력된 문자수+1 만큼으로 나오게 됩니다.

그러므로 strcpy()를 call했을 때, 할당 받은 메모리의 크기만큼 정상적인 copy가 됩니다.

그러므로 free()함수를 call했을 때, 정상적으로 해제가 됩니다.

참고로 _msize() 함수는 VS에서만 제공되는 함수이고 표준이 아니라고 합니다!

VS Code랑 online compiler에서는 왜 정상작동한건지.. 그건 사소한 의문으로 남아있네요.

강민철님의 프로필

강민철

2022.05.17

앗 답변 준비드리고 있었는데 이미 답을 구하셨군요. 다행입니다 :)

네 잘 알아주신 것처럼 _msize는 표준이 아닙니다.

VS Code랑 online compiler에서 정상작동한 이유와 관련해서는

찾아보고, 찾게 되면 이 곳 댓글에 달아두겠습니다.

 

 

 

swing-by님의 프로필

swing-by

질문자

2022.05.18

네, 댓글 감사합니다 !