Skip to content

Commit

Permalink
Bug 581932 ArrayIndexOutOfBoundsException in ArrayIntCompressed
Browse files Browse the repository at this point in the history
on beforePass2 parsing

Fix and test possible bug on MAT collections when while using an
iterator doing a non-structural update to the collection

Task-Url: https://bugs.eclipse.org/bugs/show_bug.cgi?id=581932
Change-Id: Ife7a4bfa8c202f3a60dd61bd7e99b79ffdc77c28
  • Loading branch information
ajohnson1 committed May 25, 2023
1 parent 35f9efa commit 8a4b791
Show file tree
Hide file tree
Showing 9 changed files with 475 additions and 154 deletions.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2008, 2020 SAP AG and IBM Corporation.
* Copyright (c) 2008, 2023 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
Expand All @@ -14,6 +14,7 @@
package org.eclipse.mat.collect;

import java.io.Serializable;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

Expand Down Expand Up @@ -62,6 +63,7 @@ public interface Entry
private boolean[] used;
private int[] keys;
private long[] values;
private transient int mod;

/**
* Create a map of default size
Expand All @@ -88,12 +90,6 @@ public HashMapIntLong(int initialCapacity)
*/
public boolean put(int key, long value)
{
if (size == limit)
{
// Double in size but avoid overflow or JVM limits
resize(capacity <= BIG_CAPACITY >> 1 ? capacity << 1 : capacity < BIG_CAPACITY ? BIG_CAPACITY : capacity + 1);
}

int hash = hash(key);
while (used[hash])
{
Expand All @@ -104,11 +100,27 @@ public boolean put(int key, long value)
}
hash = step(hash);
}
if (size == limit)
{
// Double in size but avoid overflow or JVM limits
resize(capacity <= BIG_CAPACITY >> 1 ? capacity << 1 : capacity < BIG_CAPACITY ? BIG_CAPACITY : capacity + 1);
// Find the spot
hash = hash(key);
while (used[hash])
{
if (keys[hash] == key)
{
// Should never happen as we searched above, so must have been modified by another thread
throw new ConcurrentModificationException();
}
hash = step(hash);
}
}
used[hash] = true;
keys[hash] = key;
values[hash] = value;
size++;

mod++;
return false;
}

Expand Down Expand Up @@ -172,6 +184,7 @@ public boolean remove(int key)
values[newHash] = values[hash];
hash = step(hash);
}
mod++;
return true;
}
hash = step(hash);
Expand Down Expand Up @@ -258,6 +271,7 @@ public void clear()
{
size = 0;
used = new boolean[capacity];
mod++;
}

/**
Expand All @@ -270,6 +284,7 @@ public IteratorInt keys()
{
int n = 0;
int i = -1;
final int mod0 = mod;

public boolean hasNext()
{
Expand All @@ -278,6 +293,8 @@ public boolean hasNext()

public int next() throws NoSuchElementException
{
if (mod != mod0)
throw new ConcurrentModificationException();
while (++i < used.length)
{
if (used[i])
Expand All @@ -301,6 +318,7 @@ public IteratorLong values()
{
int n = 0;
int i = -1;
int mod0 = mod;

public boolean hasNext()
{
Expand All @@ -309,6 +327,8 @@ public boolean hasNext()

public long next() throws NoSuchElementException
{
if (mod != mod0)
throw new ConcurrentModificationException();
while (++i < used.length)
{
if (used[i])
Expand All @@ -332,6 +352,7 @@ public Iterator<Entry> entries()
{
int n = 0;
int i = -1;
final int mod0 = mod;

public boolean hasNext()
{
Expand All @@ -340,6 +361,8 @@ public boolean hasNext()

public Entry next() throws NoSuchElementException
{
if (mod != mod0)
throw new ConcurrentModificationException();
while (++i < used.length)
{
if (used[i])
Expand All @@ -349,11 +372,15 @@ public Entry next() throws NoSuchElementException
{
public int getKey()
{
if (mod != mod0)
throw new ConcurrentModificationException();
return keys[i];
}

public long getValue()
{
if (mod != mod0)
throw new ConcurrentModificationException();
return values[i];
}
};
Expand Down Expand Up @@ -422,6 +449,7 @@ private void resize(int newCapacity)
}
}
size = oldSize;
mod++;
}

/**
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
/*******************************************************************************
* Copyright (c) 2008, 2020 SAP AG and IBM Corporation.
* Copyright (c) 2008, 2023 SAP AG and IBM Corporation.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License 2.0
* which accompanies this distribution, and is available at
* https://www.eclipse.org/legal/epl-2.0/
*
* https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
Expand All @@ -18,6 +18,7 @@
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.lang.reflect.Array;
import java.util.ConcurrentModificationException;
import java.util.Iterator;
import java.util.NoSuchElementException;

Expand Down Expand Up @@ -55,14 +56,15 @@ public interface Entry<E>
* E.g. ArrayList has a limit of Integer.MAX_VALUE - 8
*/
private static final int BIG_CAPACITY = PrimeFinder.findPrevPrime(Integer.MAX_VALUE - 8 + 1) - 1;

private int capacity;
private int step;
private int limit;
private int size;
private transient boolean[] used;
private transient int[] keys;
private transient E[] values;
private transient int mod;

/**
* Create a map of default size
Expand All @@ -89,12 +91,6 @@ public HashMapIntObject(int initialCapacity)
*/
public E put(int key, E value)
{
if (size == limit)
{
// Double in size but avoid overflow or JVM limits
resize(capacity <= BIG_CAPACITY >> 1 ? capacity << 1 : capacity < BIG_CAPACITY ? BIG_CAPACITY : capacity + 1);
}

int hash = hash(key);
while (used[hash])
{
Expand All @@ -106,16 +102,34 @@ public E put(int key, E value)
}
hash = step(hash);
}
if (size == limit)
{
// Double in size but avoid overflow or JVM limits
resize(capacity <= BIG_CAPACITY >> 1 ? capacity << 1 : capacity < BIG_CAPACITY ? BIG_CAPACITY : capacity + 1);
// Find the spot
hash = hash(key);
while (used[hash])
{
if (keys[hash] == key)
{
// Should never happen as we searched above, so must have been modified by another thread
throw new ConcurrentModificationException();
}
hash = step(hash);
}
}
used[hash] = true;
keys[hash] = key;
values[hash] = value;
size++;
mod++;
return null;
}

private int step(int hash)
{
hash += step;
// Allow for overflow
if (hash >= capacity || hash < 0)
hash -= capacity;
return hash;
Expand Down Expand Up @@ -168,6 +182,7 @@ public E remove(int key)
values[newHash] = values[hash];
hash = step(hash);
}
mod++;
return oldValue;
}
hash = step(hash);
Expand Down Expand Up @@ -248,7 +263,7 @@ public Object[] getAllValues()
* Duplicate values are possible if they correspond to different keys.
* @param a an array of the right type for the output, which will be used
* if it is big enough, otherwise another array of this type will be allocated.
* @param <T> the type of object this HashMap can store.
* @param <T> the type of values held in this map.
* @return an array of the used values
*/
@SuppressWarnings("unchecked")
Expand Down Expand Up @@ -279,7 +294,7 @@ public int size()
}

/**
* Is the map empty
* Is the map empty?
* @return true if no current mappings
*/
public boolean isEmpty()
Expand All @@ -295,6 +310,7 @@ public void clear()
{
size = 0;
used = new boolean[capacity];
mod++;
}

/**
Expand All @@ -307,6 +323,7 @@ public IteratorInt keys()
{
int n = 0;
int i = -1;
final int mod0 = mod;

public boolean hasNext()
{
Expand All @@ -315,6 +332,8 @@ public boolean hasNext()

public int next() throws NoSuchElementException
{
if (mod != mod0)
throw new ConcurrentModificationException();
while (++i < used.length)
{
if (used[i])
Expand All @@ -338,6 +357,7 @@ public Iterator<E> values()
{
int n = 0;
int i = -1;
int mod0 = mod;

public boolean hasNext()
{
Expand All @@ -346,6 +366,8 @@ public boolean hasNext()

public E next() throws NoSuchElementException
{
if (mod != mod0)
throw new ConcurrentModificationException();
while (++i < used.length)
{
if (used[i])
Expand Down Expand Up @@ -374,6 +396,7 @@ public Iterator<Entry<E>> entries()
{
int n = 0;
int i = -1;
final int mod0 = mod;

public boolean hasNext()
{
Expand All @@ -382,6 +405,8 @@ public boolean hasNext()

public Entry<E> next() throws NoSuchElementException
{
if (mod != mod0)
throw new ConcurrentModificationException();
while (++i < used.length)
{
if (used[i])
Expand All @@ -391,11 +416,15 @@ public Entry<E> next() throws NoSuchElementException
{
public int getKey()
{
if (mod != mod0)
throw new ConcurrentModificationException();
return keys[i];
}

public E getValue()
{
if (mod != mod0)
throw new ConcurrentModificationException();
return values[i];
}
};
Expand Down Expand Up @@ -450,6 +479,7 @@ private void resize(int newCapacity)
}
}
size = oldSize;
mod++;
}

private void writeObject(ObjectOutputStream stream) throws IOException
Expand Down

0 comments on commit 8a4b791

Please sign in to comment.