포맷스트링이 부릅니다. 헬게이트2…

@codemaru · January 03, 2013 · 2 min read

최근에 포맷 스트링과 관련된 문제를 한 번 더 겪어서 여기다 기록을 남겨본다. 문제는 다음과 같은 부분에서 출발했다. 크래시가 났는데 log_writer의 Write 함수를 호출하는 부분에서 났다. 그간 문제없이 잘 사용했던 함수라 증말 증상이 이해가 되질 않았다. 뭔가 buffer 값이 잘못됐는지만 계속 추적했는데 buffer 같은 이상이 없었다.

char buffer[80];
// 버퍼 계산하는 부분
log_writer->Write(L"buffer = '%hs'", buffer);

그렇게 한참을 시도를 하다 놀라운 사실을 발견했다.

클래스가 다음과 같이 선언돼 있었던 것이다. 문제를 눈치 챘는가?

class LogWriter : public ILogWriter
{
public:
    virtual void XCALL Write(xcwstr fmt, ...);
    virtual void XCALL Write(xcstr fmt, ...);
    virtual void XCALL Write(xcwstr fmt, va_arg ap);
    virtual void XCALL Write(xcstr fmt, va_arg ap);
};

맞다. 인자가 두개인 함수가 같이 선언된 것이 문제였다. 내가 원했던 링크 경로는 Write(xcwstr fmt, …)이었는데, Write(xcwstr fmt, va_arg ap)로 연결이 됐던 것이다. 흙~ 그래서 클래스를 다음과 같이 바꿨다.

class LogWriter : public ILogWriter
{
public:
    virtual void XCALL Write(xcwstr fmt, ...);
    virtual void XCALL Write(xcstr fmt, ...);
    virtual void XCALL WriteV(xcwstr fmt, va_arg ap);
    virtual void XCALL WriteV(xcstr fmt, va_arg ap);
};

가변 인자 함수를 정의할 때에는 각별히 주의해야겠다.

@codemaru
돌아보니 좋은 날도 있었고, 나쁜 날도 있었다. 그런 나의 모든 소소한 일상과 배움을 기록한다. 여기에 기록된 모든 내용은 한 개인의 관점이고 의견이다. 내가 속한 조직과는 1도 상관이 없다.
(C) 2001 YoungJin Shin, 0일째 운영 중