[pacman-dev] [PATCH] Fix divide by zero when downloading zero length files

Dan McGee dan at archlinux.org
Mon Aug 8 19:23:04 EDT 2011


If someone did a 'touch bogusrepo.db', we had the potential to throw a
SIGFPE or divide by zero, given that the total file size was 0 and
getting passed up to the pacman callback. Fix this so we get weird but
sane output and don't blow up when downloading:

:: Synchronizing package databases...
 core             35.7K  306.7K/s 00:00:00 [###################] 100%
 bogusrepo         0.0K    0.0K/s 00:00:00 [###################] 100%

Exception as seen in gdb:

Program received signal SIGFPE, Arithmetic exception.
0x000000000040cc73 in cb_dl_progress (filename=0x619dfc "bogusrepo.db", file_xfered=0, file_total=0) at callback.c:584
584             file_percent = (file_xfered * 100) / file_total;

Signed-off-by: Dan McGee <dan at archlinux.org>
---

This is for maint, where this can be easily reproduced by adding a file:// URL
to a zero-length database and running -Syy. It doesn't show up on master not
because the code is different, but because curl never even calls the callback
once on a zero length file, so we don't hit the problem.

-Dan

 src/pacman/callback.c |   25 +++++++++++++++++++------
 1 files changed, 19 insertions(+), 6 deletions(-)

diff --git a/src/pacman/callback.c b/src/pacman/callback.c
index 46ff2e8..68672b4 100644
--- a/src/pacman/callback.c
+++ b/src/pacman/callback.c
@@ -27,6 +27,7 @@
 #include <sys/types.h> /* off_t */
 #include <unistd.h>
 #include <wchar.h>
+#include <limits.h> /* UINT_MAX */
 
 #include <alpm.h>
 
@@ -561,10 +562,13 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total)
 		diff_sec = current_time.tv_sec - initial_time.tv_sec;
 		diff_usec = current_time.tv_usec - initial_time.tv_usec;
 		timediff = diff_sec + (diff_usec / 1000000.0);
-		rate = xfered / (timediff * 1024.0);
-
-		/* round elapsed time to the nearest second */
-		eta_s = (int)(timediff + 0.5);
+		if(timediff > 0.0) {
+			rate = xfered / (timediff * 1024.0);
+			/* round elapsed time to the nearest second */
+			eta_s = (unsigned int)(timediff + 0.5);
+		} else {
+			eta_s = 0;
+		}
 	} else {
 		/* compute current average values */
 		timediff = get_update_timediff(0);
@@ -576,12 +580,20 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total)
 		rate = (xfered - xfered_last) / (timediff * 1024.0);
 		/* average rate to reduce jumpiness */
 		rate = (rate + 2 * rate_last) / 3;
-		eta_s = (total - xfered) / (rate * 1024.0);
+		if(rate > 0.0) {
+			eta_s = (total - xfered) / (rate * 1024.0);
+		} else {
+			eta_s = UINT_MAX;
+		}
 		rate_last = rate;
 		xfered_last = xfered;
 	}
 
-	file_percent = (file_xfered * 100) / file_total;
+	if(file_total) {
+		file_percent = (file_xfered * 100) / file_total;
+	} else {
+		file_percent = 100;
+	}
 
 	if(totaldownload) {
 		total_percent = ((list_xfered + file_xfered) * 100) /
@@ -658,6 +670,7 @@ void cb_dl_progress(const char *filename, off_t file_xfered, off_t file_total)
 	}
 
 	/* 1 space + filenamelen + 1 space + 7 for size + 1 + 7 for rate + 2 for /s + 1 space + 8 for eta */
+	/* TODO: if eta_h > 99, formatting gets all messed up */
 	printf(" %ls%-*s %6.1f%c %#6.1f%c/s %02u:%02u:%02u", wcfname,
 			padwid, "", f_xfered, xfered_size,
 			rate, rate_size, eta_h, eta_m, eta_s);
-- 
1.7.6



More information about the pacman-dev mailing list