마이크로소프트 공식 문서에 따르면 해당 오류는 다음으로 정의된다.
_CrtIsValidHeapPointer
=> 특정 포인터가 어떤 C 런타임 라이브러리(반드시 호출자의 CRT일 필요는 없다)에 의해 할당된 힙에 존재하는지를 확인한다.
도통 무슨 말인지 모르겠지만 런타임 라이브러리 정도는 알아둘 필요가 있다.
C 런타임 라이브러리에서 런타임 라이브러리는 컴파일러가 관리하는 프로그램의 실행에 필요한 함수 기능 등 여러가지 요소들을 말한다. 그리고 여기서는 언어가 C 계열이므로 C 런타임 라이브러리 줄여서 CRT 라고 한다.
런타임 라이브러리는 프로그램이 실행되면 메모리에 적재된다.
런타임 라이브러리를 사용 하는 이유는
1. 자주 사용되는 기능들(printf, scanf 등)을 따로 저장해서 그만큼 프로그램의 크기를 줄일 수 있고
2. 런타임에만 사용할 수 있는 기능(일부 논리 오류, 배열 범위 검사, 동적 유형 검사, 디버깅 등)을 구현하려는 목적도 있다.
https://stackoverflow.com/questions/2766233/what-is-the-c-runtime-library
그리고 이 오류 역시 런타임에만 발견된다고 보면 된다.
오류가 발생 하는 경우들을 살펴보자.
1. 리터럴(데이터 영역)과 스택 영역의 값을 해제하려는 경우
#include <bits/stdc++.h>
int main() {
const char* c = "kevin";
std::string str = "brown";
std::string* ps = &str;
// delete c; // Error: CrtIsValidHeapPointer(block)
//delete ps; // Error: CrtIsValidHeapPointer(block)
return 0;
}
c는 "kevin"이라는 리터럴의 주소를 가진 변수이다. 리터럴은 데이터 영역에 있으며 따라서 delete c 라는 코드는 리터럴의 메모리를 반환한다는 얘기인데 delete 는 힙 영역의 변수만 컨트롤할 수 있으므로 에러가 발생한다.
(프로그래머는 힙 영역을 제외한 메모리 공간을 관리할 수 없다.)
마찬가지로 str은 "brown"이라는 리터럴의 주소를 가진다. 하지만 str 자체는 스택 영역에 정적 할당된 변수이다. 그리고 그 변수를 포인터 변수인 ps가 가리키고 있다.
따라서 ps의 메모리를 해제하려는 것은 곧 스택 영역에 할당된 str 변수를 해제하는 것이므로 마찬가지로 에러가 발생한다.
2. 잘못된 주소를 해제하려는 경우
#include <bits/stdc++.h>
int main() {
int* n = new int(8);
n++;
delete n;
return 0;
}
포인터 변수 n에 8이라는 리터럴을 동적 할당했다.
n의 주소 값을 한 칸 뒤로 증가시켰고 잘못된 주소를 참조하고 있으므로 이를 해제하면 오류가 발생한다.
이 경우에는 HEAP CORRUPTION DETECTED 이라는 에러도 같이 발생한다.
#include <bits/stdc++.h>
int main() {
int* n = new int(8);
delete n;
delete n;
return 0;
}
이미 메모리가 해제된 변수를 또 해제하려는 경우에도 오류가 발생할 수 있다. (이 경우 n을 댕글링 포인터라고 한다.)
하지만 컴파일러에 따라 오류로 처리하지 않기도 한다.
3. 다중 런타임 환경
마이크로소프트 CRT 공식 문서에 따르면 하나의 프로그램을 실행하는 데 여러 런타임을 포함시킬 수 있다.
문제는 각 런타임마다 고유한 힙 영역을 가질 수 있다는 데에서 발생한다.
보통 프로그래머가 새로운 런타임 라이브러리를 추가할 때는 dll(동적 라이브러리)을 사용한다.
A.dll 의 힙 영역에 할당된 변수를 B.dll 에서 해제하려는 경우 위 오류가 발생한다.
내용 참조)
'Programming Languages > C++ Study' 카테고리의 다른 글
C++ MultiThread) std::atomic과 SpinLock (4) | 2024.03.06 |
---|---|
C++) 범위 기반 for문(Range based for loop)과 사용 조건 (0) | 2024.01.26 |
C++) RTTI와 Dynamic Cast (1) | 2024.01.25 |
C++) *(Asterisk, 별표) 연산자 활용하기 (0) | 2024.01.24 |