clinuxerror-handlingsystem-callsvdso

When do Linux system calls trigger a segfault vs returning EFAULT?


I'm trying to understand when clock_gettime() can lead to errors. The man page lists the following two possibilities:

  1. EFAULT tp points outside the accessible address space.
  2. 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


Solution

  • 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.