mirror of
https://github.com/jenkinsci/jenkins.git
synced 2026-11-11 11:06:25 +00:00
[JENKINS-61841] Limit the number of exceptions stored by CompositeIOException
This commit is contained in:
1 parent
c0ce2c1781
commit
acb2ff00de
2 files changed
+88
-3
No files matched your search
@@ -30,19 +30,52 @@ import org.kohsuke.accmod.restrictions.NoExternalUse;
|
||||
import edu.umd.cs.findbugs.annotations.NonNull;
|
||||
import java.io.IOException;
|
||||
import java.io.UncheckedIOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
@Restricted(NoExternalUse.class)
|
||||
public class CompositeIOException extends IOException {
|
||||
private static final long serialVersionUID = 121943141387608148L;
|
||||
|
||||
/**
|
||||
* The maximum number of exceptions that can be reported by a single
|
||||
* {@code CompositeIOException}.
|
||||
* <p>
|
||||
* The number of exceptions is limited to avoid pathological cases where
|
||||
* where a huge number of exceptions could lead to excessive memory usage.
|
||||
* For example, if the number of exceptions was unlimited, a call to
|
||||
* {@code Util.deleteRecursive} could fail with a
|
||||
* {@code CompositeIOException} that contains an exception for every
|
||||
* single file inside of the directory.
|
||||
*/
|
||||
public static final int EXCEPTION_LIMIT = 10;
|
||||
|
||||
private final List<IOException> exceptions;
|
||||
|
||||
/**
|
||||
* Construct a new {@code CompositeIOException} where the given list of
|
||||
* exceptions are added as suppressed exceptions to the new exception.
|
||||
* <p>
|
||||
* If the given list of exceptions is longer than {@link #EXCEPTION_LIMIT},
|
||||
* the list will be truncated to that length, and an exception whose message
|
||||
* contains the number of exceptions that were removed will be added as a
|
||||
* suppressed exception to the new exception.
|
||||
*/
|
||||
public CompositeIOException(String message, @NonNull List<IOException> exceptions) {
|
||||
super(message);
|
||||
this.exceptions = exceptions;
|
||||
exceptions.forEach(this::addSuppressed);
|
||||
if (exceptions.size() > EXCEPTION_LIMIT) {
|
||||
this.exceptions = new ArrayList<>(exceptions.subList(0, EXCEPTION_LIMIT));
|
||||
this.exceptions.add(new ExceptionLimitReached(exceptions.size() - EXCEPTION_LIMIT));
|
||||
} else {
|
||||
this.exceptions = exceptions;
|
||||
}
|
||||
this.exceptions.forEach(this::addSuppressed);
|
||||
}
|
||||
|
||||
/**
|
||||
* @see CompositeIOException(String, List)
|
||||
*/
|
||||
public CompositeIOException(String message, IOException... exceptions) {
|
||||
this(message, Arrays.asList(exceptions));
|
||||
}
|
||||
@@ -54,4 +87,22 @@ public class CompositeIOException extends IOException {
|
||||
public UncheckedIOException asUncheckedIOException() {
|
||||
return new UncheckedIOException(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* An exception with no stack trace used to inform users that not all
|
||||
* exceptions are being reported.
|
||||
*/
|
||||
private static class ExceptionLimitReached extends IOException {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
public ExceptionLimitReached(int truncated) {
|
||||
super(truncated + " additional exceptions were thrown");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Throwable fillInStackTrace() {
|
||||
// Do not create a strack trace for this exception.
|
||||
return this;
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user