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

时间:2015-02-02 20:37:15

标签: c linux time system-calls

手册页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()在我的系统上返回-14而不是-1。我完全难过了。困惑,甚至。

我怀疑任何人都可以重现这个问题,但有人在那里知道为什么我可能会得到这种行为吗?如果是这样,我非常好奇!

编辑:我知道时间不会取消引用我传递它的错误指针,因为它会导致程序崩溃。手册页确实说它应该返回-1并设置errno,如果地址不可达。 EFAULT是14,但是没有返回-EFAULT 什么时间()被定义为在这里做?

2 个答案:

答案 0 :(得分:3)

根据文档time(2)

  
    
      

time_t time(time_t * t);

             

如果t为非NULL,则返回值也存储在t指向的内存中。

    
  

在通话中,您传递的是随机地址0xabad1dea。你很幸运,它只返回-14并且没有做更糟糕的事情。传递NULL或变量的地址。

答案 1 :(得分:1)

至少有3个差异点,其中记录了time()函数的行为。

ISO C standard说:

  

time 函数返回实现的最佳近似值   当前的日历时间。如果是,则返回值 (time_t)(-1)   日历时间不可用。如果 timer 不是空指针,则   返回值也分配给它指向的对象。

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

POSIX says

  

成功完成后,时间()将返回时间值。   否则,( time() ) - 1将被退回。

不允许除当前时间或time_t以外的结果。另一方面,POSIX也说:

  

此参考页面上描述的功能与   ISO C标准。此处描述的要求之间存在任何冲突   而ISO C标准是无意的。本卷POSIX.1-2008   遵循ISO C标准。

可以暗示(time_t)(-1)带有无效参数的行为未定义,就像在C中一样。

Linux手册页说:

  

成功时,返回自Epoch以来的秒数。   出错时,返回((time_t)-1),并正确设置errno。

如果&#34; time()指向您可访问的地址空间&#34;之外,它还明确表示errno设置为EFAULT。因此,它定义了行为未被标准定义的情况下的行为,并且这对于实现来说是完全有效的。

奇怪的是,它返回 t-14),而不是将-EFAULT设置为errno。返回否定的EFAULT值是Linux内核中函数的常见约定。 C运行时中的包装器通常会否定该返回值并使用它来设置errno,将返回值设置为errno(或者为特定函数定义的错误值)。这就是我期望在这里发生的事情。

另一个奇怪的事情:在我的系统(Linux Mint 17,x86_64)上,使用无效指针调用-1会导致我的程序死于分段错误。

我怀疑你的系统存在一个错误(特别容易的解决方法:不要这样做)。


更新:另一种可能性发生在我身上。您的time()来电不正确,或至少不便携。您以printf格式打印time_t值,这需要"%lld"类型的参数。您应该将参数强制转换为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_t在您的系统上具有相同的宽度,则可能在没有强制转换的情况下工作(但您仍应添加它们)。但如果long longtime_t更窄,long long可能会从相邻内存中获取迷路printf值。

系统中-14time_t的大小是多少?强制转换参数会改变行为吗?