JDK-8149450 : LdapCtx.processReturnCode() throwing Null Pointer Exception
  • Type: Bug
  • Component: core-libs
  • Sub-Component: javax.naming
  • Affected Version: 7u72,8,9
  • Priority: P3
  • Status: Closed
  • Resolution: Fixed
  • OS: solaris_10
  • CPU: x86_64
  • Submitted: 2015-09-30
  • Updated: 2019-04-23
  • Resolved: 2016-04-11
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 7 JDK 8 JDK 9 Other
7u101Fixed 8u102Fixed 9 b114Fixed openjdk7uFixed
Related Reports
Duplicate :  
Relates :  
Sub Tasks
JDK-8154474 :  
Description
FULL PRODUCT VERSION :
java version "1.7.0_72"
Java(TM) SE Runtime Environment (build 1.7.0_72-b14)
Java HotSpot(TM) Server VM (build 24.72-b04, mixed mode)


ADDITIONAL OS VERSION INFORMATION :
SunOS n3 5.10 Generic_150401-18 i86pc i386 i86pc


A DESCRIPTION OF THE PROBLEM :
When an LDAP response is received with status of LdapClient.LDAP_REFERRAL but no referrals are present (and handleReferrals is set to LDAP_REF_THROW), the following exception is received:

java.lang.NullPointerException
        at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2930)
        at com.sun.jndi.ldap.LdapCtx.processReturnCode(LdapCtx.java:2840)
        at com.sun.jndi.ldap.LdapNamingEnumeration.getNextBatch(LdapNamingEnumeration.java:147)
        at com.sun.jndi.ldap.LdapNamingEnumeration.hasMoreImpl(LdapNamingEnumeration.java:216)
        at com.sun.jndi.ldap.LdapNamingEnumeration.hasMore(LdapNamingEnumeration.java:189)

Looking at the source for LdapCtx, res.referrals.elementAt(0) is invoked without first testing that res.referrals is not null. Yes, this is technically an invalid LDAP message, but invalid messages should not result in null pointer exceptions in the stack.

STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Here is our code snippet that calls into search():

        NamingEnumeration<SearchResult> enumeration = null;

        try
        {
            setInterruptible(true);
            scheduleInterruptTimerTask(timer, interruptTimerTask, interruptTimeLimit);

            enumeration = ldapContext.search(ldapSearchArguments.getDn(), ldapSearchArguments.getFilter(),
                    searchControls);

            SearchResult searchResult;

            while (enumeration.hasMore())
            {
                searchResult = enumeration.next();
                returnedAttributes.add(searchResult.getAttributes());
            }
        }
        finally
        {
            cancelInterruptTimerTaskAndSetUnInterruptible(interruptTimerTask);
            closeEnumeration(enumeration);
        }

As mentioned in the Description, the LDAP response has a status of LdapClient.LDAP_REFERRAL but no referrals are present in the message.

EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
The stack should be throwing some kind of NamingException rather than a null pointer exception.
ACTUAL -
See stack trace in Description.

ERROR MESSAGES/STACK TRACES THAT OCCUR :
See stack trace in Description.

REPRODUCIBILITY :
This bug can be reproduced always.

CUSTOMER SUBMITTED WORKAROUND :
We currently have to ignore referrals until this bug is fixed (i.e. handleReferrals is set to LDAP_REF_IGNORE).


Comments
The JDK was involved in processing an LDAPResult when a null pointer was encountered for the referral field. The LDAP reply BER signaled that the LDAP operation was a result code of LDAP_REFERRAL (value 10) - For a valid referral result, a list of URIs should be provided in the result to indicate what servers might contain the necessary results. See RFC section 4.1.10 : https://tools.ietf.org/html/rfc4511#section-4.1.10 > The referral field is present in an LDAPResult if the resultCode is > set to referral, and it is absent with all other result codes. It > contains one or more references to one or more servers or services > that may be accessed via LDAP or other protocols. Referrals can be > returned in response to any operation request (except Unbind and > Abandon, which do not have responses). At least one URI MUST be > present in the Referral. For some reason, the LDAP server in this scenario has given this field as null. Is it non-compliant ?The JDK is now set up to return a LdapReferralException and application can decide how best to handle it.
08-04-2016

I was looking at the wrong res.referrals.elementAt call (the lines numbers lined up well with jdk8u code and wrongly assumed I had the right call site) ok - so the error occurs when Ldap result is LDAP_REFERRAL. case LdapClient.LDAP_REFERRAL: if (handleReferrals == LdapClient.LDAP_REF_IGNORE) { e = new PartialResultException(msg); break; } r = new LdapReferralException(resolvedName, resolvedObj, remainName, msg, envprops, fullDN, handleReferrals, reqCtls); // only one set of URLs is present r.setReferralInfo(res.referrals.elementAt(0), false); ==== No null check above and it explains why the issue would occur. I've patched the code and am running tests. Will submit RFR shortly.
08-04-2016

Here's the problem code in a reduced format : LdapCtx.processReturnCode protected void processReturnCode(LdapResult res, Name resolvedName, Object resolvedObj, Name remainName, Hashtable<?,?> envprops, String fullDN) throws NamingException { if (res.referrals != null) { msg = "Unprocessed Continuation Reference(s)"; if (handleReferrals == LdapClient.LDAP_REF_IGNORE) { e = new PartialResultException(msg); break; } ... msg = "Continuation Reference"; // make a chain of LdapReferralExceptions for (int i = 0; i < contRefCount; i++) { r = new LdapReferralException(resolvedName, resolvedObj, remainName, msg, envprops, fullDN, handleReferrals, reqCtls); r.setReferralInfo(res.referrals.elementAt(i), true); // NPE seen here if (hopCount > 1) { r.setHopCount(hopCount); } if (head == null) { head = ptr = r; } else { ptr.nextReferralEx = r; // append ex. to end of chain ptr = r; } } res.referrals = null; // reset ... } == we do make a check that res.referrals is non-null before referencing it later. Looks like some call has accessed the referral value and set it to null while above code is running. It's not obvious to me what code is doing that. If LdapCtx.processReturnCode(..) was called multiple times on the same LdapResult Object, then we would have a recondition (see the res.referrals = null call) - According to another group seeing this issue : "The problem starts when AD loses one Domain Controller and OUD fails to fetch the data it needs. OUD is handling this error gracefully and it is still returning data to OAM but with error code 10 (partial results)" Application code higher up the stack could handle the NPE but the best place to handle that is in the LdapCtx code. Establishing root cause of who sets referrrals to null would be useful to know. Should JDK catch the NPE and discard any extra processing of LdapReferralException generation it was involved in?
07-04-2016

Looks like an issue sitting in ldap code for a long time. Should be fixed in JDK 9. Can consider a backport then.
06-04-2016

Checked the source code for LdapCtx.java in jdk 7u-dev, 8u-dev and 9-dev. There has been no changes in the expression res.referrals.elementAt(0) which is causing the NPE. So, the issue should be there in JDK 8u and JDK 9a versions also.
09-02-2016