【问题标题】:Why calling vprintf or similar functions twice does not work or even segfaults?为什么调用 vprintf 或类似函数两次不起作用甚至是段错误?
【发布时间】:2016-12-10 10:18:17
【问题描述】:

我的程序中出现了分段错误,并且能够在这个简单的示例中可靠地重现它:

#include <stdio.h>
#include <syslog.h>
#include <stdarg.h>

// if I remove at least one of the args, segfault does not happen
void doLog(unsigned int arg0, unsigned int arg1, unsigned int arg2, const char* format, ...)
{
    va_list args;

    va_start(args, format);
    // by default - to both console and syslog
    vprintf(format, args);

    // next v* function call causes segfault, no matter if vprintf or vsyslog
    //vprintf(format, args);
    vsyslog(LOG_WARNING, format, args);
    va_end(args);
}

int main(int argc, char *argv[])
{
    // if I remove at least one of the function args or an %s in the string, the segfault does not happen
    doLog(1, 2, 3, "Format with args %s , %s", "1", "2");

    return 0;
}

这里发生了什么?为什么第二次调用 vprintf 或 vsyslog 会导致段错误,为什么它只发生在这个特定数量的函数参数上?即使我删除了一些参数以避免段错误,第二次输出仍然是错误的。

关于我的环境的一些信息:

  • 操作系统:(由uname -a 给出)Linux lexdeb 3.16.0-4-amd64 #1 SMP Debian 3.16.7-ckt25-2+deb8u3 (2016-07-02) x86_64 GNU/Linux(lexdeb 只是主机名)
  • gcc 版本 4.9.2 (Debian 4.9.2-10)
  • 程序在 main.c 文件中
  • compilation log

【问题讨论】:

  • 您可能需要阅读 va_copy 的联机帮助页。
  • 您应该始终使用gcc -Wall 进行编译,并且经常使用-g
  • @EOF 谢谢,这是有道理的。是不是说v*函数本身不调用va_copy来保证args的安全处理?
  • @JustAMartin 如果你不多次使用va_list,复制它就是浪费时间。如果v*printf()-family 复制了va_list 参数,您将无法避免这种时间浪费。

标签: c linux segmentation-fault variadic-functions


【解决方案1】:

来自vprintf 手册页:

int vprintf(const char *format, va_list ap);

(...) 因为它们调用了va_arg 宏,调用后ap 的值未定义。见stdarg(3)

所以当你到达时:

vsyslog(LOG_WARNING, format, args);

args 未定义,导致未定义的行为。

【讨论】:

  • 然而它也说他们不打电话给va_end,而调用者需要打电话给va_end
猜你喜欢
  • 2021-12-24
  • 1970-01-01
  • 1970-01-01
  • 2015-12-11
  • 1970-01-01
  • 2020-08-10
  • 1970-01-01
  • 2011-02-07
  • 2021-09-03
相关资源
最近更新 更多