Uploaded image for project: 'JDK'
  1. JDK
  2. JDK-8186171

HashMap: Entry.setValue may not work after Iterator.remove() called for previous entries

    Details

    • Subcomponent:
    • Resolved In Build:
      b26
    • CPU:
      generic
    • OS:
      generic
    • Verification:
      Verified

      Backports

        Description

        FULL PRODUCT VERSION :
        java version "1.8.0_144"
        Java(TM) SE Runtime Environment (build 1.8.0_144-b01)
        Java HotSpot(TM) 64-Bit Server VM (build 25.144-b01, mixed mode)

        A DESCRIPTION OF THE PROBLEM :
        Javadoc allows to use Iterator.remove() and Entry.setValue() when iterating over HashMap:
        "If the map is modified while an iteration over the set is in progress (except through the iterator's own remove operation, or through the setValue operation on a map entry returned by the iterator) the results of the iteration are undefined."

        However it's possible that setValue() doesn't work if remove() was called for some of previous entries. It may happen when remove() leads to untreeify() call - some TreeNodes are replaced by Nodes, but iterator continues to iterate over old instances hence setValue changes the value in the replaced node. (Test case attached)

        REGRESSION. Last worked in version 7u80


        REPRODUCIBILITY :
        This bug can be reproduced always.
        JDK-8186171
        ---------- BEGIN SOURCE ----------
        import java.util.*;

        public class Main {
            static class Key {
                @Override
                public int hashCode() {
                    return 0; // to put keys in one bucket
                }
            }
            public static void main(String[] args) {
                List<Key> keys = new ArrayList<>();
                for (int i = 0; i < 11; ++i) { // 11 is big enough for a map to use tree nodes
                    keys.add(new Key());
                }
                Map<Object, Object> data = Collections.singletonMap(keys.get(10), 1);

                Map<Object, Object> result = new HashMap<>();
                for (Object key : keys) {
                    result.put(key, null);
                }

                for (Iterator<Map.Entry<Object, Object>> iter = result.entrySet().iterator(); iter.hasNext();) {
                    Map.Entry<Object, Object> entry = iter.next();
                    Object value = data.get(entry.getKey());
                    if (value == null) {
                        iter.remove();
                    } else {
                        entry.setValue(value); // this call doesn't set the value
                    }
                }

                if (result.containsValue(null)) {
                    System.out.println("FAILED");
                } else {
                    System.out.println("OK");
                }
            }
        }
        ---------- END SOURCE ----------

          Attachments

            Issue Links

              Activity

                People

                • Assignee:
                  martin Martin Buchholz
                  Reporter:
                  webbuggrp Webbug Group
                • Votes:
                  0 Vote for this issue
                  Watchers:
                  6 Start watching this issue

                  Dates

                  • Created:
                    Updated:
                    Resolved: