DriverManager.isDriverAllowed has an unintentional side-effect?

Jaikiran Pai jai.forums2013 at gmail.com
Mon Feb 10 15:09:48 UTC 2020


Right now within the implementation of APIs in java.sql.DriverManager
there are classloader checks to ensure whether the caller is allowed
access to registered drivers. For example the getDriver(String url)
API[1] calls the isDriverAllowed (private) method[2] to check if the
registered driver is allowed access from the caller's classloader. The
implementation of isDriverAllowed has this[3]:

aClass =  Class.forName(driver.getClass().getName(), true, classLoader);

Is it intentional to intialize that class by passing "true" to the
forName call? The reason I ask is the following scenario:

1. Imagine a multi classloader environment.

2. Consider postgres JDBC driver (from postgres.jar) gets loaded through
classloader C1 and is registered in DriverManager in context of C1.

3. Now consider a class A loaded in classloader C2. Let's say this C2
also has postgres.jar in its classpath but hasn't yet loaded any of the
classes from it yet nor have any calls to "registerDriver" been made by
any of the classes loaded by this C2.

4. Class A (in context of C2) now calls getDriver(String url) passing it
a JDBC url corresponding to postgres. This will result in a
SQLException("No suitable driver") exception and that's fine, because C2
isn't allowed access to driver registered in context of C1. However, now
consider the following code(again within class A in context of C2):

try {

    DriverManager.getDriver("jdbc:postgres:....");

} catch (SQLException e) {

  // expected

  // now lets do the same call again

  driver = DriverManager.getDriver("jdbc:postgres:...."); --> this one
passes

}

So what's being done is, the SQLException("no suitable driver") is
caught and the exact same call which triggered this issue, is called
again. This time the call passes and returns a JDBC driver corresponding
to the postgres driver.

Looking at the implementation of DriverManager (which I linked before),
I can understand why this happens but it just seems odd that the API
would behave in this manner (that too with no indication in the
documentation).

What really is happening here is that the current implementation of
isDriverAllowed, due to its usage of "true" to initialize the driver
class ends up triggering the Driver's static block (which as per the
JDBC spec) is expected/mandated to register with the DriverManager. As a
result, this call ends up registering the driver, now in the context of
C2 and as a result the subsequent calls to this (and other APIs) start
passing from classes loaded by C2 (like that class A).

Should this check in the isDriverAllowed, instead use "false" and not
trigger the intialization of the class?

[1]
https://hg.openjdk.java.net/jdk/jdk/file/5a3b04593405/src/java.sql/share/classes/java/sql/DriverManager.java#l266

[2]
https://hg.openjdk.java.net/jdk/jdk/file/5a3b04593405/src/java.sql/share/classes/java/sql/DriverManager.java#l280

[3]
https://hg.openjdk.java.net/jdk/jdk/file/5a3b04593405/src/java.sql/share/classes/java/sql/DriverManager.java#l555

-Jaikiran




More information about the core-libs-dev mailing list