2017-03-25 3 views
1

내가 다음 메모리 위치 안에 무엇인지보기 위해 증가하는 잘못된 포인터가 있다고 가정합니다. 내 코드는 오류나 문제없이 잘 작동합니다. 나는이 메모리 위치의 내용을 출력한다. 내 화면에 출력을 볼 수 있습니다. 이러한 메모리 위치 중 일부는 0 값을 가지며, 다른 값은 패턴에 정렬 된 것처럼 보이는 큰 음수 또는 양수를 포함합니다. 그러나 이러한 메모리 위치의 내용을 변경하거나 덮어 쓰려고하면 어떻게됩니까? 그들은 무엇을 대표합니까? 어떤 종류의 데이터가이 메모리 위치에 저장 될 수 있으며 이러한 메모리 위치가 충분히 변경되면 운영 체제를 중단 할 수 있습니까?C++에서 범위를 벗어난 포인터의 역 참조를 변경하는 것이 안전합니까?

#include <iostream> 
    using std::cout; 
    using std::endl; 
    int main() { 
    int num1 = 5; 
    int* bad_ptr = &num1; 
    cout << "Address of num1: " << &num1 << endl; 
    cout << "Dereference bad pointer: " << *bad_ptr << endl; 

    // The bad pointer acesses 500 memory addresses 
    for (int i = 0; i < 500; i++) { 
     bad_ptr++; 
     cout << "Dereference bad pointer: " << *bad_ptr << endl; 
     // What if I try to change it? 
     // *bad_ptr = 1; 
    } 
    return 0; 
    } 
+4

정의되지 않은 동작은 정의되지 않았습니다. 이 특정 시간에 특정 컴파일러 버전이 특정 최적화 수준 및 특정 OS 버전의 플래그로 무엇인지 파악할 수 있지만 의미있는 것은 배울 수 없습니다. – nwp

+0

"운영 체제, 프로그램 유형 및 하드웨어 아키텍처에 따라 이러한 메모리 위치가 충분히 변경되는 경우 운영 체제를 중단 할 수 있습니다. 최신 CPU는 하나의 프로세스가 다른 프로세스를 손상시키지 않도록 보호하며 운영 체제는 아마도 이점을 얻습니다. 커널 드라이버에서 이것을 수행하면 좋지 않을 수 있습니다. OS를 응용 프로그램과 분리하지 않고 단순한 메모리 관리 모델을 갖춘 마이크로 컨트롤러에서이를 수행하십시오. 그렇다면 OS가 밟힐 수 있습니다. – user4581301

+0

컴파일러는 정의되지 않은 동작이 유효한 프로그램에서 발생하지 않는다고 가정합니다. 따라서 프로그램에서 멀리 떨어져있는 부분을 최적화 할 수 있습니다. 아니면 그렇지 않을 수도 있습니다. 또는 실제로 메모리 위치에 저장된 값이 아닐 수도 있습니다. 0이 인쇄 될 수도 있습니다. – user463035818

답변

5

TL; DR이 정의되지 않은 동작하고 수행 할 수없는 것이다.

더 실용적인 대답은 주소에 크게 의존한다는 것입니다. 이 예에서 int의 주소는 stack에 있습니다. 포인터를 계속 늘리면 기본적으로 스택 메모리가 보입니다. malloc()에 대한 호출에서 포인터를 사용하여 동일한 작업을 수행한다면 힙 전체에서 메모리가 보입니다.

당신이 커널 공간에 있지 않으면 대답은 아니오, 값을 변경하여 OS의 안정성에 영향을 미치지에 대한 귀하의 질문. 그러나 커널 공간에서 실행중인 드라이버에서이 작업을 수행하면 OS가 손상 될 수 있습니다.

귀하의 질문에 많은 미묘한 차이가 있기 때문에이 답변은 철저하지 않습니다. 따라서 TL (DR)을 참조하십시오. 기본적인 컴퓨터 아키텍처에 대한 검색 및 독해를 제안합니다.

0

잘못된 포인터를 참조하는 것은 정의되지 않습니다. 그러나, 당신이하고있는 일은 우연히 실수를 일으키지 않을 것입니다.

대부분의 C++ 구현에서 num1은 스택에 할당됩니다. 대부분의 컴퓨터 시스템에서 스택은 하위 주소로 증가합니다. 포인터를 증가 시키면 호출 함수의 스택 프레임으로 스택 위로 이동합니다 (즉, main보다 먼저 초기화하는 모든 함수).

당신은 결국 당신은 문제를 볼 충분한 루프 제한이 큰 한 경우.

그러나 이러한 메모리 위치의 내용을 변경하거나 덮어 쓰려고하면 어떻게됩니까? 그들은 무엇을 대표합니까? 어떤 종류의 데이터가이 메모리 위치에 저장 될 수 있으며 이러한 메모리 위치가 충분히 변경되면 운영 체제를 중단 할 수 있습니까?

이것은 모두 시스템마다 다르지만 일반적으로 함수를 호출하면 스택에 CALL FRAME이 작성됩니다. 호출 프레임은 함수에 대한 인수, 함수 호출이 리턴 한 후 실행할 다음 명령의 주소 및 저장된 레지스터를 포함합니다. 호출 프레임은 호출 된 함수가 리턴 할 때 호출 함수를 복원하는 데 필요한 모든 정보를 포함합니다.

은 일반적으로 현재의 호출 프레임 (프레임 포인터)를 가리키는 하드웨어 레지스터가있다. 호 프레임 사이

는 스택은 현재 실행중인 함수의 로컬 변수를 포함한다.

함수가 반환

, 그것은 호출 프레임을 찾습니다 프레임 포인터 레지스터를 사용합니다.그런 다음 이전에 저장된 프레임 포인터 값을 포함하여 콜 프레임의 데이터를 복원하고 호출 기능을 계속 실행합니다.

포인터의 내용을 덮어 쓰는 경우, 그럴 가능성이 있습니다. 귀하의 전화 기능은 그들의 변화를 볼 수 있습니다. 프로그램이 중단 될 수 있습니다. 아무거나 일어날 수있다.

호출 프레임과 관련된 기능이 있습니다. 이를 위해서는 콜 프레임이 어떻게 배치되고 레지스터 사용법을 정확하게 알아야합니다.

예를 들어 현재 함수가 반환 될 때 자동으로 해제되도록 스택에 메모리를 할당한다는 점을 제외하면 malloc()과 같은 공통 라이브러리 함수 alloca()가 있습니다. alloca를 구현하려면 호출 한 함수의 상태를 망칠 필요가있다. 이를 위해서는 호출 프레임 구조에 대한 지식이 필요합니다.

그리고 이러한 값을 가졌다면 운영 체제를 중단하지 않을 것입니다. 너는 단지 자신을 해칠거야.