Skip to content

Commit c2ebd17

Browse files
prsadhukaivanov-jdk
andcommitted
6187113: DefaultListSelectionModel.removeIndexInterval(0, Integer.MAX_VALUE) fails
Co-authored-by: Alexey Ivanov <aivanov@openjdk.org> Reviewed-by: aivanov
1 parent 4bd3f0a commit c2ebd17

File tree

2 files changed

+111
-8
lines changed

2 files changed

+111
-8
lines changed

src/java.desktop/share/classes/javax/swing/DefaultListSelectionModel.java

+46-8
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
/*
2-
* Copyright (c) 1997, 2021, Oracle and/or its affiliates. All rights reserved.
2+
* Copyright (c) 1997, 2022, Oracle and/or its affiliates. All rights reserved.
33
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
44
*
55
* This code is free software; you can redistribute it and/or modify it
@@ -30,7 +30,9 @@
3030
import java.io.Serializable;
3131
import java.beans.Transient;
3232

33-
import javax.swing.event.*;
33+
import javax.swing.event.EventListenerList;
34+
import javax.swing.event.ListSelectionEvent;
35+
import javax.swing.event.ListSelectionListener;
3436

3537

3638
/**
@@ -334,7 +336,7 @@ The case (r < minIndex) is not possible because r'th value was set.
334336
We only need to check for the case when lowest entry has been cleared,
335337
and in this case we need to search for the first value set above it.
336338
*/
337-
if (r == minIndex) {
339+
if (r == minIndex && minIndex < Integer.MAX_VALUE) {
338340
for(minIndex = minIndex + 1; minIndex <= maxIndex; minIndex++) {
339341
if (value.get(minIndex)) {
340342
break;
@@ -449,6 +451,10 @@ private void changeSelection(int clearMin, int clearMax,
449451
if (shouldClear) {
450452
clear(i);
451453
}
454+
// Prevent Integer overflow
455+
if (i == Integer.MAX_VALUE) {
456+
break;
457+
}
452458
}
453459
fireValueChanged();
454460
}
@@ -640,28 +646,40 @@ private void setState(int index, boolean state) {
640646
* Otherwise leave them unselected. This method is typically
641647
* called to sync the selection model with a corresponding change
642648
* in the data model.
649+
*
650+
* @throws IndexOutOfBoundsException if either {@code index}
651+
* or {@code length} is negative
643652
*/
644653
public void insertIndexInterval(int index, int length, boolean before)
645654
{
655+
if (length < 0 || index < 0) {
656+
throw new IndexOutOfBoundsException("index or length is negative");
657+
}
658+
if (index == Integer.MAX_VALUE || length == 0) {
659+
// Nothing to update
660+
return;
661+
}
646662
/* The first new index will appear at insMinIndex and the last
647663
* one will appear at insMaxIndex
648664
*/
649665
int insMinIndex = (before) ? index : index + 1;
650-
int insMaxIndex = (insMinIndex + length) - 1;
666+
int insMaxIndex = (insMinIndex + length >= 0)
667+
? (insMinIndex + length) - 1
668+
: Integer.MAX_VALUE;
651669

652670
/* Right shift the entire bitset by length, beginning with
653671
* index-1 if before is true, index+1 if it's false (i.e. with
654672
* insMinIndex).
655673
*/
656-
for(int i = maxIndex; i >= insMinIndex; i--) {
674+
for(int i = Math.min(maxIndex, Integer.MAX_VALUE - length); i >= insMinIndex; i--) {
657675
setState(i + length, value.get(i));
658676
}
659677

660678
/* Initialize the newly inserted indices.
661679
*/
662680
boolean setInsertedValues = ((getSelectionMode() == SINGLE_SELECTION) ?
663681
false : value.get(index));
664-
for(int i = insMinIndex; i <= insMaxIndex; i++) {
682+
for(int i = insMaxIndex; i >= insMinIndex; i--) {
665683
setState(i, setInsertedValues);
666684
}
667685

@@ -686,18 +704,38 @@ public void insertIndexInterval(int index, int length, boolean before)
686704
* the selection model. This is typically called to sync the selection
687705
* model width a corresponding change in the data model. Note
688706
* that (as always) index0 need not be &lt;= index1.
707+
*
708+
* @throws IndexOutOfBoundsException if either index is negative
689709
*/
690710
public void removeIndexInterval(int index0, int index1)
691711
{
712+
if (index0 < 0 || index1 < 0) {
713+
throw new IndexOutOfBoundsException("index is negative");
714+
}
715+
692716
int rmMinIndex = Math.min(index0, index1);
693717
int rmMaxIndex = Math.max(index0, index1);
718+
719+
if (rmMinIndex == 0 && rmMaxIndex == Integer.MAX_VALUE) {
720+
for (int i = Integer.MAX_VALUE; i >= 0; i--) {
721+
setState(i, false);
722+
}
723+
724+
if (this.anchorIndex != -1 || this.leadIndex != -1) {
725+
updateLeadAnchorIndices(-1, -1);
726+
}
727+
return;
728+
}
729+
694730
int gapLength = (rmMaxIndex - rmMinIndex) + 1;
695731

696732
/* Shift the entire bitset to the left to close the index0, index1
697733
* gap.
698734
*/
699-
for(int i = rmMinIndex; i <= maxIndex; i++) {
700-
setState(i, value.get(i + gapLength));
735+
for (int i = rmMinIndex; i >= 0 && i <= maxIndex; i++) {
736+
setState(i, (i <= Integer.MAX_VALUE - gapLength)
737+
&& (i + gapLength >= minIndex)
738+
&& value.get(i + gapLength));
701739
}
702740

703741
int leadIndex = this.leadIndex;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
/*
2+
* Copyright (c) 2023, 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+
* @test
25+
* @bug 6187113
26+
* @summary Verifies if
27+
* DefaultListSelectionModel.removeIndexInterval(0, Integer.MAX_VALUE) fails
28+
* @run main TestDefListModelException
29+
*/
30+
import javax.swing.DefaultListSelectionModel;
31+
32+
public class TestDefListModelException {
33+
34+
public static void main(String[] args) throws Exception {
35+
test1();
36+
test2();
37+
test3();
38+
test4();
39+
}
40+
41+
private static void test1() {
42+
DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
43+
selectionModel.setSelectionInterval(0, 1);
44+
selectionModel.removeIndexInterval(0, Integer.MAX_VALUE);
45+
}
46+
47+
private static void test2() {
48+
DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
49+
selectionModel.setSelectionInterval(Integer.MAX_VALUE - 1, Integer.MAX_VALUE);
50+
selectionModel.removeIndexInterval(0, 1);
51+
}
52+
53+
private static void test3() {
54+
DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
55+
selectionModel.setSelectionInterval(Integer.MAX_VALUE - 2, Integer.MAX_VALUE - 1);
56+
selectionModel.removeIndexInterval(0, Integer.MAX_VALUE - 1);
57+
}
58+
59+
private static void test4() {
60+
DefaultListSelectionModel selectionModel = new DefaultListSelectionModel();
61+
selectionModel.setSelectionInterval(Integer.MAX_VALUE - 1, Integer.MAX_VALUE);
62+
selectionModel.insertIndexInterval(Integer.MAX_VALUE - 1, Integer.MAX_VALUE, true);
63+
}
64+
}
65+

0 commit comments

Comments
 (0)