tomcat startup throws stackoverflowerror because of cyclic inheritance dependencies

570 views Asked by At

I deployed my application war to tomcat, threw StackOverflowError after startup, the stacktrace is shown in the picture below. stacktrace

According to the stacktrace tip and source code, i can find the cyclic inheritance dependencies are: org.bouncycastle.asn1.ASN1Boolean extends org.bouncycastle.asn1.DERBoolean(org.bouncycastle:bcprov-jdk15:1.45) org.bouncycastle.asn1.DERBoolean extends org.bouncycastle.asn1.ASN1Boolean(org.bouncycastle:bcprov-jdk15on:1.60)

key source code:

    protected void checkHandlesTypes(JavaClass javaClass,
            Map<String,JavaClassCacheEntry> javaClassCache) {

        // ....

        String className = javaClass.getClassName();

        Class<?> clazz = null;
        if (handlesTypesNonAnnotations) {
            populateJavaClassCache(className, javaClass, javaClassCache);
            JavaClassCacheEntry entry = javaClassCache.get(className);
            if (entry.getSciSet() == null) {
                try {           
                    // soe throws because of this code(recursive call)
                    populateSCIsForCacheEntry(entry, javaClassCache);
                } catch (StackOverflowError soe) {
                    throw new IllegalStateException(sm.getString(
                            "contextConfig.annotationsStackOverflow",
                            context.getName(),
                            classHierarchyToString(className, entry, javaClassCache)));
                }
            }            
        }
    }

    private void populateJavaClassCache(String className, JavaClass javaClass,
            Map<String,JavaClassCacheEntry> javaClassCache) {
        if (javaClassCache.containsKey(className)) {
            return;
        }

        // Add this class to the cache
        javaClassCache.put(className, new JavaClassCacheEntry(javaClass));

        populateJavaClassCache(javaClass.getSuperclassName(), javaClassCache);

        for (String interfaceName : javaClass.getInterfaceNames()) {
            populateJavaClassCache(interfaceName, javaClassCache);
        }
    }

    private void populateJavaClassCache(String className,
            Map<String,JavaClassCacheEntry> javaClassCache) {
        if (!javaClassCache.containsKey(className)) {
            String name = className.replace('.', '/') + ".class";
            try (InputStream is = context.getLoader().getClassLoader().getResourceAsStream(name)) {
                if (is == null) {
                    return;
                }
                ClassParser parser = new ClassParser(is);
                JavaClass clazz = parser.parse();
                populateJavaClassCache(clazz.getClassName(), clazz, javaClassCache);
            } catch (ClassFormatException e) {
                log.debug(sm.getString("contextConfig.invalidSciHandlesTypes",
                        className), e);
            } catch (IOException e) {
                log.debug(sm.getString("contextConfig.invalidSciHandlesTypes",
                        className), e);
            }
        }
    }

---------------edits--------------

I’ve known how to fix the error,my point is how the recursive call happen in populateSCIsForCacheEntry method.

I read the populateJavaClassCache method,after the org.bouncycastle:bcprov-jdk15:1.45 jar parsed,the javaCacheMap contains: "org.bouncycastle.asn1.ASN1Boolean" -> classEntry["org.bouncycastle.asn1. DERBoolean","interface stuff"], "org.bouncycastle.asn1.DERBoolean" -> classEntry["Java.lang.Object","interface stuff"],

and when org.bouncycastle:bcprov-jdk15on:1.60 jar is parsing,keys for class org.bouncycastle.asn1.ASN1Boolean and org.bouncycastle.asn1.DERBoolean won't be put into javaCacheMap again because of map's contains method check.

so the javaCacheMap does not contain the cyclic dependencies below: "org.bouncycastle.asn1.ASN1Boolean" -> classEntry["org.bouncycastle.asn1. DERBoolean","interface stuff"], "org.bouncycastle.asn1.DERBoolean" -> classEntry["org.bouncycastle.asn1.ASN1Boolean","interface stuff"],

and how does the recursive call happen?

0

There are 0 answers