행글링 포인터

Dangling pointer
행글링 포인터

컴퓨터 프로그래밍에서 행글링 포인터와 와일드 포인터는 적절한 유형의 유효한 객체를 가리키지 않는 포인터입니다.이것들은 메모리 안전 위반의 특수한 경우입니다.보다 일반적으로, 행잉 레퍼런스와일드 레퍼런스는, 유효한 수신처로 해결되지 않는 레퍼런스입니다.

덩글링 포인터는 오브젝트 파괴 중에 포인터 값을 변경하지 않고 착신 참조를 가진 오브젝트가 삭제 또는 할당 해제될 때 발생합니다.이 경우 포인터는 할당 해제된 메모리의 메모리 위치를 계속 가리킵니다.시스템은 이전에 빈 메모리를 재할당할 수 있으며, 프로그램이 (지금) 행잉 포인터를 비활성화하면 메모리에 전혀 다른 데이터가 포함되어 있을 수 있기 때문에 예측할 수 없는 동작이 발생할 수 있습니다.프로그램이 달랑거리는 포인터로 참조되는 메모리에 쓸 경우 관련 없는 데이터가 소리 없이 손상되어 발견이 매우 어려울 수 있는 미묘한 버그가 발생할 수 있습니다.메모리가 다른 프로세스에 재할당된 경우, 덩글링 포인터를 참조 해제하려고 하면 세그먼트화 장애(UNIX, Linux) 또는 일반 보호 장애(Windows)가 발생할 수 있습니다.프로그램이 커널의 메모리 할당자에 의해 사용되는 장부 데이터를 덮어쓸 수 있는 충분한 권한을 가지고 있는 경우, 파손으로 인해 시스템이 불안정해질 수 있습니다.가비지 컬렉션이 있는 오브젝트 지향 언어에서는 도달할 수 없는 오브젝트만 파기함으로써 행잉 참조가 방지됩니다.즉, 수신 포인터는 없습니다.이는 트레이스 또는 참조 카운트를 통해 보증됩니다.그러나 최종자는 오브젝트에 대한 새로운 참조를 작성할 수 있으며, 오브젝트 부활이 요구되어 참조가 매달리는 것을 방지할 수 있습니다.

와일드 포인터는 일부 프로그래밍 언어에서 가능한 알려진 상태로 초기화하기 전에 포인터를 사용할 때 발생합니다.이들은 행글링 포인터와 같은 불규칙한 동작을 보이지만 많은 컴파일러가 초기화 [1]전에 선언된 변수에 액세스하면 컴파일 시 경고를 발생시키기 때문에 검출되지 않을 가능성이 낮습니다.

포인터가 매달리는 원인

많은 언어(예를 들어 C 프로그래밍 언어)에서 오브젝트를 메모리에서 명시적으로 삭제하거나 반환 시 스택프레임을 파괴해도 연관된 포인터는 변경되지 않습니다.포인터는, 다른 용도로 사용할 수 있게 되어도, 메모리내의 같은 장소를 가리키고 있습니다.

간단한 예를 다음에 나타냅니다.

{     *에서 = 특수한 순서;    /* ... */    {         c;        에서 = &c;    }       /* c가 범위를 벗어납니다*/      /* dp는 매달림 포인터가 되었습니다*/ } 

운영체제가 늘 포인터에 대한 런타임 참조를 검출할 수 있는 경우 위의 해결책은 내부 블록이 종료되기 직전에0(늘)을 dp에 할당하는 것입니다.또 다른 해결책은 추가 초기화 없이 dp를 다시 사용하지 않도록 하는 것입니다.

또 다른 포인터의 빈번한 소스는 혼재된 조합입니다.malloc()그리고.free()라이브러리 콜: 포인터가 가리키는 메모리 블록이 해방되면 포인터가 행업합니다.위의 예와 마찬가지로 이 문제를 회피하는 한 가지 방법은 다음과 같이 참조를 해제한 후 포인터를 null로 리셋하는 것입니다.

#실패하다 <stdlib.h>  무효 기능하다() {      *dp = 마로크(A_CONST);     /* ... */     공짜(dp);         /* dp가 매달리는 포인터가 되었습니다*/     dp = 특수한 순서;        /* dp가 행업하지 않게 되었습니다*/     /* ... */ } 

스택에 할당되어 있는 로컬 변수의 주소를 반환하는 것은 매우 일반적인 실수입니다.호출된 함수가 반환되면 이들 변수의 공간은 할당 해제되어 기술적으로 "쓰레기 값"이 됩니다.

인트 *기능하다(무효) {     인트 숫자 = 1234;     /* ... */     돌아가다 &숫자; } 

포인터에서 읽기를 시도해도 호출 후 한동안 올바른 값(1234)이 반환될 수 있습니다.func단, 그 이후에 호출된 함수는 에 할당된 스택스토리지를 덮어쓸 수 있습니다.num다른 값을 지정하면 포인터가 올바르게 작동하지 않게 됩니다.에 대한 포인터가 있는 경우num반환해야 합니다.num이 함수의 범위를 넘어야 합니다.이것은 다음과 같이 선언될 가능성이 있습니다.static.

매달린 참조가 없는 수동 할당 해제

Antoni Kreczmar [pl](1945-1996)는 매달린 참조 [2]현상이 없는 완전한 객체 관리 시스템을 만들었습니다.비슷한 접근방식은 Locks-and-keys라는 이름으로 Fisher와 LeBlanc에 의해 제안되었다.

와일드 포인터의 원인

와일드 포인터는 처음 사용하기 전에 필요한 초기화를 생략함으로써 생성됩니다.따라서 엄밀히 말하면 초기화를 강제하지 않는 프로그래밍 언어의 모든 포인터는 와일드 포인터로 시작합니다.

이 문제는 대부분 초기화를 생략하지 않고 건너뛰기 때문에 발생합니다.대부분의 컴파일러는 이에 대해 경고할 수 있습니다.

인트 f(인트 i) {      *에서;    /* dp는 와일드 포인터 */     정적인  *scp;  /* scp는 와일드 포인터가 아닙니다. * 정적 변수는 0으로 초기화됩니다. * 시작 시점의 가치를 유지하고 * 그 후 마지막 통화. * 이 기능을 사용하면 좋지 않은 것으로 간주될 수 있습니다. * 코멘트가 없는 경우 스타일 */ } 

포인터가 매달려 있는 보안 구멍

버퍼 오버플로우 버그와 마찬가지로 행글링/와일드포인터 버그가 보안의 구멍이 되는 경우가 많습니다.예를 들어 포인터가 가상 함수 호출에 사용되는 경우 vtable 포인터가 덮어쓰기되어 다른 주소(아마도 취약성 코드를 가리키고 있음)가 호출될 수 있습니다.또는 포인터가 메모리에 쓰기에 사용되는 경우 다른 데이터 구조가 손상될 수 있습니다.포인터가 행잉된 후에만 메모리를 읽어도 정보 유출(해당된 다음 구조에 대상 데이터가 배치되는 경우) 또는 권한 상승(현재 유효하지 않은 메모리가 보안 검사에 사용되는 경우)이 발생할 수 있습니다.새로운 메모리 청크를 할당하지 않고 해방된 후 행글링 포인터를 사용하는 경우 이를 "사용 후 빈"[4] 취약성이라고 합니다.예를 들어 CVE-2014-1776은 Microsoft Internet Explorer 6 ~ 11의[5] 사용 후 취약성으로, 고급 영구 [6]위협제로 데이 공격에 의해 사용됩니다.

행잉 포인터 오류 방지

C에서 가장 간단한 기술은 다른 버전의 C를 구현하는 것입니다.free()포인터의 리셋을 보증하는 (또는 유사) 기능.그러나 이 기술은 포인터의 복사본을 포함할 수 있는 다른 포인터 변수를 지우지 않습니다.

#실패하다 <고객명>님.h> #실패하다 <stdlib.h>  /* 'free()' 대체 버전 */ 정적인 무효 세이프프리(무효 **pp) {     /* 디버깅모드에서 pp가 NULL이면 중단*/     주장하다(pp);     /* free(NULL)는 정상적으로 동작하므로 디버깅모드에서의 아사트 이외에는 체크가 필요 없습니다*/     공짜(*pp);                  /* 청크의 할당을 해제합니다.무료(NULL)는 유효합니다*/     *pp = 특수한 순서;                 /* 원래 포인터를 리셋 */ }  인트 f(인트 i) {      *p = 특수한 순서, *p2;     p = 마로크(1000);    /* 청크를 가져옵니다*/     p2 = p;              /* 포인터를 복사합니다*/     /* 여기에 청크를 사용 */     세이프프리((무효 **)&p);       /* 안전 해제, p2 변수에는 영향을 주지 않음 */     세이프프리((무효 **)&p);       /* 이 두 번째 콜은 p가 NULL로 리셋되므로 실패하지 않습니다*/      c = *p2;       /* p2는 여전히 덩글링 포인터이므로 이는 정의되지 않은 동작입니다.*/     돌아가다 i + c; } 

대체 버전은 호출하기 전에 빈 포인터의 유효성을 보장하기 위해 사용될 수 있습니다.malloc():

    세이프프리(&p);        /* 청크가 출시되었는지 잘 모르겠습니다 */     p = 마로크(1000);    /* 지금 당장 할당 */ 

이러한 용도를 통해 마스킹할 수 있습니다.#define유용한 매크로를 구축하기 위한 지침(일반적인 것)#define XFREE(ptr) safefree((void **)&(ptr)))를 작성하거나 도구 라이브러리에 별도로 삽입할 수 있습니다.모든 경우에 이 기술을 사용하는 프로그래머는 안전한 버전을 사용해야 합니다.free()사용할 수 있습니다.그렇게 하지 않으면 다시 문제가 발생합니다.또한 이 솔루션은 단일 프로그램 또는 프로젝트의 범위로 한정되므로 적절하게 문서화해야 합니다.

보다 구조화된 솔루션 중, C++에서 포인터가 매달리는 것을 피하기 위한 인기 있는 기술은 스마트 포인터를 사용하는 것이다.스마트 포인터는 일반적으로 참조 카운트를 사용하여 개체를 회수합니다.다른 기술로는 묘석법과 자물쇠 [3]달기법이 있다.

또 다른 방법은 Bohm 가비지 컬렉터를 사용하는 것입니다.이는 C 및 C++의 표준 메모리 할당 기능을 가비지 컬렉터로 대체하는 보수적인 가비지 컬렉터입니다.이 방법에서는 빈 공간을 사용하지 않도록 설정하고 가비지 수집을 통해 개체를 회수하여 매달림 포인터 오류를 완전히 제거합니다.

Java와 같은 언어에서는 메모리 할당을 명시적으로 해제하는 메커니즘이 없기 때문에 덩글링 포인터가 발생할 수 없습니다.대신 가비지 컬렉터는 메모리 할당을 해제할 수 있지만 참조에서 개체에 더 이상 연결할 수 없는 경우에만 해당됩니다.

Rust라는 언어에서 유형 시스템은 변수 수명 및 리소스 획득을 포함하도록 확장되었습니다.언어의 기능을 무효로 하지 않는 한, 행글링 포인터는 컴파일시에 검출되어 프로그래밍 에러로서 보고됩니다.

매달림 포인터 검출

덩글링 포인터 오류를 노출하기 위해 일반적인 프로그래밍 기법 중 하나는 포인터가 가리키는 스토리지가 해제되면 포인터 또는 비활성 주소로 포인터를 설정하는 것입니다.null 포인터가 참조되지 않은 경우(대부분의 언어에서) 프로그램은 즉시 종료됩니다.데이터 손상이나 예측할 수 없는 동작이 발생할 가능성은 없습니다.이를 통해 기본 프로그래밍 오류를 더 쉽게 찾고 해결할 수 있습니다.이 기술은 포인터의 복사본이 여러 개 있는 경우에는 도움이 되지 않습니다.

일부 디버거는 해방된 데이터를 다음과 같은 특정 패턴으로 자동으로 덮어쓰고 파기합니다.0xDEADBEEF(예를 들어 Microsoft의 Visual C/C++ 디버거는0xCC,0xCD또는0xDD해제된[7] 내용에 따라 달라집니다).이것은 보통 데이터를 쓸모없게 하고 매우 두드러지게 함으로써 데이터가 재사용되는 것을 막습니다(패턴이 프로그래머에게 메모리가 이미 해방되었음을 보여주는 역할을 합니다).

Polyspace, TotalView, Valgrind, Mudflap,[8] AddressSanitizer 등의 툴이나 LLVM 기반[9] 툴을 사용하여 덩글링 포인터의 사용을 검출할 수도 있습니다.

다른 도구(SoftBound, Insure++CheckPointer)는 소스 코드를 계측하여 포인터의 정당한 값("메타데이터")을 수집 및 추적하고 각 포인터 액세스를 메타데이터와 비교하여 확인합니다.

또 다른 전략은 작은 클래스 세트를 의심하는 경우 모든 멤버 함수를 일시적으로 가상화하는 것입니다.클래스 인스턴스가 파기/자유된 후 Virtual Method Table로의 포인터는 다음과 같이 설정됩니다.NULL멤버 함수에 대한 호출은 프로그램을 크래시하고 디버거에 의심스러운 코드를 표시합니다.

「 」를 참조해 주세요.

레퍼런스

  1. ^ "Warning Options - Using the GNU Compiler Collection (GCC)".
  2. ^ Gianna Cioni, Antoni Kreczmar, 달링 참조 없이 프로그래밍된 할당 해제, 정보처리 서신, v. 18, 1984, 페이지 179-185
  3. ^ a b C.N. Fisher, R.J. Leblanc, Pascal, IEEE Trans에서의 런타임 진단 구현.소프트, 영어, 6(4):313-319, 1980
  4. ^ Dalci, Eric; anonymous author; CWE Content Team (May 11, 2012). "CWE-416: Use After Free". Common Weakness Enumeration. Mitre Corporation. Retrieved April 28, 2014. {{cite web}}: author2=범용명(도움말)이 있습니다.
  5. ^ "CVE-2014-1776". Common Vulnerabilities and Exposures (CVE). 2014-01-29. Archived from the original on 2017-04-30. Retrieved 2017-05-16.
  6. ^ Chen, Xiaobo; Caselden, Dan; Scott, Mike (April 26, 2014). "New Zero-Day Exploit targeting Internet Explorer Versions 9 through 11 Identified in Targeted Attacks". FireEye Blog. FireEye. Retrieved April 28, 2014.
  7. ^ Visual C++ 6.0 메모리 충전 패턴
  8. ^ Mudflap 포인터의 디버깅
  9. ^ Durjati, D. 및 Adve, V. 프로덕션 서버에서 사용되는 모든 당글링 포인터를 효율적으로 검출