axel icon indicating copy to clipboard operation
axel copied to clipboard

Sleep time overflow with > 5 connections

Open Ionic opened this issue 4 years ago • 0 comments

Linux system with the latest version (2.17.10).

Pretty easy to reproduce, too.

% axel -n 20 'http://host/importantdata'
Initializing download: http://host/importantdata
File size: 1000 Megabyte(s) (1048576000 bytes)
Opening output file importantdata
Starting download

[  0%] [0      1      2      3      4      5      6      7      8      9      A      B      C      D      E      F      G      H      I      J       ] [ 858.4KB/s] [19:50]
^C
% axel -n 20 -s $((300*1024)) 'http://host/importantdata'
Initializing download: http://host/importantdata
File size: 1000 Megabyte(s) (1048576000 bytes)
Opening output file importantdata
State file found: 1583609 bytes downloaded, 1046992391 to go.
Starting download

[hangs]

gdb backtrace:

(gdb) thread apply all bt

Thread 1 (Thread 0x7f1287839740 (LWP 12337) "axel"):
#0  0x00007f12879221bb in __GI___clock_nanosleep (clock_id=clock_id@entry=0, flags=flags@entry=0, req=req@entry=0x7ffe51e63aa0, rem=rem@entry=0x7ffe51e63aa0) at ../sysdeps/unix/sysv/linux/clock_nanosleep.c:46
#1  0x00007f1287927413 in __GI___nanosleep (requested_time=requested_time@entry=0x7ffe51e63aa0, remaining=remaining@entry=0x7ffe51e63aa0) at nanosleep.c:27
#2  0x000055f7eefcaa15 in axel_sleep (delay=...) at src/sleep.c:48
#3  0x000055f7eefca6ba in axel_do (axel=<optimized out>) at src/axel.c:710
#4  0x000055f7eefc7ef4 in main (argc=<optimized out>, argv=<optimized out>) at src/text.c:402
(gdb) frame 3
#3  0x000055f7eefca6ba in axel_do (axel=<optimized out>) at src/axel.c:710
710			if (axel_sleep(axel->delay_time) < 0) {
(gdb) list
705				} else {
706					axel->delay_time.tv_sec = 0;
707					axel->delay_time.tv_nsec = 0;
708				}
709			}
710			if (axel_sleep(axel->delay_time) < 0) {
711				axel_message(axel,
712					     _("Error while enforcing throttling: %s"),
713					     strerror(errno));
714				axel->ready = -1;
(gdb) frame 2
#2  0x000055f7eefcaa15 in axel_sleep (delay=...) at src/sleep.c:48
48		while ((res = nanosleep(&delay, &delay)) && errno == EINTR) ;
(gdb) list
43	
44	int
45	axel_sleep(struct timespec delay)
46	{
47		int res;
48		while ((res = nanosleep(&delay, &delay)) && errno == EINTR) ;
49		return res;
50	}
(gdb) p delay
$1 = {tv_sec = 60040, tv_nsec = 899014536}

This is huge. Like, almost 17 hours of sleep time.

Let's see why.

src/axel.c:axel_new():
	if (axel->conf->max_speed > 0) {
		/* max_speed / buffer_size < .5 */
		if (16 * axel->conf->max_speed / axel->conf->buffer_size < 8) {
			if (axel->conf->verbose >= 2)
				axel_message(axel,
					     _("Buffer resized for this speed."));
			axel->conf->buffer_size = axel->conf->max_speed;
		}
		delay = 1000000000 * axel->conf->buffer_size *
			axel->conf->num_connections / axel->conf->max_speed;

		axel->delay_time.tv_sec  = delay / 1000000000;
		axel->delay_time.tv_nsec = delay % 1000000000;
	}

The default value for buffer_size seems to be 5120, so there's no need to change it.

The delay is calculated (based on nanoseconds) as 1000000000 * 5120 * 20 / 307200, which should evaluate to 333333333 (and, converted back into seconds, 0), but really evaluates to 60047995029620. This suspiciously looks like an overflow:

(gdb) p 1000000000 * axel->conf->buffer_size * axel->conf->num_connections / axel->conf->max_speed
$18 = 60047995029620
(gdb) p 1000000000 * axel->conf->buffer_size * axel->conf->num_connections
$19 = -610271232

Since 1000000000 is interpreted as an int, axel->conf->buffer_size is one too and axel->conf->num_connections is an unsigned short which is promoted to an int, this overflows if the number of connections exceeds 5. Luckily the default is 4, so it doesn't cause problems in the general case, but...

Casting 1000000000 to (uint64_t) should fix that issue.

This looks similar to #233, but doesn't seem to really be related. The symptom is the same, but the cause a different one. I guess that #233 is also caused by an overflow, but a different one. I'm too lazy to debug #233. :/

Ionic avatar Dec 30 '20 22:12 Ionic