I'm trying to understand when clock_gettime() can lead to errors.
Ok.
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?
It's easy. There are some checks in case they are true the function sets errno. In case you access a protected memory region the kernel sends SIGSEGV to your process.
If you inspect the __clock_gettime from glibc function you see that:
switch (clock_id)
{
#ifdef SYSDEP_GETTIME
SYSDEP_GETTIME;
#endif
#ifndef HANDLED_REALTIME
case CLOCK_REALTIME:
...
break;
#endif
default:
#if HP_TIMING_AVAIL
if ((clock_id ...) == CLOCK_THREAD_CPUTIME_ID)
...
else
#endif
__set_errno (EINVAL);
break;
The glibc wrapper set's EINVAL in case of some strange clock_id value.
Dereferencing a pointer value outside any valid memory region in undefined behaviour and spawns nasal demons. On Linux a SIGSEGV is a signal sent to a process which tries to write to a protected memory region.
The following code spawns demons and should raise SIGSEGV:
struct timespec tp;
*(&tp + 4096) = (struct timespec){0};
so does the following code:
struct timespec tp;
clock_gettime(CLOCK_MONOTONIC, &tp + 4096)
If the kernel always sends the signal,
Not really. If it so just happens that sizeof(struct timespec)
bytes starting from &tp + 4096
will not be inside protected memory region, the kernel will not send any signal, cause it would think, you write inside you own memory.
is it actually necessary to check whether errno equals EFAULT?
It's not necessary to check for any errors. I think you mix interpreting errors with checking for them. If you machine follows the specification you mentioned, if clock_gettime
returns EFAULT you can write your program so it assumes that the underlying implementation on your machine of clock_gettime
follows the linux manual page of clock_gettime
. However, as you discovered, it does not, instead undefined behaviour happens and the kernel raises SIGSEGV. Which only means that the underlying implementation of the clock_gettime
function does not follow the manual. The POSIX does not specify the EFAULT errno code. However I believe there may exists implementations which may return EFAULT errno or any other errno codes. However, what do you want your program to do when receiving EFAULT error? How to recover from such error? If these question bear any significance to you, then it may be reasonable to write an EFAULT handler for the clock_gettime
function.
Please note, you are using Linux. Linux, kernel and glibc, mostly are licensed under the GNU General License or GNU Lesser General License, which has the following in it:
BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE LIBRARY “AS IS” WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
The question bears down to trust: do you believe your system's clock_gettime()
to follow the Linux manual implementation? I don't. If your system would be POSIX certificate, you could place some more trust in the functions that they will work as the manual says. No one guarantees you that, it is just a good will of many hardworking people that it works.