首次调用 dprintf() 或 vdprintf() 后出现分段错误

Segmentation fault after first call to dprintf() or vdprintf()

我在 Oracle Virtual Box 上使用 Ubuntu 20.04.3。

我很少调用 printf() 使用文件描述符的函数, 但在第二次调用后出现分段错误。 我尝试了 fsync(fd)fdatasync(fd) 但没有解决问题:

logFileFd = open("./logFile.log", O_APPEND);

if (logFileFd == -1)
{
    printf("\ncan't create file %s :[%s]", logFileName, strerror(err));
    exit(ERROR_OPEN_LOG_FILE);
}

va_start(a_list, format);
sprintf(logStr, "%s, %s, INFO, %s, %d - ", __DATE__, __TIME__, __BASE_FILE__, __LINE__);
printf("%s", logStr);
dprintf(logFileFd, "%s", logStr);
vprintf(format, a_list);
vdprintf(logFileFd, format, a_list);
va_end(a_list);
close(logFileFd);

段错误发生在以下行: vdprintf(logFileFd, 格式, a_list);

谁能帮忙看看这是为什么?

非常感谢!

引用 vfprintf(3) 的手册页:

The functions vprintf(), vfprintf(), vsprintf(), vsnprintf() are equivalent to the functions printf(), fprintf(), sprintf(), snprintf(), respectively, except that they are called with a va_list instead of a variable number of arguments. These functions do not call the va_end macro. Because they invoke the va_arg macro, the value of ap is undefined after the call.

此外,在 stdarg(3) 的手册页上,您可以阅读:

If ap is passed to a function that uses va_arg(ap,type) then the value of ap is undefined after the return of that function.

您的代码中的问题是您使用了 va_list a_list 两次 - 第一次调用 vprintf(),然后调用 vdprintf()。第一次调用后,a_list 值未定义。

Man stdarg(3) 声明“列表的多次遍历,每个遍历都由 va_start() 和 va_end() 括起来”。尝试应用以下修改:

sprintf(logStr, "%s, %s, INFO, %s, %d - ", __DATE__, __TIME__, __BASE_FILE__, __LINE__);
printf("%s", logStr);
dprintf(logFileFd, "%s", logStr);

va_start(a_list, format);
vprintf(format, a_list);
va_end(a_list);

va_start(a_list, format);
vdprintf(logFileFd, format, a_list);
va_end(a_list);

此外,请查看调用 open() 时使用的标志。根据手册页 open(2):

The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR

我建议应用以下修改:

logFileFd = open("./logFile.log", O_WRONLY | O_APPEND);

非常感谢您 (ytta) 的及时帮助。

我实施了您所有的回答和建议,并且效果很好。

我唯一需要添加的(这不是我的问题)是 mode_topen() 函数并将其用作: *int open(const char pathname, int flags, mode_t mode); 模式 设置为 0777 因为当我添加 O_CREAT 位时: open("./logFile.log", O_APPEND | OCREAT); 文件 logFile.log 是在文件系统中使用 sticky 位 ON(启用)创建的,在下一次迭代中 open()失败。

再次感谢您的帮助。