summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMatthias Sohn <matthias.sohn@sap.com>2023-01-16 21:58:56 +0100
committerMatthias Sohn <matthias.sohn@sap.com>2023-01-31 14:15:53 +0100
commit611412a05528ba5898cf948f4d3959f1fbc4170a (patch)
tree8cb5e2f67a265feb0af05d107ddfe92860d3a91f
parentcd3fc7a2995c06cf2425f51758094e039c938559 (diff)
downloadjgit-611412a05528ba5898cf948f4d3959f1fbc4170a.tar.gz
jgit-611412a05528ba5898cf948f4d3959f1fbc4170a.zip
BatchingProgressMonitor: avoid int overflow when computing percentage
When cloning huge repositories I observed percentage of object counts turning negative. This happened if lastWork * 100 exceeded Integer.MAX_VALUE. Change-Id: Ic5f5cf5a911a91338267aace4daba4b873ab3900
-rw-r--r--org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TextProgressMonitorTest.java83
-rw-r--r--org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java6
2 files changed, 86 insertions, 3 deletions
diff --git a/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TextProgressMonitorTest.java b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TextProgressMonitorTest.java
new file mode 100644
index 0000000000..55ca2cdea3
--- /dev/null
+++ b/org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TextProgressMonitorTest.java
@@ -0,0 +1,83 @@
+/*
+ * Copyright (C) 2023, SAP SE or an SAP affiliate company and others
+ *
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Distribution License v. 1.0 which is available at
+ * https://www.eclipse.org/org/documents/edl-v10.php.
+ *
+ * SPDX-License-Identifier: BSD-3-Clause
+ */
+package org.eclipse.jgit.lib;
+
+import java.io.ByteArrayOutputStream;
+import java.io.OutputStreamWriter;
+import java.io.UnsupportedEncodingException;
+import java.nio.charset.StandardCharsets;
+
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+
+public class TextProgressMonitorTest {
+
+ private TextProgressMonitor m;
+
+ private ByteArrayOutputStream buf;
+
+ @Before
+ public void setup() {
+ buf = new ByteArrayOutputStream();
+ m = new TextProgressMonitor(
+ new OutputStreamWriter(buf, StandardCharsets.UTF_8));
+ }
+
+ @Test
+ public void testSimple() throws Exception {
+ m.beginTask("task", 10);
+ for (int i = 0; i < 10; i++) {
+ m.update(1);
+ }
+ m.endTask();
+ Assert.assertArrayEquals(
+ new String[] { "", "task: 10% ( 1/10)",
+ "task: 20% ( 2/10)",
+ "task: 30% ( 3/10)",
+ "task: 40% ( 4/10)",
+ "task: 50% ( 5/10)",
+ "task: 60% ( 6/10)",
+ "task: 70% ( 7/10)",
+ "task: 80% ( 8/10)",
+ "task: 90% ( 9/10)",
+ "task: 100% (10/10)",
+ "task: 100% (10/10)\n" },
+ bufLines());
+ }
+
+ @Test
+ public void testLargeNumbers() throws Exception {
+ m.beginTask("task", 1_000_000_000);
+ for (int i = 0; i < 10; i++) {
+ m.update(100_000_000);
+ }
+ m.endTask();
+ Assert.assertArrayEquals(
+ new String[] { "",
+ "task: 10% ( 100000000/1000000000)",
+ "task: 20% ( 200000000/1000000000)",
+ "task: 30% ( 300000000/1000000000)",
+ "task: 40% ( 400000000/1000000000)",
+ "task: 50% ( 500000000/1000000000)",
+ "task: 60% ( 600000000/1000000000)",
+ "task: 70% ( 700000000/1000000000)",
+ "task: 80% ( 800000000/1000000000)",
+ "task: 90% ( 900000000/1000000000)",
+ "task: 100% (1000000000/1000000000)",
+ "task: 100% (1000000000/1000000000)\n" },
+ bufLines());
+ }
+
+ String[] bufLines() throws UnsupportedEncodingException {
+ String s = new String(buf.toString(StandardCharsets.UTF_8.name()));
+ return s.split("\r");
+ }
+}
diff --git a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java
index 2caefa4d97..49e295aed8 100644
--- a/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java
+++ b/org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java
@@ -176,7 +176,7 @@ public abstract class BatchingProgressMonitor implements ProgressMonitor {
}
} else {
// Display once per second or when 1% is done.
- int currPercent = lastWork * 100 / totalWork;
+ int currPercent = Math.round(lastWork * 100F / totalWork);
if (display) {
pm.onUpdate(taskName, lastWork, totalWork, currPercent);
output = true;
@@ -201,8 +201,8 @@ public abstract class BatchingProgressMonitor implements ProgressMonitor {
if (totalWork == UNKNOWN) {
pm.onEndTask(taskName, lastWork);
} else {
- int pDone = lastWork * 100 / totalWork;
- pm.onEndTask(taskName, lastWork, totalWork, pDone);
+ int currPercent = Math.round(lastWork * 100F / totalWork);
+ pm.onEndTask(taskName, lastWork, totalWork, currPercent);
}
}
if (timerFuture != null)