태그 보관물: c++

c++

유효성을위한 포인터 테스트 (C / C ++) 확인하는 것은 쉽지만 0x00001234와

주어진 포인터가 “유효”한지 (물론 프로그램 적으로) 결정하는 방법이 있습니까? NULL을 확인하는 것은 쉽지만 0x00001234와 같은 것은 어떻습니까? 이러한 종류의 포인터를 역 참조하려고하면 예외 / 충돌이 발생합니다.

크로스 플랫폼 방법이 선호되지만 플랫폼 별 (Windows 및 Linux 용)도 괜찮습니다.

설명을위한 업데이트 :
문제는 부실 / 해제 / 초기화되지 않은 포인터가 아닙니다. 대신 호출자 (문자열에 대한 포인터, 파일 핸들 등)로부터 포인터를 가져 오는 API를 구현하고 있습니다. 호출자는 (의도적으로 또는 실수로) 잘못된 값을 포인터로 보낼 수 있습니다. 충돌을 어떻게 방지합니까?



답변

설명을위한 업데이트 : 문제는 오래된 포인터, 해제되었거나 초기화되지 않은 포인터가 아닙니다. 대신 호출자 (문자열에 대한 포인터, 파일 핸들 등)로부터 포인터를 가져 오는 API를 구현하고 있습니다. 호출자는 (의도적으로 또는 실수로) 잘못된 값을 포인터로 보낼 수 있습니다. 충돌을 어떻게 방지합니까?

당신은 그 수표를 만들 수 없습니다. 포인터가 “유효”한지 확인할 수있는 방법은 없습니다. 사람들이 포인터를받는 함수를 사용할 때 그 사람들이 자신이 무엇을하는지 안다는 것을 믿어야합니다. 포인터 값으로 0x4211을 전달하면 0x4211 주소를 가리키는 것을 신뢰해야합니다. 그리고 그들이 “우연히”물체에 부딪힌 경우, 무서운 운영 체제 기능 (IsValidPtr 등)을 사용하더라도 여전히 버그에 빠질 것이며 빠르게 실패하지 않을 것입니다.

이런 종류의 신호를 보내기 위해 널 포인터를 사용하고 라이브러리 사용자에게 실수로 잘못된 포인터를 전달하는 경향이있는 경우 포인터를 사용해서는 안된다고 알리십시오.


답변

다음은 Linux에서 C 프로그램이 실행중인 메모리의 상태에 대해 성찰 할 수있는 세 가지 쉬운 방법과 질문이 일부 컨텍스트에서 적절한 정교한 답변을 갖는 이유입니다.

  1. getpagesize ()를 호출하고 포인터를 페이지 경계로 반올림 한 후 mincore ()를 호출하여 페이지가 유효한지 여부와 프로세스 작업 집합의 일부인지 확인할 수 있습니다. 여기에는 약간의 커널 리소스가 필요하므로 벤치마킹하고이 함수를 호출하는 것이 API에서 정말 적절한 지 결정해야합니다. API가 인터럽트를 처리하거나 직렬 포트에서 메모리로 읽는 경우 예측할 수없는 동작을 피하기 위해 이것을 호출하는 것이 적절합니다.
  2. 사용 가능한 / proc / self 디렉토리가 있는지 확인하기 위해 stat ()를 호출 한 후 / proc / self / maps를 열고 포인터가있는 영역에 대한 정보를 찾을 수 있습니다. 프로세스 정보 의사 파일 시스템 인 proc의 매뉴얼 페이지를 살펴보십시오. 분명히 이것은 상대적으로 비용이 많이 들지만 이진 검색을 사용하여 효율적으로 조회 할 수있는 배열로 구문 분석 결과를 캐싱하는 것을 피할 수 있습니다. / proc / self / smaps도 고려하십시오. API가 고성능 컴퓨팅을위한 것이라면 프로그램은 비 균일 메모리 아키텍처 인 numa의 man 페이지에 문서화 된 / proc / self / numa에 대해 알고 싶어 할 것입니다.
  3. get_mempolicy (MPOL_F_ADDR) 호출은 실행 스레드가 여러 개 있고 CPU 코어 및 소켓 리소스와 관련하여 비 균일 메모리에 대한 선호도를 갖도록 작업을 관리하는 고성능 컴퓨팅 API 작업에 적합합니다. 물론 이러한 API는 포인터가 유효한지 여부도 알려줍니다.

Microsoft Windows에는 Process Status API (NUMA API에도 있음)에 문서화 된 QueryWorkingSetEx 함수가 있습니다. 정교한 NUMA API 프로그래밍의 결과로서이 함수를 사용하면 간단한 “유효성 테스트 포인터 (C / C ++)”작업을 수행 할 수 있습니다. 따라서 최소 15 년 동안 사용되지 않을 가능성이 높습니다.


답변

호출자가 잘못된 포인터를 전송하여 발생하는 크래시를 방지하는 것은 찾기 어려운 조용한 버그를 만드는 좋은 방법입니다.

API를 사용하는 프로그래머가 코드를 숨기지 않고 충돌시켜 가짜라는 명확한 메시지를 얻는 것이 더 낫지 않습니까?


답변

Win32 / 64에는이를 수행하는 방법이 있습니다. 포인터 읽기를 시도하고 실패시 발생하는 결과 SEH 예외를 포착합니다. 던지지 않으면 유효한 포인터입니다.

이 방법의 문제는 포인터에서 데이터를 읽을 수 있는지 여부를 반환한다는 것입니다. 형식 안전성이나 기타 불변성을 보장하지 않습니다. 일반적으로이 방법은 “예, 지금 지나간 시간에 기억의 특정 위치를 읽을 수 있습니다”라고 말하는 것 외에는 거의 유용하지 않습니다.

간단히 말해서,하지 마십시오;)

Raymond Chen은이 주제에 대한 블로그 게시물 : http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx


답변

AFAIK 방법이 없습니다. 메모리를 해제 한 후 항상 포인터를 NULL로 설정하여 이러한 상황을 피해야합니다.


답변

에 살펴보세요 질문을. 또한 스마트 포인터를 살펴보십시오 .


답변

이 스레드의 답변에 대해서는 다음과 같습니다.

Windows의 경우 IsBadReadPtr (), IsBadWritePtr (), IsBadCodePtr (), IsBadStringPtr ().

내 조언은 그들로부터 멀리 떨어져 있다는 것입니다. 누군가 이미 이것을 게시했습니다 :
http://blogs.msdn.com/oldnewthing/archive/2007/06/25/3507294.aspx

같은 주제와 같은 저자 (제 생각에)에 대한 또 다른 게시물은 다음과 같습니다.
http://blogs.msdn.com/oldnewthing/archive/2006/09/27/773741.aspx ( “IsBadXxxPtr은 실제로 CrashProgramRandomly라고해야합니다. “).

API 사용자가 잘못된 데이터를 보내면 충돌이 발생하도록합니다. 문제가 전달 된 데이터가 나중에까지 사용되지 않고 원인을 찾기 어렵게 만드는 경우 문자열 등이 입력시 기록되는 디버그 모드를 추가합니다. 그들이 나쁘다면 그것은 명백 할 것입니다 (그리고 아마도 충돌 할 것입니다). 자주 발생하는 경우 API를 프로세스 외부로 이동하여 기본 프로세스 대신 API 프로세스를 중단시키는 것이 좋습니다.