Skip to content

fix: replace IAE with IOException on byte array overflow#785

Merged
garydgregory merged 1 commit intomasterfrom
feat/io-exception-on-overflow
Sep 22, 2025
Merged

fix: replace IAE with IOException on byte array overflow#785
garydgregory merged 1 commit intomasterfrom
feat/io-exception-on-overflow

Conversation

@ppkarwasz
Copy link
Contributor

The method IOUtils#toByteArray(InputStream) previously threw an IllegalArgumentException when the number of bytes read exceeded what could be stored in a byte[].

This change updates the method to throw an IOException instead, which is more semantically appropriate for stream-reading failures. A dedicated test has been added to verify this behavior.

Before you push a pull request, review this list:

  • Read the contribution guidelines for this project.
  • Read the ASF Generative Tooling Guidance if you use Artificial Intelligence (AI).
  • I used AI to create the mocked unit test.
  • Run a successful build using the default Maven goal with mvn; that's mvn on the command line by itself.
  • Write unit tests that match behavioral changes, where the tests fail if the changes to the runtime are not applied. This may not always be possible, but it is a best-practice.
  • Write a pull request description that is detailed enough to understand what the pull request does, how, and why.
  • Each commit in the pull request should have a meaningful subject line and body. Note that a maintainer may squash commits during the merge process.

The method `IOUtils#toByteArray(InputStream)` previously threw an `IllegalArgumentException` when the number of bytes read exceeded what could be stored in a `byte[]`.

This change updates the method to throw an `IOException` instead, which is more semantically appropriate for stream-reading failures. A dedicated test has been added to verify this behavior.
@ppkarwasz ppkarwasz requested a review from Copilot September 22, 2025 11:33
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull Request Overview

This PR fixes the exception type thrown by IOUtils.toByteArray(InputStream) when the input stream size exceeds the maximum byte array length, changing from IllegalArgumentException to IOException for better semantic alignment with I/O operations.

  • Replace IllegalArgumentException with IOException when byte array overflow occurs
  • Update method documentation to reflect the exception type change
  • Add comprehensive test coverage for the overflow scenario using mocking

Reviewed Changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated 2 comments.

File Description
src/main/java/org/apache/commons/io/IOUtils.java Changes exception type from IllegalArgumentException to IOException and updates javadoc
src/test/java/org/apache/commons/io/IOUtilsTest.java Adds test case with mocking to verify IOException is thrown on overflow
src/changes/changes.xml Documents the bug fix in the changelog

Tip: Customize your code reviews with copilot-instructions.md. Create the file or learn how to get started.

Copy link
Member

@garydgregory garydgregory left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @ppkarwasz

I'm did a review for consistency. In git master, we have, eleven (11) IOUtils methods that throw IllegalArgumentException. Since the test in this method doesn't test the actual input arguments, it seems semantically OK to make this change. I just wanted to mention it since all other APIs in IOUtils throw IllegalArgumentException by explicitly testing their input arguments.

@garydgregory garydgregory merged commit fb917b5 into master Sep 22, 2025
20 of 21 checks passed
final UnsynchronizedByteArrayOutputStream output = copyToOutputStream(inputStream, SOFT_MAX_ARRAY_LENGTH + 1, DEFAULT_BUFFER_SIZE);
if (output.size() > SOFT_MAX_ARRAY_LENGTH) {
throw new IllegalArgumentException(String.format("Cannot read more than %,d into a byte array", SOFT_MAX_ARRAY_LENGTH));
throw new IOException(String.format("Cannot read more than %,d into a byte array", SOFT_MAX_ARRAY_LENGTH));
Copy link
Member

@garydgregory garydgregory Sep 22, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@ppkarwasz

Is it worth also testing

if (inputStream instanceof FileInputStream && ((FileInputStream) inputStream).getChannel().size() > SOFT_MAX_ARRAY_LENGTH`) {
    throw new IllegalArgumentException(...);
}

before we call copyToOutputStream() ?

The above would be justified in an IllegalArgumentException. WDYT? Is that too specific?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In my opinion IllegalArgumentException should be thrown for conditions that the caller is supposed to verify himself. Asking the user to verify this condition seems like a big requirement. @ecki, what do you think?

However, I think that:

  • We can add the condition as a fail-fast option and throw an IOException. The condition should be size() - position() > SOFT_MAX_ARRAY_LENGTH.
  • Depending on the remaining size of the FileInputStream, we can also use FileChannel.map() to map the remaining bytes into direct memory and then copy them into Java heap memory to a newly created byte[].
  • We could actually use this technique for all toByteArray methods. In this case, we should reword the toByteArray(InputStream, int, int) Javadoc to say that chunkSize is the maximum size of temporary byte arrays used to load the data.

@ppkarwasz ppkarwasz deleted the feat/io-exception-on-overflow branch September 23, 2025 05:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants

Comments