0

次のコード(log関数の一部)を取得しました:

/* set to 32 on purpose */
#define MAX_LOG_MSG_SZ 32

void log(const char *fmt, ...) {
    ....

    char msg[MAX_LOG_MSG_SZ] = {0};
    int nb_bytes = 0;

    /* get current time */
    time_t now = time(NULL);

    char time_buf[32] = {0};

    /* format time as `14 Jul 20:00:08`, and exactly 16 bytes */
    strftime(time_buf, sizeof(time_buf), "%d %b %H:%M:%S", localtime(&now));

    nb_bytes = snprintf(msg, sizeof(msg), "%s", time_buf);

    va_list ap;
    va_start(ap, fmt);
    vsnprintf(msg + nb_bytes, MAX_LOG_MSG_SZ, fmt, ap);
    va_end(ap);

    ....
}

注意が必要なのは、長いパラメーターを渡す (32 バイトより長くする) ときにtime_buf32 未満の値 (16 よりも大きい、たとえば 31) に変更すると、これらのコードはスタック破壊をスローすることです。数分間のデバッグの後、vsnprintf呼び出しラインを次のように変更しました

 vsnprintf(msg + nb_bytes, MAX_LOG_MSG_SZ - nb_bytes, fmt, ap);

スタックスマッシングがなくなり、問題は解決したと思います。

BUT:オンtime_buf[32](または他の大きなサイズ)、なぜエラー呼び出し

 vsnprintf(msg + nb_bytes, MAX_LOG_MSG_SZ, fmt, ap);

スタックスマッシングを投げませんか?もっと正確に言えば、なぜmsgのスタック破壊がその無関係なスタック ( time_buf) スペースに関連しているのですか?

更新:これは私のuname -a出力です:

 Linux coanor 3.5.0-34-generic #55-Ubuntu SMP Thu Jun 6 20:20:19 UTC 2013 i686 i686 i686 GNU/Linux
4

2 に答える 2

1
char time_buf[32] = {0};
/* format time as `14 Jul 20:00:08`, and exactly 16 bytes */
strftime(time_buf, sizeof(time_buf), "%d %b %H:%M:%S", localtime(&now));

nb_bytes = snprintf(msg, sizeof(msg), "%s", time_buf);

したがって、実質的に time_buf と msg には同じデータが含まれます。snprintfnull 文字を除いて、msg に正常に書き込まれた文字数を返します。

vsnprintf(msg + nb_bytes, MAX_LOG_MSG_SZ, fmt, ap);

で指定されたアドレスから書き込もうとしていますmsg+nb_bytes。msg には 16 文字ありました。しかし、あなたMAX_LOG_MSG_SZは32文字あると主張しています。文字列の最後に書き込もうとしています。fmt に 15 文字を超える文字が含まれている可能性があります。

vsnprintf(msg + nb_bytes, MAX_LOG_MSG_SZ - nb_bytes, fmt, ap);

今回は、既に msg に書き込まれている文字を適切に減算し、16 文字を に書き込みvsnprintfます。これに従い、文字配列の末尾を超えて書き込みません。

于 2013-07-14T13:15:10.947 に答える
1

スタックベースのバッファを使用する場合、割り当てられたバッファがオーバーランしないように注意する必要があります。ご自分でわかったように、 を使用してバッファ オーバーフローの可能性を導入しましたvsnprintf(msg + nb_bytes, MAX_LOG_MSG_SZ, fmt, ap);。これは、vsnprintf に伝えたために、実際よりも多くのスペースが利用可能になっているためです (nb_bytes = snprintf(msg, sizeof(msg), "%s", time_buf);既にいくつかのバイトがバッファーに書き込まれているため)。

したがって、この効果を回避するには、MAX_LOG_MSG_SZ - nb_bytesの代わりに渡すという修正が正しいです。MAX_LOG_MSG_SIZE

また、snprintf とそのバリアントは、実際にバッファーに書き込まれたバイト数に関係なく、常に書き込まれたバイト数を返すことを知っておくことも重要です。

編集: したがって、あなたの場合、メッセージ バッファの合計長を超えないように、構成中に文字列の全長を追跡する必要があります。

于 2013-07-14T13:16:41.590 に答える