]> source.dussan.org Git - jgit.git/commitdiff
BatchingProgressMonitor: avoid int overflow when computing percentage 35/199435/4
authorMatthias Sohn <matthias.sohn@sap.com>
Mon, 16 Jan 2023 20:58:56 +0000 (21:58 +0100)
committerMatthias Sohn <matthias.sohn@sap.com>
Tue, 31 Jan 2023 13:15:53 +0000 (14:15 +0100)
When cloning huge repositories I observed percentage of object counts
turning negative. This happened if lastWork * 100 exceeded
Integer.MAX_VALUE.

Change-Id: Ic5f5cf5a911a91338267aace4daba4b873ab3900

org.eclipse.jgit.test/tst/org/eclipse/jgit/lib/TextProgressMonitorTest.java [new file with mode: 0644]
org.eclipse.jgit/src/org/eclipse/jgit/lib/BatchingProgressMonitor.java

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 (file)
index 0000000..55ca2cd
--- /dev/null
@@ -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");
+       }
+}
index 2caefa4d9757167d6431f3d86440793549185163..49e295aed8d83a92b59b37a153e4a7a6137c350e 100644 (file)
@@ -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)