8366040: Change URL.lookupViaProviders to use ScopedValue to detect recursive lookup

Reviewed-by: alanb, dfuchs
This commit is contained in:
Volkan Yazici 2025-10-07 15:57:31 +00:00
parent eb729f0aaa
commit eb835e05f9
3 changed files with 69 additions and 19 deletions

View File

@ -41,7 +41,6 @@ import java.util.ServiceLoader;
import jdk.internal.access.JavaNetURLAccess;
import jdk.internal.access.SharedSecrets;
import jdk.internal.misc.ThreadTracker;
import jdk.internal.misc.VM;
import jdk.internal.vm.annotation.AOTRuntimeSetup;
import jdk.internal.vm.annotation.AOTSafeClassInitializer;
@ -1394,24 +1393,13 @@ public final class URL implements java.io.Serializable {
return handler;
}
private static class ThreadTrackHolder {
static final ThreadTracker TRACKER = new ThreadTracker();
}
private static Object tryBeginLookup() {
return ThreadTrackHolder.TRACKER.tryBegin();
}
private static void endLookup(Object key) {
ThreadTrackHolder.TRACKER.end(key);
}
private static final ScopedValue<Boolean> IN_LOOKUP = ScopedValue.newInstance();
private static URLStreamHandler lookupViaProviders(final String protocol) {
Object key = tryBeginLookup();
if (key == null) {
if (IN_LOOKUP.isBound()) {
throw new Error("Circular loading of URL stream handler providers detected");
}
try {
return ScopedValue.where(IN_LOOKUP, true).call(() -> {
final ClassLoader cl = ClassLoader.getSystemClassLoader();
final ServiceLoader<URLStreamHandlerProvider> sl =
ServiceLoader.load(URLStreamHandlerProvider.class, cl);
@ -1423,9 +1411,7 @@ public final class URL implements java.io.Serializable {
return h;
}
return null;
} finally {
endLookup(key);
}
});
}
/**

View File

@ -1,5 +1,5 @@
/*
* Copyright (c) 2015, 2024, Oracle and/or its affiliates. All rights reserved.
* Copyright (c) 2015, 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
@ -77,6 +77,7 @@ public class Basic {
viaProvider("bert", KNOWN);
viaBadProvider("tom", SCE);
viaBadProvider("jerry", SCE);
viaCircularProvider("circular", CIRCULAR);
}
private static String withoutWarning(String in) {
@ -99,6 +100,12 @@ public class Basic {
throw new RuntimeException("exitValue: "+ r.exitValue + ", output:[" +r.output +"]");
}
};
static final Consumer<Result> CIRCULAR = r -> {
if (r.exitValue == 0 ||
!r.output.contains("Circular loading of URL stream handler providers detected")) {
throw new RuntimeException("exitValue: " + r.exitValue + ", output:[" + r.output + "]");
}
};
static void unknownProtocol(String protocol, Consumer<Result> resultChecker) {
System.out.println("\nTesting " + protocol);
@ -125,6 +132,15 @@ public class Basic {
sysProps);
}
static void viaCircularProvider(String protocol, Consumer<Result> resultChecker,
String... sysProps)
throws Exception
{
viaProviderWithTemplate(protocol, resultChecker,
TEST_SRC.resolve("circular.provider.template"),
sysProps);
}
static void viaProviderWithTemplate(String protocol,
Consumer<Result> resultChecker,
Path template, String... sysProps)

View File

@ -0,0 +1,48 @@
/*
* Copyright (c) 2025, Oracle and/or its affiliates. All rights reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation.
*
* This code is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
* or visit www.oracle.com if you need additional information or have any
* questions.
*/
package $package;
import java.io.IOException;
import java.net.URI;
import java.net.URL;
import java.net.URLConnection;
import java.net.URLStreamHandler;
import java.net.spi.URLStreamHandlerProvider;
public final class Provider extends URLStreamHandlerProvider {
private static final String PROTOCOL = "$protocol";
@Override
public URLStreamHandler createURLStreamHandler(String protocol) {
try {
// Trigger circular lookup
URI.create("bogus://path/to/nothing").toURL();
} catch (Exception exception) {
throw new RuntimeException(exception);
}
throw new AssertionError("Should not have reached here!");
}
}