I'm trying to understand when clock_gettime()
can lead to errors. The man page lists the following two possibilities:
It's easy to trigger an EINVAL
error but I'm not able to get clock_gettime()
to set errno
to EFAULT
. Instead, the kernel sends a SIGSEGV signal to terminate the program. For instance, in the following code:
#include <time.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>
int main()
{
struct timespec tp;
double time;
if (clock_gettime(CLOCK_MONOTONIC, &tp + 4096) == -1) {
if (errno == EINVAL) {
perror("EINVAL");
return EXIT_FAILURE;
} else if (errno == EFAULT) {
perror("EFAULT");
return EXIT_FAILURE;
} else {
perror("something else");
return EXIT_FAILURE;
}
}
time = tp.tv_sec + 1e-9 * tp.tv_nsec;
printf("%f\n", time);
}
How does the Linux kernel choose between triggering a segmentation fault and having the system call return -EINVAL
? When will it choose to do the latter? If the kernel always sends the signal, is it actually necessary to check whether errno
equals EFAULT
?
I'm running Linux kernel 4.15 and I compiled the program with (using clang v6.0):
clang -g -O0 -Wall -Wextra -Wshadow -Wstrict-aliasing -ansi -pedantic -Werror -std=gnu11 file.c -o file
clock_gettime
is probably not executing as a syscall, but rather in userspace as part of the vdso. If you actually perform a syscall by using the syscall
function with SYS_clock_gettime
as its argument, I would expect you to see EFAULT
.
With that said, EFAULT
is not ever something you should expect to be able to rely on. As soon as you pass an invalid pointer to a function that requires a valid pointer as part of its interface contract, you have undefined behavior, and a segfault or an error is only one possible manifestation among many. From this perspective it's something of a mistake that EFAULT
is even documented.