On 27/10/2025 20:06, Charles Oliver Nutter wrote:
Hello!
I've been looking for a concrete explanation for why the JDBC
DriverManager can't find drivers under the following circumstances:
* Driver jar loaded into child classloader of app classloader
* Child classloader set for current thread's context classloader
My long explanation of the issue is here:
https://github.com/jruby/jruby/issues/8910#issuecomment-3453029437
The short explanation is that when the DriverManager goes to check for
"allowed" drivers, it ends up using the wrong classloader.
https://github.com/openjdk/jdk/blob/8151251fa683459e57430abf8e3583c444315746/src/java.sql/share/classes/java/sql/DriverManager.java#L157
* Caller's class is acquired with Reflection.getCallerClass
* Caller's classloader is acquired
* If that classloader is null, as it would have been for classes
loaded on the root classpath in Java 8, it instead uses the thread
context classloader.
* If that classloader is not null (Java 9+) and not the platform
classloader, it is used for verification; in this case it is the
system classloader (a "ClassLoader#AppClassLoader" instance) so the
child classloader's driver is disallowed.
My confusion is why this code was never patched for the change to the
system classloader (from null to an AppClassLoader). The logic in
DriverManager will never use the ThreadContext classloader now, since
there's almost no cases where "getClassLoader" will return null.
Is there a good explanation for why this code still checks for a null
classloader?
The java.sql module is mapped to the platform class loader so you are
correct that none of the classes in that module will be visible to the
boot class loader. None of the core modules `requires java.sql` so
wouldn't compile anyway.
The edge case of a JNI attached thread calling DriverManager methods
with no java frames on the stack should be the only case now where the
caller is null. The java.sql.rowset (requires java.sql) is also mapped
to the platform class loader. I don't know if it uses DriverManager but
if it did, then the caller would be a class defined by the platform
class loader.
I don't think it's possible to engage on the question as to why
DriverManager does a visibility check. The discovery and and driver
registration in this API date back to early JDK releases and have been
very problematic to secure. I think (need Lance to confirm) that the
hope was that the eco system would move to DataSource but it seems there
is still a lot of usage of DriverManager.
-Alan