Call to Iterator.remove may fail¶
ID: java/iterator-remove-failureKind: problemSecurity severity: Severity: warningPrecision: mediumTags: - quality - reliability - correctnessQuery suites: - java-security-and-quality.qls
Click to see the query in the CodeQL repository
Theremove method of theIterator interface is an optional operation. It is not supported by iterators on unmodifiable collections, or iterators on lists constructed by theArrays.asList method. Invokingremove on such an iterator will lead to anUnsupportedOperationException.
Recommendation¶
If a collection is meant to be modified after construction, use a modifiable collection type such asArrayList orHashSet.
Example¶
In the following example, the constructorA(Integer...) initializes the fieldA.l toArrays.asList(is). While the type of lists returned byArrays.asList supports element updates through theset method, it does not support element removal. Hence the call toiter.remove on line 20 must fail at runtime.
importjava.util.Arrays;importjava.util.Iterator;importjava.util.List;publicclassA{privateList<Integer>l;publicA(Integer...is){this.l=Arrays.asList(is);}publicList<Integer>getList(){returnl;}publicstaticvoidmain(String[]args){Aa=newA(23,42);for(Iterator<Integer>iter=a.getList().iterator();iter.hasNext();)if(iter.next()%2!=0)iter.remove();}}
To avoid this failure, copy the list returned byArrays.asList into a newly createdArrayList like this:
importjava.util.Arrays;importjava.util.Iterator;importjava.util.List;importjava.util.ArrayList;publicclassA{privateList<Integer>l;publicA(Integer...is){this.l=newArrayList<Integer>(Arrays.asList(is));}publicList<Integer>getList(){returnl;}publicstaticvoidmain(String[]args){Aa=newA(23,42);for(Iterator<Integer>iter=a.getList().iterator();iter.hasNext();)if(iter.next()%2!=0)iter.remove();}}
References¶
Mark Needham:Java: Fooled by java.util.Arrays.asList.