Bug 18909 - select(2) timeout limited to 100000000 seconds
Summary: select(2) timeout limited to 100000000 seconds
Status: Closed FIXED
Alias: None
Product: Base System
Classification: Unclassified
Component: kern (show other bugs)
Version: 3.4-RELEASE
Hardware: Any Any
: Normal Affects Only Me
Assignee: freebsd-bugs (Nobody)
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2000-05-30 21:50 UTC by Archie Cobbs
Modified: 2017-08-09 18:30 UTC (History)
1 user (show)

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Archie Cobbs 2000-05-30 21:50:00 UTC
	select(2) returns EINVAL if the timeout is specified for
	longer than 100000000 seconds.

	Is this according to some specification? If so, nevermind,
	but please document this limitation in the man page. As it
	stands, there's nothing in the man page that indicates there
	is such an arbitrary limitation.

	Otherwise, it should support up to the maximum possible value
	that can be specified in a struct timeval.

Fix: 

Either allow all valid struct timeval's, or else please
	document this shortcoming in the man page.
How-To-Repeat: 
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/time.h>
#include <unistd.h>
#include <string.h>
#include <err.h>

void
main(int ac, char *av[]) {
	struct timeval tv;
	fd_set fds;
	int r;

	switch (ac) {
	default:
		errx(1, "usage: xx [secs]");
	case 2:
		tv.tv_sec = strtol(av[1], 0, NULL);
		break;
	case 1:
		tv.tv_sec = 100000001;
		break;
	}
	tv.tv_usec = 0;

	FD_ZERO(&fds);
	FD_SET(0, &fds);

	r = select(1, &fds, NULL, NULL, &tv);
	if (r < 0)
		err(1, "select");
}
Comment 1 dwmalone 2000-05-30 23:15:20 UTC
Here is what "The Single UNIX  Specification, Version 2" that I
downloaded about a year ago says:

     Implementations may place limitations on the maximum timeout
     interval supported. On all implementations, the maximum timeout
     interval supported will be at least 31 days. If the timeout
     argument specifies a timeout interval greater than the
     implementation-dependent maximum value, the maximum value will be
     used as the actual timeout value. Implementations may also place
     limitations on the granularity of timeout intervals. If the
     requested timeout interval requires a finer granularity than the
     implementation supports, the actual timeout interval will be
     rounded up to the next supported value.

So it looks the implimentation doesn't agree with this, and the
man page should probably say what the max timeout is.

(Excerpt is from http://www.opennc.org/onlinepubs/7908799/xsh/select.html).

	David.
Comment 2 Bruce Evans 2000-05-31 07:58:20 UTC
Everything that is implemented using itimers has this limit.  The limit
is only documented explicitly in setitimer.2, alarm.3 and ualarm.3.

The possible existence of a limit is documented in select.2:

     [EINVAL]		The specified time limit is invalid.  One of its com-
			ponents is negative or too large.

Saying exactly which values are too large in the man page wouldn't be very
useful.  Programs (sic) would have to read the man page to determine the
limit, since it would be machine-dependent.  A limit reported by sysconf(2)
would be more useful, but there is no standard for this.

The limit of 10^8 seconds is imposed to reduce the chance of overflows
in computations involving itimers.  Note that timeouts of 10^8 seconds
don't actually work, at least for select().  10^8 seconds is 1157+
days, by the default configuration of HZ = 100, timeouts in 32-bit
ticks are limited to only 248+ days.  If you increase HZ to 10^5 then
you may even notice this bug :-).

On Tue, 30 May 2000, Kelly Yancey wrote:

> On Tue, 30 May 2000, David Malone wrote:

> >  Here is what "The Single UNIX  Specification, Version 2" that I
> >  downloaded about a year ago says:
> >  
> >       Implementations may place limitations on the maximum timeout
> >       interval supported. On all implementations, the maximum timeout
> >       interval supported will be at least 31 days. If the timeout

Setting HZ to More than about 800 will break this.  There are many possible
problems like this, so nonstandard values of HZ aren't really supported.

> >       argument specifies a timeout interval greater than the
> >       implementation-dependent maximum value, the maximum value will be
> >       used as the actual timeout value. Implementations may also place
> >       limitations on the granularity of timeout intervals. If the
> >       requested timeout interval requires a finer granularity than the
> >       implementation supports, the actual timeout interval will be
> >       rounded up to the next supported value.
> >  
> >  So it looks the implimentation doesn't agree with this, and the
> >  man page should probably say what the max timeout is.
> >  
> >  (Excerpt is from http://www.opennc.org/onlinepubs/7908799/xsh/select.html).
> >  
> 
>   I read this to say that returning EINVAL (as reported in the submitted
> PR) is the Wrong Thing and that we should be rounding the interval down
> instead. The culprit is kern_time.c:itimerfix which is called by select,

I read this as a bug in the SUS :-).  The easiest workaround is to not
have a limit.  It seems to be easy to fix for select() and poll(), since
there is already a loop where we check after some wakeups to see if the
timeout expired (see old fixes for this problem in nanosleep()).

>   So someone more wise will definately need to review this (simple) patch
> as it may have far-reaching affects.

It affects setitimer(), etc.  The SUS requires setitimer() and alarm() to
handle the full interval.  POSIX requires this for alarm() IIRC.

Bruce
Comment 3 dwmalone 2000-06-07 22:37:57 UTC
> Everything that is implemented using itimers has this limit.  The limit
> is only documented explicitly in setitimer.2, alarm.3 and ualarm.3.

Unless I'm mistaken, select (and poll and the kevent stuff) don't
actually have anything to do with itimers, as the implementation
of their timeouts is with tsleep, which uses timeout, which uses
callouts. They are just borrowing the itimerfix() function for
a use for which it wasn't intended?

Probably what is needed is a timevalisvalid() function. There is
already a (static) timevalfix() function, however it doesn't do
what is required here.

> The limit of 10^8 seconds is imposed to reduce the chance of overflows
> in computations involving itimers.  Note that timeouts of 10^8 seconds
> don't actually work, at least for select().  10^8 seconds is 1157+
> days, by the default configuration of HZ = 100, timeouts in 32-bit
> ticks are limited to only 248+ days.  If you increase HZ to 10^5 then
> you may even notice this bug :-).

I guess this means that itimerfix should really say something like:

-        if (tv->tv_sec < 0 || tv->tv_sec > 100000000 ||
+        if (tv->tv_sec < 0 || tv->tv_sec/hz > 1000000 ||
             tv->tv_usec < 0 || tv->tv_usec >= 1000000)

to avoid problems on such systems?

> I read this as a bug in the SUS :-).  The easiest workaround is to not
> have a limit.  It seems to be easy to fix for select() and poll(), since
> there is already a loop where we check after some wakeups to see if the
> timeout expired (see old fixes for this problem in nanosleep()).

> It affects setitimer(), etc.  The SUS requires setitimer() and alarm() to
> handle the full interval.  POSIX requires this for alarm() IIRC.

I'd be interested in trying to fix this, and really just need more
info on how timevals should be handeled. Is adding a timevalisvalid()
function/macro reasonable? How should negative timevals be represented?
Is -1.5s written as:

	tv_sec = -2; tv_usec = 500000;
or	tv_sec = -1; tv_usec = -500000;

I'd presume it is the first, but you never can tell.

	David.
Comment 4 Bruce Evans 2000-06-08 09:31:18 UTC
On Wed, 7 Jun 2000, David Malone wrote:

> > Everything that is implemented using itimers has this limit.  The limit
> > is only documented explicitly in setitimer.2, alarm.3 and ualarm.3.
> 
> Unless I'm mistaken, select (and poll and the kevent stuff) don't
> actually have anything to do with itimers, as the implementation
> of their timeouts is with tsleep, which uses timeout, which uses
> callouts. They are just borrowing the itimerfix() function for
> a use for which it wasn't intended?

I think it was intended.  For both itimers and select(), the value of
timeout()'s `tick' arg was once calculated using hzto().  This involved
a timevaladd() of the current time to a timeout.  It was important
that the addition doesn't overflow.  This was arranged by limiting
the timeout.  32-bit signed time_t's will overflow in 2038, and timeouts
of 10^8 would have started overflowing things in 2035.

FreeBSD now uses tvtohz() instead of hzto(), so the limit of 10^8 is
no longer very appropriate for either itimers or select().  A limit
of (timeval when time_t's overflow) - (current time) would be about
right.  It would be better to have no limit until the current time
actually overflows time_t (which won't happen becauase either time_t
or the code will be changed before then), but this may require more
changes to avoid overflow in intermediate computations.

> I'd be interested in trying to fix this, and really just need more
> info on how timevals should be handeled. Is adding a timevalisvalid()
> function/macro reasonable? How should negative timevals be represented?
> Is -1.5s written as:
> 
> 	tv_sec = -2; tv_usec = 500000;
> or	tv_sec = -1; tv_usec = -500000;
> 
> I'd presume it is the first, but you never can tell.

The first is enforced in various places.

Bruce
Comment 5 dwmalone freebsd_committer freebsd_triage 2000-07-11 12:43:05 UTC
Responsible Changed
From-To: freebsd-bugs->dwmalone

I'm interested in this one.
Comment 6 Eitan Adler freebsd_committer freebsd_triage 2012-07-10 04:41:37 UTC
Responsible Changed
From-To: dwmalone->freebsd-bugs

over to the pool (approved by bugmeister)
Comment 7 Eugene Grosbein freebsd_committer freebsd_triage 2017-08-09 18:30:00 UTC
FreeBSD 11.1/i386 does not have this problem anymore. That is, select(2) does not return EINVAL if a timeout is specified for longer than 100000000 seconds. 

Close this after 17 years.