programing

"dead" 객체에 대한 포인터 접근은 언제 유효합니까?

nicescript 2022. 8. 9. 22:05
반응형

"dead" 객체에 대한 포인터 접근은 언제 유효합니까?

첫째, 분명히 하자면, 저는 참조가 잘못된 포인터에 대해 말하는 이 아닙니다!

다음 두 가지 예를 생각해 보겠습니다.

예 1

typedef struct { int *p; } T;

T a = { malloc(sizeof(int) };
free(a.p);  // a.p is now indeterminate?
T b = a;    // Access through a non-character type?

예 2

void foo(int *p) {}

int *p = malloc(sizeof(int));
free(p);   // p is now indeterminate?
foo(p);    // Access through a non-character type?

질문.

위의 예 중 하나가 정의되지 않은 동작을 호출합니까?

맥락

이 질문은 이 논의에 대한 답변입니다.예를 들어 포인터 인수는 x86 세그먼트 레지스터를 통해 함수에 전달될 수 있으며, 이는 하드웨어 예외를 일으킬 수 있습니다.

C99 표준에서는 다음 사항을 학습합니다(강조사항).

[3.17] 불확정값 - 지정되지 않은 값 또는 트랩 표현

그 후:

[6.2.4 p2] 포인터가 가리키는 오브젝트가 수명이 다하면 포인터의 값이 부정하게 됩니다.

그 후:

[6.2.6.1 p5] 특정 객체 표현은 객체 유형의 값을 나타낼 필요가 없습니다.객체의 저장된 값이 이러한 표현을 가지며 문자 유형이 없는 lvalue 식에 의해 읽혀질 경우 동작은 정의되지 않습니다.이러한 표현이 문자 유형이 없는 lvalue 식에 의해 객체의 전부 또는 일부를 수정하는 부작용에 의해 생성되는 경우 동작은 정의되지 않습니다.이러한 표현을 트랩 표현이라고 합니다.

이 모든 것을 종합하면, "데드" 객체에 대한 포인터 액세스에는 어떤 제한이 있습니까?

부록

위의 C99 표준을 인용했습니다만, C++ 규격에서 동작이 다른지 알고 싶습니다.

예 2는 유효하지 않습니다.당신의 질문은 정확합니다.

예 1은 유효합니다.구조체 유형에는 멤버 중 하나가 트랩 표현을 보유하더라도 트랩 표현을 보유하지 않습니다.즉, 트랩 표현에 문제가 있는 시스템에서는 멤버별 복사가 아닌 바이트 단위 복사로 구조 할당을 구현해야 합니다.

6.2.6 형식의 표현

6.2.6.1 일반

6 [...] 구조체 또는 결합 객체의 값이 트랩 표현일 수 있지만 구조체 또는 결합 객체의 값은 trap 표현일 수 없습니다.

필자의 해석으로는 비문자 타입만이 트랩 표현을 가질 수 있지만, 어떤 타입이든 불확정 값을 가질 수 있으며, 어떤 방법으로든 불확정 값을 가진 오브젝트에 접근하면 정의되지 않은 동작이 발생한다는 것입니다.가장 악명 높은 예로는 OpenSSL이 초기화되지 않은 개체를 랜덤 시드로 잘못 사용하는 경우가 있습니다.

그래서 당신의 질문에 대한 대답은 "절대"가 될 것입니다.

그런데 포인터 자체뿐만 아니라 포인터 자체가 그 후에 결정되지 않는 흥미로운 결과입니다.free또는realloc이 관용어가 정의되지 않은 동작을 호출한다는 것입니다.

void *tmp = realloc(ptr, newsize);
if (tmp != ptr) {
    /* ... */
}

C++ 토론

간단한 답변:C++에서는 클래스 인스턴스에 액세스하여 "읽기"를 하는 것은 없습니다.클래스 이외의 오브젝트는 "읽기"만 할 수 있습니다.이 작업은 lvalue-to-rvalue 변환에 의해 이루어집니다.

자세한 답변:

typedef struct { int *p; } T;

T는 이름 없는 클래스를 지정합니다.토론을 위해 이 반의 이름을 짓자T:

struct T {
    int *p; 
};

복사 생성자를 선언하지 않았기 때문에 컴파일러는 암시적으로 복사 생성자를 선언하므로 클래스 정의는 다음과 같습니다.

struct T {
    int *p; 
    T (const T&);
};

다음과 같은 것이 있습니다.

T a;
T b = a;    // Access through a non-character type?

네, 실제로; 이것은 복사 컨스트럭터에 의한 초기화입니다.따라서 복사 컨스트럭터 정의는 컴파일러에 의해 생성됩니다.정의는 다음과 같습니다.

inline T::T (const T& rhs) 
    : p(rhs.p) {
}

, 이 값에 액세스 하는 것은 포인터이지 바이트 수가 아닙니다.

포인터 값이 유효하지 않은 경우(초기화되지 않았거나 해방되지 않은 경우) 동작은 정의되지 않습니다.

언급URL : https://stackoverflow.com/questions/17024866/when-is-it-valid-to-access-a-pointer-to-a-dead-object

반응형