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_buf为小于 32 的其他值(大于 16,例如 31)时,这些代码会抛出堆栈粉碎。经过几分钟的调试,我将vsnprintf调用线路更改为

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

堆栈粉碎消失了,我认为问题已解决。

但是:在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 包含相同的数据。snprintf返回将成功写入 msg 的字符数,不包括空字符。

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

您正试图从 给出的地址写入msg+nb_bytes。您在 msg 中有 16 个字符。但是你声称你有MAX_LOG_MSG_SZ32 个字符。您正在尝试写入字符串的末尾。也许 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 回答