Skip to content

Commit a2a6873

Browse files
committed
8205399: Set node color on pinned HashMap.TreeNode deletion
Backport-of: 51d0a9e1223f218d10f8761e38cd2dd478607040
1 parent 0944384 commit a2a6873

File tree

2 files changed

+176
-1
lines changed

2 files changed

+176
-1
lines changed

jdk/src/share/classes/java/util/HashMap.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2125,7 +2125,7 @@ else if (pr != null)
21252125
if (replacement != p) {
21262126
TreeNode<K,V> pp = replacement.parent = p.parent;
21272127
if (pp == null)
2128-
root = replacement;
2128+
(root = replacement).red = false;
21292129
else if (p == pp.left)
21302130
pp.left = replacement;
21312131
else
Lines changed: 175 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,175 @@
1+
/*
2+
* Copyright (c) 2018, Oracle and/or its affiliates. All rights reserved.
3+
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4+
*
5+
* This code is free software; you can redistribute it and/or modify it
6+
* under the terms of the GNU General Public License version 2 only, as
7+
* published by the Free Software Foundation.
8+
*
9+
* This code is distributed in the hope that it will be useful, but WITHOUT
10+
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
11+
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
12+
* version 2 for more details (a copy is included in the LICENSE file that
13+
* accompanied this code).
14+
*
15+
* You should have received a copy of the GNU General Public License version
16+
* 2 along with this work; if not, write to the Free Software Foundation,
17+
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
18+
*
19+
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
20+
* or visit www.oracle.com if you need additional information or have any
21+
* questions.
22+
*/
23+
24+
/**
25+
* @test
26+
* @bug 8205399
27+
* @summary Check for AssertionError from HashMap TreeBin after Iterator.remove
28+
* @run testng/othervm -esa TreeBinAssert
29+
*/
30+
31+
import org.testng.annotations.DataProvider;
32+
import org.testng.annotations.Test;
33+
import org.testng.annotations.BeforeTest;
34+
import java.util.Map;
35+
import java.util.Set;
36+
import java.util.Iterator;
37+
import java.util.HashMap;
38+
import java.util.LinkedHashSet;
39+
import java.util.function.BiConsumer;
40+
import java.util.function.Function;
41+
42+
public class TreeBinAssert {
43+
private static final int ITR_RM = -1; // Remove an item via Iterator
44+
private static final int BIN352442_SIZE = 524288;
45+
private static final int BIN552165_SIZE = 1048576;
46+
47+
@DataProvider(name = "SizeAndHashes")
48+
public Object[][] sizeAndHashes() {
49+
return new Object[][] {
50+
{ // Bin 352442
51+
BIN352442_SIZE,
52+
new int[] {
53+
2020958394,
54+
631595194,
55+
1984782522,
56+
419782842,
57+
285565114,
58+
1432182970,
59+
841310394,
60+
320692410,
61+
303390906,
62+
ITR_RM,
63+
ITR_RM,
64+
ITR_RM,
65+
ITR_RM,
66+
ITR_RM,
67+
ITR_RM,
68+
ITR_RM,
69+
ITR_RM,
70+
519397562,
71+
ITR_RM,
72+
626352314,
73+
101540026
74+
}
75+
},{ // Bin 552165
76+
BIN552165_SIZE,
77+
new int[] {
78+
790129893,
79+
1214803173,
80+
1212706021,
81+
608726245,
82+
2073586917,
83+
1433955557,
84+
692612325,
85+
370699493,
86+
2061004005,
87+
48786661,
88+
ITR_RM,
89+
ITR_RM,
90+
1418226917,
91+
ITR_RM,
92+
ITR_RM,
93+
ITR_RM,
94+
ITR_RM,
95+
ITR_RM,
96+
ITR_RM,
97+
ITR_RM,
98+
1487432933,
99+
ITR_RM,
100+
ITR_RM,
101+
1880648933,
102+
338193637
103+
}
104+
}
105+
};
106+
}
107+
108+
@BeforeTest
109+
public void checkAssertionStatus() {
110+
if (!HashMap.class.desiredAssertionStatus()) {
111+
System.out.println("*** Superficial test run. Test should be run with -esa ***\n");
112+
return;
113+
}
114+
}
115+
116+
@Test(dataProvider = "SizeAndHashes")
117+
public void testMap(int size, int[] hashes) {
118+
Map<Key,Integer> map = new HashMap<>(size);
119+
120+
doTest(map, hashes,
121+
(c,k) -> { ((Map<Key,Integer>)c).put(k,0); },
122+
(c) -> { return ((Map<Key,Integer>)c).keySet().iterator(); }
123+
);
124+
}
125+
126+
@Test(dataProvider = "SizeAndHashes")
127+
public void testSet(int size, int[] hashes) {
128+
Set<Key> set = new LinkedHashSet<>(size);
129+
130+
doTest(set, hashes,
131+
(c,k) -> { ((Set<Key>)c).add(k); },
132+
(c) -> { return ((Set<Key>)c).iterator(); }
133+
);
134+
}
135+
136+
private void doTest(Object collection, int[] hashes,
137+
BiConsumer<Object,Key> addKey,
138+
Function<Object,Iterator<Key>> mkItr) {
139+
Iterator<Key> itr = null; // saved iterator, used for removals
140+
for (int h : hashes) {
141+
if (h == ITR_RM) {
142+
if (itr == null) {
143+
itr = mkItr.apply(collection);
144+
}
145+
itr.next();
146+
itr.remove();
147+
} else {
148+
itr = null;
149+
addKey.accept(collection, new Key(h));
150+
}
151+
}
152+
}
153+
154+
/**
155+
* Class that will have specified hash code in a HashMap.
156+
*/
157+
static class Key implements Comparable<Key> {
158+
final int hash;
159+
160+
public Key(int desiredHash) {
161+
// Account for processing done by HashMap
162+
this.hash = desiredHash ^ (desiredHash >>> 16);
163+
}
164+
165+
@Override public int hashCode() { return this.hash; }
166+
167+
@Override public boolean equals(Object o) {
168+
return o.hashCode() == this.hashCode();
169+
}
170+
171+
@Override public int compareTo(Key k) {
172+
return Integer.compare(this.hash, k.hash);
173+
}
174+
}
175+
}

0 commit comments

Comments
 (0)