2014年4月5日

va_list の ap は消費される。

前回のデーモンプロジェクトでは結局ログメッセージをsyslogとstderrの両方に出力するようにし、以下のようなwarnx(3)の包み込みを書いたのだがうまく行かない。


static void __warnx(const char *fmt, ...)
{

        va_list ap;

        va_start(ap, fmt);
        if (lopt)
                vsyslog(LOG_WARNING, fmt, ap);
        if (eopt)

                vwarnx(fmt, ap);
        va_end(ap);
}

lopteoptの両方が真の時、vwarnx(3)の出力が乱れるのだ。

vsyslog(3)vwarnx(3) を入れ替えると、必ず後に呼ばれる方が乱れることから、v付きの関数が呼ばれる度にapが消費されるのではないかと考え、以下のようにそれぞれのv付き関数にapを新しく確保するようにしたらうまく行った。


static void __warnx(const char *fmt, ...)
{

        va_list ap;

        va_start(ap, fmt);
        if (lopt)
                vsyslog(LOG_WARNING, fmt, ap);
 
        va_end(ap);
        va_start(ap, fmt);
        if (eopt)
                vwarnx(fmt, ap);
        va_end(ap);
}

このことはva_start(3)のマニュアルページには明記されていない

va_copy(3)を使ってapを複製・保存(va_copy(aq, ap);)するという手もあるのかも知れないが、その際、マニュアルページにはva_copy(3)で複製されたaqva_end(aq);で開放しなければならないと書いてあるが、複製元のapについては明記されていない(通常はva_start(3)で確保されたapは必ずva_end(3)で開放)。

深入りするのが面倒なので今回はこれでよしとする。

0 件のコメント:

コメントを投稿