Skip to main content

Core Dump Pattern 두번째

Code Dump Pattern에 대해서는 지난 번 글에서 얘기한 바 있습니다. 한동안 잠잠하다가 다시 core dump가 발생했는데 이번에도 제가 담당하는 부분이 아니어서 보지 않고 있다가 다른 분이 pstack을 구해 공지한 것을 보니 대략 원인이 보이더군요.

그럼 먼저 증상을 보여 드릴테니 원인을 찾아보세요. :-)

먼저 log 파일에는 pure virtual function called라는 문장이 출력되었으며 해당 pstack은 다음과 같았습니다.


Thread 127 (process 18441):
...
#17 0x01089514 in std::terminate () from /usr/lib/libstdc++.so.5
#18 0x01089a17 in __cxa_pure_virtual () from /usr/lib/libstdc++.so.5
#19 0x08ebc0d9 in DpOMidCallActiveInitial::process (this=0x555ff748,
bcsm=0x89faec1c)
#20 0x08e2bd77 in Bcsm (this=0x89faec1c,
bcsmState=_DpOMidCallActiveInitial, legId=1,
destinationRoutingAddress=0x0, cs=0x8f88aa14,
isArmedTDPExist=true)
#21 0x08e50e51 in BcsmKo (this=0x89faec1c, st=_DpOMidCallActiveInitial,
lt=1, ds=0x0, cs=0x8f88aa14)
#22 0x081eda42 in NPFactory::makeNewBcsm (st=_DpOMidCallActiveInitial,
lt=1, ds=0x0, cs=0x8f88aa14, isArmedTDBExist=true)
...


.

찾으셨나요?

사실 몇주 전에 pure virtual function called 에러에 관한 글을 쓰려고 한적이 있었는데 마침 똑같은 주제의 글이 The C++ Source에 올라오더군요. 여기의 글을 읽으시는 분들이면 대부분 구독하고 있는 사이트일 것 같아 쓰지 않기로 했었는데 이번에 이 내용의 core dump가 발생했네요.

이 에러의 원인에 대해 자세히 알고 싶으신 분들은 위의 링크를 참고하세요. 이해하기 쉽게 그림까지 곁들여 설명해 주고 있습니다. ((예전에 썼던 Study About Double Delete글에도 비슷한 내용이 있었습니다.))

이번에 발생한 문제는 위 글의 Two of the Classic Blunders 부분에 나와 있는 내용입니다. 그리고 Effective C++ 3rd Ed.의 Item 9: "Never call virtual functions during construction or destruction."에서도 설명하고 있는 내용이죠. 바로 클래스의 생성자에서 virtual function을 호출한 경우입니다. 다만 직접 호출한 것이 아니라 다른 함수를 한단계 거쳐 호출한 것이라 컴파일러가 warning을 발생시키지 않았습니다.

위의 pstack을 보면 BcsmKo는 Bcsm을 상속받은 클래스로 BcsmKo가 new되면서 먼저 Bcsm의 생성자가 호출되고 있습니다. 여기서 DpOMidCallActiveInitial 클래스의 process()라는 함수를 호출하면서 생성중인 자신의 this (Base*)를 넘기고 있습니다. 이 process()함수에서는 이 this (Base*)를 사용하여 Base 클래스의 어떤 함수를 호출하는데 이 함수가 바로 pure virtual function이었습니다.

원래 있었던 코드였는데 새로운 기능이 추가되기 전까진 한번도 실행되지는 않던 코드의 조합이었다고 하더군요. 에러가 발생한 원인을 설명해주자 관련 개발자들이 모여 얘기하는걸 들었는데 아마 다른 조합도 있을 것 같다며 괴로워하더군요. :-|

이번에도 지난번 글에서 만들었던 패턴의 형식으로 만들어 보았습니다.


  1. Name
    • Core on Constructor with "pure virtual function called" message


  2. Problem
    • pstack에서 생성자가 보이며 "pure virtual function called"라는 메시지가 출력된다.

      Thread 127 (process 18441):
      ...
      #17 0x01089514 in std::terminate () from /usr/lib/libstdc++.so.5
      #18 0x01089a17 in __cxa_pure_virtual () from /usr/lib/libstdc++.so.5
      #19 0x08ebc0d9 in bar(base=0x89faec1c)
      #20 0x08e2bd77 in Base (this=0x89faec1c)
      #21 0x08e50e51 in Derived (this=0x89faec1c)
      ...


  3. Cause
    • 원인은 다음과 같이 생성자에서 pure virtual function을 호출했을 가능성이 매우 높다.

      void bar(Base* );

      struct Base
      {
      Base() {
      bar(this);
      }
      virtual ~Base() {}
      virtual void foo() = 0;
      };

      struct Derived : Base
      {
      virtual ~Derived();
      };

      void bar(Base* b)
      {
      b->foo(); // oops! this is pure virtual function.
      }

      Base* obj = new Derived; // core dump


  4. Solution

    • 생성자에서 해당 pure virtual function을 호출하지 않아도 되는 방법이 있다면 그 방법을 사용한다.

    • 생성자외에 init()와 같은 별도의 초기화 함수를 만들어 사용한다. 이 방법으로 위의 코드를 수정해 보면 다음과 같다.

      struct Base
      {
      void init() {
      bar(this);
      do_init();
      }
      virtual ~Base() {}
      virtual void foo() = 0;
      virtual void do_init() {}
      };

      Base* obj = new Derived;
      obj->init();
      ((여기서 do_init()은 C++ of the Day #39 - State with NVI (or Template Method)에서 설명했던 NVI 함수입니다. 이렇게 함으로써 Base를 상속받는 클래스는 자신을 위한 초기화 내용을 추가할 수 있습니다.))



  5. Other Possible Causes
    • 없음




패턴으로 만들고 보니 "pstack에 생성자가 보이고 pure virual function called 에러가 발생한다"라는 원인에 해답이 다 있군요. 다음 패턴을 위해 core dump가 더 자주 발생하길 바래야 하는걸까요? ;-)

Comments

  1. 비슷한 주제의 글을 만나게 되어 반갑습니다. 저도 http://www.buggymind.com/84 여기에 같은 문제에 대한 글을 올렸습니다만... 트랙백남길까 하다가 못찾아서 덧글 남기고 갑니다. 좋은 하루 되세요 ^^

    ReplyDelete

Post a Comment

Popular posts from this blog

1의 개수 세기

저도 간단한 알고리즘 문제 하나... :-)

어떤 수 n이 주어졌을때 1~n까지의 수를 쭈욱 썼을때 나오는 1의 개수를 구하는 문제입니다.

예를 들어 13이라는 수가 주어지면 1~13까지의 수 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13에서 1은 1, 10, 11, 12, 13에 나오며 그 개수는 6이 됩니다. 즉, f(13)=6.

원래 문제는 f(n)=n이 되는 1이 아닌 가장 작은 수를 구하는 문제인데 이 문제의 경우에는 처음부터 쭈욱 세어나가면 되기 때문에 간단히 다음과 같이 구현을 하면 됩니다. ((한가지 주의할 점은 이전에 찾았던 n-1값을 사용하지 않고 다시 처음부터 n까지 값을 계산하면 시간이 너무 많이 걸린다는 점입니다. 위의 코드에서는 static 변수를 사용하여 이전 값에 계속 더해나가는 방법을 사용했습니다.))


#include

int count1(int n)
{
static int cnt = 1; // not 0 because n starts from 2. see main.

while (n > 0) {
if ((n % 10) == 1) ++cnt;
n /= 10;
}

return cnt;
}

int main()
{
using namespace std;

int n = 2;

while (count1(n) != n) ++n;
cout << n << endl;
}


좀 재미가 없죠? 그래서 이번 문제는 어떤 수 n에 대해서 f(n)을 O(1)시간에 구하는 알고리즘을 만드는 것입니다. 관심있으신 분들은 한번 풀어보세요. 제가 만든 코드는 내일 올려보겠습니다.

C++ of the Day #9 - Boost.Python 사용하기 #1

Python은 가장 인기있는 interpret 언어중의 하나입니다. Python의 장점 중 하나는 C/C++ 모듈과 쉽게 연동할 수 있다는 점입니다. 물론 손으로 일일히 wrapper를 만드는 것은 손이 많이 가고 에러를 만들수 있는 작업이나 SWIG등과 같은 도구를 사용하면 쉽게 python 모듈을 만들 수 있습니다.

Boost.Python은 이런 SWIG와 같이 python 모듈을 쉽게 만들 수 있도록 도와주는 라이브러리로 순수 C++만을 사용한다는 점이 SWIG와 다른 점입니다. 그리고 개인적으로는 Boost 라이브러리에 포함되어 있는 것들이 왠지 좀 더 믿음직스러워서... :-)

이번 글에서는 Boost.Python 문서에 나와 있는 예제를 가지고 간단하게 python 모듈을 만드는 방법에 대해서 알아보겠습니다.

Requirements리눅스
이 글에서는 리눅스 환경에서의 사용 방법을 설명한다.Boost.Python 라이브러리 (1.33.1)
Boost 라이브러리를 다운로드받아 아래와 유사한 명령으로 라이브러리를 빌드한다.
bjam -sTOOLS=gcc -with-python install

bjam의 --prefix 옵션으로 라이브러리가 설치될 위치를 변경할 수 있다.Python 라이브러리 (2.4.3)
Python을 다운로드 받아 빌드하여 설치한다.
위의 경우와 유사하게 configure의 --prefix 옵션으로 설치될 위치를 변경할 수 있다.

Write C++ Code다음과 같이 코드를 작성한다.

// greet.cpp #include <stdexcept> char const* greet(unsigned x) { static char const* const msgs[] = { "hello", "Boost.Python", "world!" }; if (x > 2) throw std::range_error("greet: index out of range"…

Hello Wordpress, again.

한 두주일 정도 Textpattern을 사용해봤는데 다시 Wordpress로 돌아오기로 결정했습니다. 무엇보다 스킨 변경이 너무 복잡하고 사용자층이 Wordpress에 비해 너무 앏네요. 원하는 plugin도 찾기 어렵고... :-|

그동안 Textpattern에 썼던 글들은 모두 Wordpress로 옮겼습니다. 2개 있던 댓글도 옮겼는데 그중의 하난 제가 쓴... ;-)

애초에 wp-dokuwiki plugin이 무거워서 옮겼던 것이라 이 plugin은 설치를 안할 예정인데 몇가지 아쉬운 점이 있네요.

첫째는 code highlighting 기능인데 이 기능은 예전에 만들어 놨던 것을 조금 수정해서 쓰려고 준비중입니다. 두번째는 Footnote 기능인데 찾아보니 Footnotes 0.9 Plugin for WordPress 2.0.x라는게 있네요.

이정도면 비록 wiki syntax에 비할바는 아니지만 쓸만할 것 같습니다. :-)