내가 내 질문에 문제 해결 싶지 않아 있습니다 - 뭔가에 대해 궁금 해서요 내가 이렇게 일어나는 일들의 가능성에 대해 생각하고했습니다 :개체를 삭제하면 정확히 어떻게됩니까? (GCC) (때 충돌을 두 번 삭제 하시겠습니까?)
객체에서 삭제하고 gcc를 컴파일러로 사용하면 정확히 어떻게됩니까?
지난 주 나는 경쟁 조건이 개체의 이중 삭제로 이어지는 충돌을 조사하고있었습니다.
가상 함수 테이블에 대한 포인터가 이미 덮어 쓰기 때문에 개체의 가상 소멸자를 호출 할 때 충돌이 발생했습니다.
가상 함수 포인터가 첫 번째 삭제로 덮어 씁니까?
그렇다면 새로운 메모리 할당이 이루어지지 않는 한 두 번째 삭제가 안전합니까?
내가 전에는 인식하지 못했던 유일한 궁금한 점은 가상 함수 표가 첫 번째 삭제 중에 immediatly 덮어 쓰이거나 두 번째 삭제가 중단되지 않는다는 것입니다.
(첫 번째는 "경주"가 발생하면 항상 같은 위치에서 충돌이 발생한다는 것을 의미합니다. 두 번째 경주는 일반적으로 경주가 발생해도 아무 일도 일어나지 않습니다.) 그리고 세 번째 스레드가 한편 문제가 발생합니다)
편집/업데이트 :. 내가 다음 코드 세그먼트 폴트와 함께 테스트를 충돌 않았다
(GCC 4.4는 i686과 AMD64) :
class M
{
private:
int* ptr;
public:
M() {
ptr = new int[1];
}
virtual ~M() {delete ptr;}
};
int main(int argc, char** argv)
{
M* ptr = new M();
delete ptr;
delete ptr;
}
dtor에서 '가상'을 제거하면 double-free를 감지하기 때문에 프로그램이 glibc에 의해 중단됩니다. 'virtual'을 사용하면 가상 함수 테이블에 대한 포인터가 유효하지 않기 때문에 소멸자에 간접 함수 호출을 수행 할 때 충돌이 발생합니다.
포인터가 유효한 메모리 영역 (힙)을 가리키고 있지만 유효하지 않은 값 (카운터? 매우 작음, 예 : 0x11 또는 0x21)이므로 '호출'(또는 'jmp '컴파일러가 반환 최적화를했을 때) 잘못된 영역으로 건너 뜁니다.
프로그램 신호 SIGSEGV,
분할 결함을 받았다. 0x0000000000000021
??() (gdb)
#
0 개 0x0000000000000021 in ??()() 주에서
#
1 0x000000000040083e
그래서 위에서 언급 한 조건에 가상 함수 테이블에 대한 포인터는 항상 덮어 쓰기 한 다음 삭제가 열반 경우로 이동합니다 있도록 먼저 삭제 클래스에는 가상 소멸자가 있습니다.
은 당신이 어떤 뮤텍스 또는 중요한 부분에 투자해야 할 것 같은데 너무 –
0A0D : 이것은 내 prelimary 솔루션 (해결 방법)이다. 실제로 개체를 삭제할 수있는 두 개의 스레드가 있다는 의도가 있었기 때문에 디자인 결함이있었습니다. – IanH