I'm trying to understand when clock_gettime()
can lead to errors. The man page lists the following two possibilities:
- EFAULT tp points outside the accessible address space.
- EINVAL The clk_id specified is not supported on this system.
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 thesyscall
function withSYS_clock_gettime
as its argument, I would expect you to seeEFAULT
.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 thatEFAULT
is even documented.