[ 
https://issues.apache.org/jira/browse/LANG-1814?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=18054373#comment-18054373
 ] 

Gary D. Gregory edited comment on LANG-1814 at 1/26/26 3:36 PM:
----------------------------------------------------------------

Good one [~iponomarev]!

Thank you for your report.

Are you planning to create a PR?

For better reading:
{code:java}
    @ParameterizedTest
    @CsvSource(value = { 
            // Normal operation
            "2, 1",
            // Overflowed to newSize == 1 (AIOOBE)
            "2147483647, -2147483648",
            // Overflowed to a large positive newSize (OOME)
            "2000000000, -2000000000" })
    void testNegativeEndAndHugeStartDoesNotOverflow(final int 
startIndexInclusive, final int endIndexExclusive) {
        final int[] array = { 1, 2, 3 };
        final int[] result = ArrayUtils.subarray(array, startIndexInclusive, 
endIndexExclusive);
        assertEquals(0, result.length);
    }
{code}


was (Author: garydgregory):
Good one [~iponomarev]!

Thank you for your report.

Are you planning to create a PR?

For better reading:
{code:java}
    @ParameterizedTest
    @CsvSource(value = { // Normal operation
            "2, 1",
            // Overflowed to newSize == 1 (AIOOBE)
            "2147483647, -2147483648",
            // Overflowed to a large positive newSize (OOME)
            "2000000000, -2000000000" })
    void testNegativeEndAndHugeStartDoesNotOverflow(final int 
startIndexInclusive, final int endIndexExclusive) {
        final int[] array = { 1, 2, 3 };
        final int[] result = ArrayUtils.subarray(array, startIndexInclusive, 
endIndexExclusive);
        assertEquals(0, result.length);
    }
{code}



> ArrayUtils.subarray(..) may overflow index arithmetic and violate contract 
> for extreme index values
> ---------------------------------------------------------------------------------------------------
>
>                 Key: LANG-1814
>                 URL: https://issues.apache.org/jira/browse/LANG-1814
>             Project: Commons Lang
>          Issue Type: Bug
>          Components: lang.*
>            Reporter: Ivan Ponomarev
>            Priority: Trivial
>
> {{ArrayUtils.subarray(.., int startIndexInclusive, int endIndexExclusive)}} 
> (the full family of overloads for different array types) is documented to 
> return an empty array when {{{}endIndexExclusive < startIndexInclusive{}}}:
> {quote}“Undervalue (< startIndex) produces empty array.”
> {quote}
> However, for certain extreme combinations of indices the method violates this 
> contract due to subtraction overflow in index arithmetic. After clamping:
>  * {{startIndexInclusive}} is promoted to {{>= 0}}
>  * {{endIndexExclusive}} is only clamped to {{{}<= array.length{}}}, but may 
> remain negative
> The method then computes:
>  
> {{final int newSize = endIndexExclusive - startIndexInclusive;}}
> This subtraction is performed in {{int}} and may overflow, turning a 
> logically negative size into a positive value. As a result, the method 
> attempts to allocate and/or copy an array instead of returning an empty 
> result.
> *Observed failure modes*
> Depending on the overflowed value and available heap size, this leads to:
>  * {{ArrayIndexOutOfBoundsException}} (small positive overflow, allocation 
> succeeds, copy fails)
>  * {{OutOfMemoryError}} (large positive overflow, allocation attempt fails)
> {{*Reproducer*}}
>    @ParameterizedTest
>     @CsvSource({
>             // Normal operation
>             "2, 1",
>             // Overflowed to newSize == 1 (AIOOBE)
>             "2147483647, -2147483648",
>             // Overflowed to a large positive newSize (OOME)
>             "2000000000, -2000000000"
>     })
>     void testNegativeEndAndHugeStartDoesNotOverflow(int startIndexInclusive, 
> int endIndexExclusive) {
>         int[] array = \{1, 2, 3};
>         int[] result = ArrayUtils.subarray(array, startIndexInclusive, 
> endIndexExclusive);
>         assertEquals(0, result.length);
>     }
> {{{{ }}}}
> {{{{{}(For all inputs where \{{{}endIndexExclusive < startIndexInclusive{}}}, 
> the method should return an empty array as documented, however, the method 
> may throw {{ArrayIndexOutOfBoundsException}} or {{OutOfMemoryError}} instead 
> of returning an empty array.)}}}}
> *Proposed Fix*
> For all {{ArrayUtils.subarray(..)}} overloads, ensure {{endIndexExclusive}} 
> is clamped to the same lower bound as {{startIndexInclusive}} before 
> subtraction:
>  
> {{endIndexExclusive = {*}max0{*}(Math.min(endIndexExclusive, array.length));}}
> {{int newSize = endIndexExclusive - startIndexInclusive; }}
> This guarantees:
>  * {{0 <= endIndexExclusive}} < {{array.length}}
>  * {{newSize}} cannot overflow
>  * {{newSize <= 0}} correctly triggers an empty array return
>  
>  



--
This message was sent by Atlassian Jira
(v8.20.10#820010)

Reply via email to