Limit the TCCL when instantiating UntrustedXML 00/77300/1
authorRobert Varga <robert.varga@pantheon.tech>
Wed, 24 Oct 2018 21:12:02 +0000 (23:12 +0200)
committerRobert Varga <robert.varga@pantheon.tech>
Fri, 26 Oct 2018 10:06:41 +0000 (12:06 +0200)
JAXP newInstance() methods can end up going through ServiceLoader
with TCCL as its ClassLoader, which means our constants may end up
pointing to a ClassLoader beyond our normal visibility.

This means we can end up picking up a different factory depending
on where we are called from and also can mean the TCCL cannot be
garbage-collected.

Force the TCCL to be the ClassLoader holding UntrustedXML, thus
establishing tight coupling between JAXP implementation discovery
mechanism and UntrustedXML.

JIRA: CONTROLLER-1867
Change-Id: Icacb0e193c7360c73bd07bc5c815bf803ca9ac44
Signed-off-by: Robert Varga <robert.varga@pantheon.tech>
(cherry picked from commit 6fd73a016d19cfb336ab12f6eddfc2d5934fb3fc)

common/util/src/main/java/org/opendaylight/yangtools/util/xml/UntrustedXML.java

index 46c28490c85af3cff106abd83414d319fb93bbbd..1eea9442bf1d84b8cfaeb5f7190a2e97b342c9a5 100644 (file)
@@ -11,6 +11,7 @@ import com.google.common.annotations.Beta;
 import java.io.InputStream;
 import java.io.Reader;
 import java.nio.charset.Charset;
+import java.util.function.Supplier;
 import javax.xml.XMLConstants;
 import javax.xml.parsers.DocumentBuilder;
 import javax.xml.parsers.DocumentBuilderFactory;
@@ -21,6 +22,7 @@ import javax.xml.stream.XMLInputFactory;
 import javax.xml.stream.XMLStreamException;
 import javax.xml.stream.XMLStreamReader;
 import org.eclipse.jdt.annotation.NonNull;
+import org.opendaylight.yangtools.util.ClassLoaderUtils;
 import org.xml.sax.SAXException;
 import org.xml.sax.SAXNotRecognizedException;
 import org.xml.sax.SAXNotSupportedException;
@@ -35,7 +37,7 @@ public final class UntrustedXML {
     private static final @NonNull DocumentBuilderFactory DBF;
 
     static {
-        final DocumentBuilderFactory f = DocumentBuilderFactory.newInstance();
+        final DocumentBuilderFactory f = getLimited(DocumentBuilderFactory::newInstance);
         f.setCoalescing(true);
         f.setExpandEntityReferences(false);
         f.setIgnoringElementContentWhitespace(true);
@@ -57,7 +59,7 @@ public final class UntrustedXML {
     private static final SAXParserFactory SPF;
 
     static {
-        final SAXParserFactory f = SAXParserFactory.newInstance();
+        final SAXParserFactory f = getLimited(SAXParserFactory::newInstance);
         f.setNamespaceAware(true);
         f.setXIncludeAware(false);
         try {
@@ -76,8 +78,7 @@ public final class UntrustedXML {
     private static final XMLInputFactory XIF;
 
     static {
-        final XMLInputFactory f = XMLInputFactory.newInstance();
-
+        final XMLInputFactory f = getLimited(XMLInputFactory::newInstance);
         f.setProperty(XMLInputFactory.IS_COALESCING, Boolean.TRUE);
         f.setProperty(XMLInputFactory.IS_NAMESPACE_AWARE, Boolean.TRUE);
         f.setProperty(XMLInputFactory.IS_SUPPORTING_EXTERNAL_ENTITIES, Boolean.FALSE);
@@ -153,4 +154,9 @@ public final class UntrustedXML {
     public static @NonNull XMLStreamReader createXMLStreamReader(final Reader reader) throws XMLStreamException {
         return XIF.createXMLStreamReader(reader);
     }
+
+    private static <T> T getLimited(final @NonNull Supplier<T> supplier) {
+        final ClassLoader loader = UntrustedXML.class.getClassLoader();
+        return loader == null ? supplier.get() : ClassLoaderUtils.getWithClassLoader(loader, supplier);
+    }
 }