2012-07-15 2 views
6

How is access for private variables implemented in C++ under the hood?이 질문에 대한 답변을 얻었습니다. 개인 데이터 멤버에 액세스하는 대신 캐스팅과 레이아웃 호환성에 의존하여 private 멤버 함수를 호출 할 수 있습니까? 이 (적어도 Ideone에) 작동 :레이아웃 호환 유형으로 캐스팅하여 개인 멤버 함수에 액세스 할 수 있습니까?

#include <iostream> 

class X 
{ 
public: 
    X() : private_(1) { /*...*/ } 

private: 
    int Value() { return private_; } 
    int private_; 
}; 

// Nasty attempt to simulate the object layout 
// (cross your fingers and toes). 
// 
class BaitAndSwitch 
    // hopefully has the same data layout as X 
{ // so we can pass him off as one 
public: 
    int Value() { return private_; } 
private: 
    int private_; 
}; 

int f(X& x) 
{ 
    // evil laughter here 
    return (reinterpret_cast<BaitAndSwitch&>(x)).Value(); 
} 

int main() 
{ 
    X x; 
    std::cout << f(x) << "\n"; // prints 0, not 1 
    return 0; 
}; 

주 (허브 셔터의 열 Uses and Abuses of Access Rights에서 영감을)

일부 코드! 새로운 C++11 Standard 또는 적어도 구현 정의 -으로 정의 된 방식으로 레이아웃 호환성 및 reinterpret_cast/static_cast를 사용하여 액세스 제어를 우회하는 방법이 있습니까?

EDIT1 : (이 실제로 작동하지만) 그는 위의 코드가 작동하지 않을 이유 두 가지 이유를 나열 셔터의 열에서

A) : Ideone

EDIT2에 출력 X와 BaitAndSwitch의 오브젝트 레이아웃은 같은 것이 보장되지는 않지만 실제로는 항상 그렇습니다.

b) 대부분의 컴파일러는 해커가 의도 한대로 의 결과 참조를 사용하도록 허용하지만 reinterpret_cast의 결과는 정의되지 않습니다.

새로운 C++ 11 Standard는 이제 이러한 레이아웃/reinterpret_cast 보장을 제공합니까?

+0

'reinterpret_cast'를 사용하여 원하는 모든 것을 우회 할 수 있습니다. 잘 정의 된 방식으로 그렇게 할 수 있는지 묻고 있습니까? –

+0

@OliCharlesworth 예, 보장은 최상의 것이고, 구현은 두 번째로 우수하며 UB는 좋지 않습니다. – TemplateRex

+0

안돼. 어셈블리 수준의 클래스 메서드는 숨겨진 "this"매개 변수가있는 전역 함수이며 클래스 인스턴스에 속하지 않으며 레이아웃 트릭을 통해 액세스 할 수 없습니다. –

답변

3

예. 필자가 도용하려는 유형과 동일한 레이아웃을 사용하는 유형을 만든 다음 해당 유형에서 레이아웃 호환 유형으로 reinterpret_cast을 작성할 수 있습니다. 그러나 이것은 표준에 의해서만 보호됩니다. 모두 소스 및 대상 유형은 표준 레이아웃 유형입니다 (물론 레이아웃이 동일하면 실제로 작동합니다). 그래서 소스에 가상 기능이 있다면, 당신은 망설입니다.

이렇게하면 셔터의 문제를 모두 만족하는 것 같습니다. 표준 레이아웃의 규칙이 같은 순서로 같은 회원 레이아웃 호환 정의 모두 표준 레이아웃 (9.2, 17 절)되는 두 가지 유형의 확인 :

두 표준 레이아웃 구조체 (9 절) 형식은 비 정적 데이터 멤버의 수와 해당 비 정적 데이터 멤버가 (선언 순서에 따라) 레이아웃 호환 유형 (3.9) 인 경우 레이아웃 호환 가능합니다.

그리고 reinterpret_cast에 대한 규칙은 두 개의 표준 레이아웃 유형 (섹션 5.2.10, 제 7 항) 사이의 변환의 의미를 지정하는 객체 포인터가 명시 적으로의 객체 포인터로 변환 할 수 있습니다

을 다른 유형. "T1에 대한 포인터"유형의 prvalue v가 "cv T2에 대한 포인터"유형으로 변환되면 T1과 T2가 모두 표준 레이아웃 유형 (3.9)이고 T2의 정렬 요구 사항이 더 엄격하지 않으면 결과는 static_cast<cv T2*>(static_cast<cv void*>(v))입니다. T1의 것보다, 또는 어느 쪽의 형태도 void 인 경우.

+0

감사합니다. 누락 된 return 문이 이미 수정되었습니다. – TemplateRex

+2

엄격한 앨리어싱을 위반하지 않습니까? – Puppy

+0

@DeadMG : 확실하지 않습니다. 나는 [엄격한 앨리어싱을 유발하는 표준 섹션의 일부를 보았다] (http://stackoverflow.com/a/9588075/734069), 이것들을 위반하지 않는 것 같다. 그러나 나는 그것에 대한 전문가가 아니다. –