Linux 系统调用 time() 在错误时返回 ((time_t) -14)

Linux system call time() is returning ((time_t) -14) on error

手册页 man 2 time 说:

SYNOPSIS
       #include <time.h>
       time_t time(time_t *t);

RETURN VALUE
       On success, the value of time in seconds since  the  Epoch  is  returned.   On  error,
       ((time_t) -1) is returned, and errno is set appropriately.

ERRORS
       EFAULT t points outside your accessible address space.

我已经设置了一个简单的测试,试图从该函数强制错误 - 应该是有史以来最简单的事情:

time_t *ptr = (time_t *) 0xabad1dea;
time_t secs = time(ptr);

if (secs == ((time_t) -1)) /* Not caught */
    exit(EXIT_FAILURE);

printf("Number of seconds since the Epoch:        %lld\n", secs);
printf("It should return ((time_t) -1) on error:  %lld\n", (time_t) -1);
secs = *ptr; /* This *does* segfault */

出于某种原因,time() 在我的系统上 returning -14 而不是 -1。我完全被难住了。莫名其妙,甚至。

我怀疑任何人都可以重现这个问题,但是有人知道为什么我会出现这种行为吗?如果是这样,我很好奇!

编辑:我知道时间并没有取消引用我传递给它的错误指针,因为这会使程序崩溃。并且手册页确实说它应该 return -1 并且如果地址不可访问则设置 errno 。 EFAULT 是 14,但不是 returning -EFAULT not what time() is defined as doing here?

根据文档 time(2):

time_t time(time_t *t);

If t is non-NULL, the return value is also stored in the memory pointed to by t.

在您的调用中,您传递了一些随机地址 0xabad1dea。你很幸运,它只返回 -14 而没有做更糟糕的事情。传递 NULL 或变量的地址。

至少有 3 个不同的地方记录了 time() 函数的行为。

ISO C standard 说:

The time function returns the implementation’s best approximation to the current calendar time. The value (time_t)(-1) is returned if the calendar time is not available. If timer is not a null pointer, the return value is also assigned to the object it points to.

标准中的其他措辞清楚地表明传递无效参数(这就是您正在做的)具有未定义的行为。 time() 需要处理空指针,但不是无效指针。

POSIX says:

Upon successful completion, time() shall return the value of time. Otherwise, (time_t)-1 shall be returned.

不允许当前时间或 (time_t)(-1) 以外的结果。另一方面,POSIX 也表示:

The functionality described on this reference page is aligned with the ISO C standard. Any conflict between the requirements described here and the ISO C standard is unintentional. This volume of POSIX.1-2008 defers to the ISO C standard.

这可能意味着 time() 带有无效参数的行为是未定义的,就像在 C 中一样。

Linux 手册页说:

On success, the value of time in seconds since the Epoch is returned. On error, ((time_t) -1) is returned, and errno is set appropriately.

它还明确表示,如果“t 指向您的可访问地址 space 之外”,则 errno 设置为 EFAULT。因此它定义了标准未定义行为的情况下的行为,这对于实现来说是完全有效的事情。

奇怪的是它 returns -14 (-EFAULT) 而不是将 errno 设置为 EFAULT。返回取反的 errno 值是 Linux 内核 中函数 的常见约定。 C 运行时中的包装器通常会否定 return 值并使用它来设置 errno,将 return 值设置为 -1(或为特定功能)。这就是我希望在这里发生的事情。

另一件奇怪的事情:在我的系统上(Linux Mint 17,x86_64),像您一样使用无效指针调用 time() 导致我的程序因分段错误而死.

我怀疑您的系统存在错误(有一个特别简单的解决方法:不要那样做)。


更新: 我想到了另一种可能性。您的 printf 调用不正确,或者至少是不可移植的。您正在使用 "%lld" 格式打印 time_t 值,这需要类型为 long long 的参数。您应该将参数转换为 long long:

printf("Number of seconds since the Epoch:        %lld\n",
       (long long)secs);
printf("It should return ((time_t) -1) on error:  %lld\n",
       (long long)((time_t) -1));

如果 time_tlong long 在您的系统上是相同的宽度,它 可能 可以在没有转换的情况下工作(但无论如何您都应该添加它们) .但是,如果 time_tlong long 窄,printf 可能会从相邻内存中拾取杂散的 -14 值。

在您的系统上 time_tlong long 的大小是多少?转换参数会改变行为吗?