【问题标题】:Is a strlen call in snprintf causing this segfault?snprintf 中的 strlen 调用是否导致此段错误?
【发布时间】:2011-03-10 09:24:28
【问题描述】:

我有一个void *,叫它data,我知道它的长度,但不是以空结尾的。我拨打这样的电话snprintf(line, sizeof(line), "%*s", n, (const char*)data),其中n 是已知长度。几乎总是这样,但偶尔会导致段错误。

每当发生段错误时,回溯都会表明问题出在 strlen 内部。当我在 gdb 中打印 data 时,我看到了类似这样的内容

(gdb) p n
$1 = 88
(gdb) p (const char*) data
$2 = 0x1d752fa8
"JASDF" ... "ADS"<Address 0x1d753000 out of bounds>
(gdb) p 0x1d753000-0x1d752fa8
$3 = 88

data 确实是 88 个字符,但不是以 null 结尾的,事实上,它似乎正好靠在一个段上。我的猜测是 snprintf 在数据上总是被称为 strlen ,我通常很幸运,即使data 不是以空值终止的,在我点击该段之前有一个\0 ,然后偶尔我会不走运,它是。那正确吗?如果是这样,解决方法是什么?

这就是堆栈跟踪的样子

#0  0x0000003c8927839e in strlen () from /lib64/libc.so.6
#1  0x0000003c89246749 in vfprintf () from /lib64/libc.so.6
#2  0x0000003c8926941a in vsnprintf () from /lib64/libc.so.6
#3  0x0000003c8924d0a3 in snprintf () from /lib64/libc.so.6

编辑为了回答我自己关于变通的问题,strncpy 是一个更适合调用的函数。我习惯使用 snprintf。

【问题讨论】:

    标签: c segmentation-fault strlen printf


    【解决方案1】:

    snprintf(line, sizeof(line), "%*s", n, (const char*)data)

    data 不是零终止的吗?那你就做错了。

    snprintf(line, sizeof(line), "%.*s", n, (const char*)data);
    

    注意点。

    在字符串的情况下,*.* 中的第一个 * 如果对于所需的输出(屏幕上)长度 - 输入长度是第二个 *man printf 了解更多。

    显然在%*s 格式化的情况下可能会调用strlen(),因为它需要知道是否需要填充输出以及如何填充它。

    【讨论】:

    • 你是对的。手册页非常明确地讨论了非空终止字符串和精度修饰符。
    【解决方案2】:

    看来你是对的。不能保证printf 不会调用strlen,即使它在给定的上下文中不一定必须如此。您通过提供不是 C 字符串的内容作为%s 格式说明符的参数而撒谎,因此您违反了printf 的合同。未定义的行为结果。

    【讨论】:

    • %s 支持非 0 终止字符串:%.*s
    • 真正的问题是他的格式字符串不对,用"%.*s"代替"%*s"
    【解决方案3】:

    我认为你的分析是正确的。如果缓冲区不是以空值终止的,则 strlen 调用将读取直到找到\0。如果它运行超过段的末尾(并且下一个段无效),那么它将产生异常。

    解决方案是对其进行空终止或将其放入另一个可以空终止的缓冲区中。

    【讨论】:

    • 请参阅下面的回复。格式化已经支持非 0 终止的字符串。
    【解决方案4】:

    “解决方法”是使用memcpy()

    size_t validlen = n < sizeof line ? n : (sizeof line - 1);
    memcpy(line, data, validlen);
    line[validlen] = '\0';
    

    【讨论】:

    • "%.*s" 是这样做的方法 - 不需要多余的复制。
    • 我的回答中没有多余的复制——只有一个单个副本,使用memcpy()而不是snprintf()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2012-08-14
    • 2011-01-10
    • 2015-10-14
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多