JDK-8046085 : HashMap.put with null key may throw NullPointerException
  • Type: Bug
  • Component: core-libs
  • Sub-Component: java.util:collections
  • Affected Version: 8
  • Priority: P2
  • Status: Closed
  • Resolution: Fixed
  • OS: generic
  • CPU: generic
  • Submitted: 2014-06-05
  • Updated: 2015-10-14
  • Resolved: 2014-06-06
The Version table provides details related to the release that this issue/RFE will be addressed.

Unresolved : Release in which this issue/RFE will be addressed.
Resolved: Release in which this issue/RFE has been resolved.
Fixed : Release in which this issue/RFE has been fixed. The release containing this fix may be available for download as an Early Access Release or a General Availability Release.

To download the current JDK release, click here.
JDK 8 JDK 9
8u20Fixed 9 b19Fixed
Description
FULL PRODUCT VERSION :
java version "1.8.0_05"
Java(TM) SE Runtime Environment (build 1.8.0_05-b13)
Java HotSpot(TM) Client VM (build 25.5-b02, mixed mode, sharing)

ADDITIONAL OS VERSION INFORMATION :
Microsoft Windows [Version 6.1.7601]

A DESCRIPTION OF THE PROBLEM :
Changes to improve HashMap performance in Java 8 can cause HashMap.put() with a null key to throw a NullPointerException.  This problem did not occur in Java 7.

Caused by: java.lang.NullPointerException
    at java.util.HashMap$TreeNode.putTreeVal(HashMap.java:1970)
    at java.util.HashMap.putVal(HashMap.java:637)
    at java.util.HashMap.put(HashMap.java:611)

It looks like the line of code in question is
else if ((pk = p.key) == k || (pk != null && k.equals(pk)))

Probably k.equals(pk) is source of the NullPointerException where k is null.
Possibly fix is change it to pk.equals(k).


REGRESSION.  Last worked in version 7u17

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Problem occurs on continuous build machine during unit test.  Unit test is parsing XML and custom ContentHandler is saving data to a HashMap.

/* HashMap for saving parsed data */
    private static final ThreadLocal contextMap = new ThreadLocal() {
        protected Object initialValue() {
            return new HashMap();
        }
    };

/* Insertion of data into HashMap */
    Map map = (Map) contextMap.get();
    map.put(key, value);

Problem has not occurred on development machine with limited testing, but consistently fails on build machine.


ERROR MESSAGES/STACK TRACES THAT OCCUR :
Caused by: java.lang.NullPointerException
    at java.util.HashMap$TreeNode.putTreeVal(HashMap.java:1970)
    at java.util.HashMap.putVal(HashMap.java:637)
    at java.util.HashMap.put(HashMap.java:611)


REPRODUCIBILITY :
This bug can be reproduced often.

CUSTOMER SUBMITTED WORKAROUND :
Check if key or value is not null, then insert into map.


Comments
HashMap.java source is the same in JDK 8 and 8u5 so resetting affected version to 8.
14-10-2015

webrev posted http://cr.openjdk.java.net/~mduigou/JDK-8046085/0/webrev/ RFR posted to corelibs-dev
06-06-2014

I will propose the obvious patch today along with a test.
06-06-2014

I agree with Paul's comment. The find method appears to be right, it seems to be just putTreeVal where it checks pk instead of k. This one is important to fix in the next 8 update if we can. It needs to be fixed in 9 first of course.
06-06-2014

This occurs when the hash of a key maps to a tree in the entry table, rather than a linked list i.e. when there are a high number of collisions. I think there was most likely a typo, the code at line 1970 in java.util.HashMap$TreeNode.putTreeVal should be: else if ((pk = p.key) == k || (k != null && k.equals(pk))) All other relevant equality code was checked and looks correct. Better null key tests are required.
06-06-2014

Paul: Thanks; yes, definitely a typo..
06-06-2014