This is an automated email from the ASF dual-hosted git repository.

markt-asf pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/tomcat.git


The following commit(s) were added to refs/heads/main by this push:
     new 3c6cd2eab3 Fix a race with two requests looking up a singleton JNDI 
resource
3c6cd2eab3 is described below

commit 3c6cd2eab3f012f32002b1b342451073732ab2ba
Author: Mark Thomas <[email protected]>
AuthorDate: Fri Jun 19 13:35:49 2026 +0100

    Fix a race with two requests looking up a singleton JNDI resource
---
 java/org/apache/naming/NamingContext.java | 58 ++++++++++++++++++++-----------
 webapps/docs/changelog.xml                |  4 +++
 2 files changed, 42 insertions(+), 20 deletions(-)

diff --git a/java/org/apache/naming/NamingContext.java 
b/java/org/apache/naming/NamingContext.java
index 2bb5274ba4..b6712c3eea 100644
--- a/java/org/apache/naming/NamingContext.java
+++ b/java/org/apache/naming/NamingContext.java
@@ -518,28 +518,28 @@ public class NamingContext implements Context {
             } else if (entry.type == NamingEntry.REFERENCE) {
                 try {
                     Object obj = null;
-                    if (!GRAAL) {
-                        obj = NamingManager.getObjectInstance(entry.value, 
name, this, env);
-                    } else {
-                        // NamingManager.getObjectInstance would simply return 
the reference here
-                        // Use the configured object factory to resolve it 
directly if possible
-                        // Note: This may need manual constructor reflection 
configuration
-                        Reference reference = (Reference) entry.value;
-                        String factoryClassName = 
reference.getFactoryClassName();
-                        if (factoryClassName != null) {
-                            Class<?> factoryClass = 
getClass().getClassLoader().loadClass(factoryClassName);
-                            ObjectFactory factory = (ObjectFactory) 
factoryClass.getDeclaredConstructor().newInstance();
-                            obj = factory.getObjectInstance(entry.value, name, 
this, env);
-                        }
-                    }
+                    boolean singleton = false;
                     if (entry.value instanceof ResourceRef) {
-                        boolean singleton = Boolean.parseBoolean(
-                                (String) ((ResourceRef) 
entry.value).get(ResourceRef.SINGLETON).getContent());
-                        if (singleton) {
-                            entry.type = NamingEntry.ENTRY;
-                            entry.value = obj;
+                        // Only create singleton instances inside the sync
+                        synchronized (entry) {
+                            if (entry.value instanceof ResourceRef) {
+                                singleton = Boolean.parseBoolean(
+                                        (String) ((ResourceRef) 
entry.value).get(ResourceRef.SINGLETON).getContent());
+                                if (singleton) {
+                                    obj = getObjectInstance(name, entry);
+                                    entry.type = NamingEntry.ENTRY;
+                                    entry.value = obj;
+                                }
+                            } else {
+                                // Another thread has created the singleton
+                                singleton = true;
+                                obj = entry.value;
+                            }
                         }
                     }
+                    if (!singleton) {
+                        obj = getObjectInstance(name, entry);
+                    }
                     if (obj == null) {
                         throw new 
NamingException(sm.getString("namingContext.failResolvingReference", name));
                     }
@@ -557,10 +557,28 @@ public class NamingContext implements Context {
                 return entry.value;
             }
         }
-
     }
 
 
+    private Object getObjectInstance(Name name, NamingEntry entry) throws 
Exception {
+        Object obj = null;
+        if (!GRAAL) {
+            obj = NamingManager.getObjectInstance(entry.value, name, this, 
env);
+        } else {
+            // NamingManager.getObjectInstance would simply return the 
reference here
+            // Use the configured object factory to resolve it directly if 
possible
+            // Note: This may need manual constructor reflection configuration
+            Reference reference = (Reference) entry.value;
+            String factoryClassName = reference.getFactoryClassName();
+            if (factoryClassName != null) {
+                Class<?> factoryClass = 
getClass().getClassLoader().loadClass(factoryClassName);
+                ObjectFactory factory = (ObjectFactory) 
factoryClass.getDeclaredConstructor().newInstance();
+                obj = factory.getObjectInstance(entry.value, name, this, env);
+            }
+        }
+        return obj;
+    }
+
     /**
      * Binds a name to an object. All intermediate contexts and the target 
context (that named by all but terminal
      * atomic component of the name) must already exist.
diff --git a/webapps/docs/changelog.xml b/webapps/docs/changelog.xml
index 17c29a517d..588a5a3803 100644
--- a/webapps/docs/changelog.xml
+++ b/webapps/docs/changelog.xml
@@ -218,6 +218,10 @@
         third-party library version information. (csutherl)
       </add>
       <!-- Entries for backport and removal before 12.0.0-M1 below this line 
-->
+      <fix>
+        Avoid a race condition with concurrent lookups for a singleton JNDI
+        resource. (markt)
+      </fix>
     </changelog>
   </subsection>
   <subsection name="Coyote">


---------------------------------------------------------------------
To unsubscribe, e-mail: [email protected]
For additional commands, e-mail: [email protected]

Reply via email to