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_gettimeis probably not executing as a syscall, but rather in userspace as part of the vdso. If you actually perform a syscall by using thesyscallfunction withSYS_clock_gettimeas its argument, I would expect you to seeEFAULT.With that said,
EFAULTis 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 thatEFAULTis even documented.