首次调用 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_t 到 open() 函数并将其用作:
*int open(const char pathname, int flags, mode_t mode);
将 模式 设置为 0777
因为当我添加 O_CREAT 位时: open("./logFile.log", O_APPEND | OCREAT);
文件 logFile.log 是在文件系统中使用 sticky 位 ON(启用)创建的,在下一次迭代中 open()失败。
再次感谢您的帮助。
我在 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_t 到 open() 函数并将其用作: *int open(const char pathname, int flags, mode_t mode); 将 模式 设置为 0777 因为当我添加 O_CREAT 位时: open("./logFile.log", O_APPEND | OCREAT); 文件 logFile.log 是在文件系统中使用 sticky 位 ON(启用)创建的,在下一次迭代中 open()失败。
再次感谢您的帮助。