My mistake it's ArraysSupport.newLength that's failing here,

String::replace

                pos = Arrays.copyOf(pos, ArraysSupport.newLength(p, 1, p >> 1));

newLength should be causing the exception but it in turn is passing the OOM 
size on to Arrays.copyOf

The logic in ArraysSupport::newLength is similar to that in the first part of 
this discussion:

    public static int newLength(int oldLength, int minGrowth, int prefGrowth) {
        // assert oldLength >= 0
        // assert minGrowth > 0

        int newLength = Math.max(minGrowth, prefGrowth) + oldLength;
        if (newLength - MAX_ARRAY_LENGTH <= 0) {
            return newLength;
        }
        return hugeLength(oldLength, minGrowth);
    }

    private static int hugeLength(int oldLength, int minGrowth) {
        int minLength = oldLength + minGrowth;
        if (minLength < 0) { // overflow
            throw new OutOfMemoryError("Required array length too large");
        }
        if (minLength <= MAX_ARRAY_LENGTH) {
            return MAX_ARRAY_LENGTH;
        }
        return Integer.MAX_VALUE;
    }

That is, pass Integer.MAX_VALUE on to the allocator and let it fail.


> On Jun 1, 2020, at 8:56 AM, Jim Laskey <james.las...@oracle.com> wrote:
> 
> In the same light the test in String::replace
> 
>        int resultLen;
>        try {
>            resultLen = Math.addExact(valLen,
>                    Math.multiplyExact(++p, replLen - targLen));
>        } catch (ArithmeticException ignored) {
>            throw new
>            OutOfMemoryError("String resulting from replace exceeds maximum 
> string size");
>        }
> 
> Is useless in this situation (from the bug report):
> 
>        int missingToIntMax = 10;
>        String tooLarge = "a".repeat(Integer.MAX_VALUE - missingToIntMax);
>        tooLarge.replace("a", "a".repeat(missingToIntMax + 2));
> 
> The replace "test" does not fail and the exception comes from further down 
> the stack:
> 
> Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
>       at java.base/java.util.Arrays.copyOf(Arrays.java:3584)
>       at java.base/java.lang.StringLatin1.replace(StringLatin1.java:349)
>       at java.base/java.lang.String.replace(String.java:2173)
>       at JI9062163.main(JI9062163.java:6)
> 
> 
> 
> 
>> On May 31, 2020, at 10:15 PM, Martin Buchholz <marti...@google.com> wrote:
>> 
>> I'm still not deeply reading the code in java.nio but I see in
>> AbstractStringBuilder
>> 
>>    * Will not return a capacity greater than
>>    * {@code (MAX_ARRAY_SIZE >> coder)} unless the given minimum capacity
>>    * is greater than that.
>> 
>> My intent was that a garden variety grow method would first grow to
>> MAX_ARRAY_SIZE, then to Integer.MAX_VALUE.
>> 
>> (this doesn't always work, e.g. hash tables want to have a
>> power-of-two sized backing array)
>> 
>> (these methods have evolved recently without much help from me)
>> 
>> (Library code should know as little about VM implementation
>> idiosyncrasies as possible)
>> 
>> On Sun, May 31, 2020 at 5:56 PM David Holmes <david.hol...@oracle.com> wrote:
>>> 
>>> On 1/06/2020 9:52 am, Martin Buchholz wrote:
>>>> On Sun, May 31, 2020 at 4:35 PM David Holmes <david.hol...@oracle.com> 
>>>> wrote:
>>>> 
>>>>> Not sure how we could have minCapacity < 0 at this point. It should have
>>>>> been checked before the call to grow, and grow will not make it negative.
>>>> 
>>>> At least some of the grow methods were designed so that callers did
>>>> not have to do the checking, and grow would interpret negative values
>>>> as int overflow
>>>> 
>>>>>> It just seems that it's pushing the inevitable off to Arrays.copyOf.  
>>>>>> Shouldn't it be:
>>>>>> 
>>>>>>     private static int hugeCapacity(int minCapacity) {
>>>>>>         if (minCapacity < 0 || minCapacity > MAX_ARRAY_SIZE) {
>>>>>>             throw
>>>>>>                 new OutOfMemoryError("ByteArrayChannel exceeds maximum 
>>>>>> size: " +
>>>>>>                                       MAX_ARRAY_SIZE);
>>>>>>         }
>>>>>> 
>>>>>>         return MAX_ARRAY_SIZE;
>>>>>>     }
>>>>> 
>>>>> That seems more appropriate to me - modulo the question mark over
>>>>> minCapacity being negative.
>>>> 
>>>> Again, the original design was to allow a capacity with MAX_ARRAY_SIZE
>>>> < capacity <= Integer.MAX_VALUE if and when the VM also allowed it.
>>> 
>>> The only way to know that is to try and create the array, catch the OOME
>>> and then adjust the value used. None of the code does that so I can't
>>> see how your claim here can be correct. My understanding, having been on
>>> the VM side, was that Hotspot's internal limits were reflected on the
>>> Java side so that the Java code could avoid the VM exception.
>>> 
>>> David
> 

Reply via email to