더북(TheBook)

위에서 RoboCat 클래스에 추가된 내용이 어떻게 메모리에 저장되는지를 살펴보면, 직렬화가 꽤 골치 아플 것을 알 수 있다. 표 4-2에 전송 전/후의 메모리 레이아웃을 나타내었다.

▼ 표 4-2 복잡해진 RoboCat의 메모리 레이아웃

주소

필드

원본값

대상 초깃값

대상 최종값

바이트 0-3

vTablePtr

0x0A131400

0X0B325080

0x0A131400

바이트 4-7

mHealth

0x00000005

0x0000000A

0x00000005

바이트 8-11

mMeowCount

0x00000002

0x00000003

0x00000002

바이트 12-15

mHomeBase

0x0D124008

0x00000000

0x0D124008

바이트 16-143

mName

Fuzzy\0

\0

Fuzzy\0

바이트 144-167

mMiceIndices

??????

??????

??????

 

이제 RoboCat의 첫 4바이트는 가상 함수 테이블(virtual function table)을 가리키는 포인터가 되었다. 이것도 32비트 아키텍처일 때만 그렇고 64비트 아키텍처에서는 8바이트가 된다. RoboCat에 가상 함수 RoboCat::Update()가 추가되었으므로, 각 RoboCat 인스턴스는 자신의 가상 함수가 실제 구현된 지점을 가리키는 함수 포인터를 갖고 있어야 한다. 이 포인터 값을 나이브하게 송수신하면 제대로 동작하지 않는데 왜냐하면 실행되는 프로세스마다 가상 함수 테이블의 위치가 같다는 보장이 없기 때문이다. 위의 경우에 수신자의 멀쩡하던 가상 함수 테이블 포인터 값 0x0B325080이 데이터가 리플리케이션, 즉 복제 전달되는 과정에서 엉뚱한 값으로 덮어 쓰이고 만다. 그 결과 수신자가 갱신 받은 RoboCat 객체의 Update()를 호출할 때, 운이 좋으면 메모리 접근 예외가 발생하고 끝나지만, 대개는 엉뚱한 위치의 코드를 실행하게 되어 훨씬 심각한 현상이 야기될 수 있다.

신간 소식 구독하기
뉴스레터에 가입하시고 이메일로 신간 소식을 받아 보세요.