I am using Ubuntu 20.04.3 on a Oracle Virtual Box.
I have few calls to printf() functions that use file descriptors, but get segmentation fault after the second call. I tried fsync(fd) and fdatasync(fd) but it didn't solve the problem:
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);
the segmentation fault occurs at the line: vdprintf(logFileFd, format, a_list);
Can any one assist why is that?
Thanks a lot !
CodePudding user response:
Quoting man page for 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.
Additionally on the man page for stdarg(3) you can read that:
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.
The problem in your code is that you are using va_list a_list
twice - first in call to vprintf()
, then in call to vdprintf()
. After the first call, a_list
value is undefined.
Man stdarg(3) states that "Multiple traversals of the list, each bracketed by va_start() and va_end() are possible". Try applying following modification:
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);
Additionally, please review the flags used in call to open()
. According to man page open(2):
The argument flags must include one of the following access modes: O_RDONLY, O_WRONLY, or O_RDWR
I would propose to apply following modification:
logFileFd = open("./logFile.log", O_WRONLY | O_APPEND);
CodePudding user response:
Thank you (ytta) very very much for your prompted help.
I implemented all your answer and suggestions and it worked perfectly.
The only thing I needed to add (which was not in my question) is the mode_t to the open() function and use the it as: *int open(const char pathname, int flags, mode_t mode); setting mode to 0777 because when I added the O_CREAT bit: open("./logFile.log", O_APPEND | OCREAT); the file logFile.log was created with the sticky bit ON (enabled) in the file system, and in the next iteration the open() failed.
Thanks again very much for your help.