Home > Blockchain >  Segmentation fault after first call to dprintf() or vdprintf()
Segmentation fault after first call to dprintf() or vdprintf()

Time:12-15

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.

  • Related