Skip to content

[java] StackOverflowError with recursive generic types #5442

@slovdahl

Description

@slovdahl

Affects PMD Version: 7.8.0 and 7.9.0 at least

Description:

I'm trying to upgrade PMD from 6.55 in our codebase. I started out with 7.3.0 but got a StackOverflowError that was reported in #5096 and fixed in 7.9.0. Now I'm seeing another StackOverflowError.

Exception Stacktrace:

The start and end of the stack trace inline (and the full one, and the full --debug log):

Exception in thread "main" java.lang.StackOverflowError
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.visitSentinel(TypeOps.java:586)
	at net.sourceforge.pmd.lang.java.types.SentinelType.acceptVisitor(SentinelType.java:66)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.isConvertible(TypeOps.java:656)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.isConvertible(TypeOps.java:598)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.typeArgContains(TypeOps.java:785)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.visitClass(TypeOps.java:854)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.visitClass(TypeOps.java:586)
	at net.sourceforge.pmd.lang.java.types.JClassType.acceptVisitor(JClassType.java:312)

        ...

	at net.sourceforge.pmd.lang.java.types.JClassType.acceptVisitor(JClassType.java:312)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.isConvertible(TypeOps.java:656)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.isConvertible(TypeOps.java:598)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.visitTypeVar(TypeOps.java:808)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.visitTypeVar(TypeOps.java:586)
	at net.sourceforge.pmd.lang.java.types.JTypeVar.acceptVisitor(JTypeVar.java:103)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.visitSentinel(TypeOps.java:826)
	at net.sourceforge.pmd.lang.java.types.TypeOps$SubtypeVisitor.visitSentinel(TypeOps.java:586)
	at net.sourceforge.pmd.lang.java.types.SentinelType.acceptVisitor(SentinelType.java:66)

Also tested 7.8.0 on only the file that triggers it and got a slightly different stack trace.

Code Sample demonstrating the issue:

I have spent quite some time on trying to extract a reproducer outside our codebase, but no success yet. Using PMD_JAVA_OPTS="-Dpmd.error_recovery" I was able to figure out that the class triggering the StackOverflowError is an AbstractResourceAssembler that has the following shape at least:

abstract class AbstractResourceAssembler<T, R extends Resource<? extends R>, UID, V> implements EntityResourceAssembler<T, R, UID, V> {
}

interface EntityResourceAssembler<T, R extends Resource<? extends R>, UID, V> extends ResourceAssembler<R, UID, V> {
}

interface ResourceAssembler<R extends Resource<? extends R>, UID, V> {
}

abstract class Resource<T extends Resource<? extends T>> extends org.springframework.hateoas.RepresentationModel<T> {
}

But I'm not able to get PMD to fail using just those 4 classes.

Ruleset:

<?xml version="1.0" encoding="UTF-8"?>
<ruleset name="PMD ruleset"
         xmlns="http://pmd.sourceforge.net/ruleset/2.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://pmd.sourceforge.net/ruleset/2.0.0 https://pmd.sourceforge.io/ruleset_2_0_0.xsd">

  <description>PMD ruleset</description>

  <rule ref="category/java/bestpractices.xml/MissingOverride"/>
  <rule ref="category/java/bestpractices.xml/PrimitiveWrapperInstantiation"/>
  <rule ref="category/java/bestpractices.xml/ReplaceVectorWithList"/>
  <rule ref="category/java/bestpractices.xml/UseStandardCharsets"/>
  <rule ref="category/java/bestpractices.xml/UseTryWithResources"/>
  <rule ref="category/java/codestyle.xml/ExtendsObject"/>
  <rule ref="category/java/codestyle.xml/PackageCase"/>
  <rule ref="category/java/codestyle.xml/UnnecessaryCast"/>
  <rule ref="category/java/codestyle.xml/UnnecessarySemicolon"/>
  <rule ref="category/java/codestyle.xml/UseDiamondOperator"/>
  <rule ref="category/java/errorprone.xml/AvoidDecimalLiteralsInBigDecimalConstructor" />
  <rule ref="category/java/errorprone.xml/ClassCastExceptionWithToArray" />
  <rule ref="category/java/errorprone.xml/IdempotentOperations" />
  <rule ref="category/java/errorprone.xml/MissingSerialVersionUID" />
  <rule ref="category/java/errorprone.xml/NonStaticInitializer" />
  <rule ref="category/java/errorprone.xml/UseEqualsToCompareStrings" />
  <rule ref="category/java/errorprone.xml/UselessOperationOnImmutable" />
  <rule ref="category/java/multithreading.xml/DontCallThreadRun" />
</ruleset>

Steps to reproduce:

Please provide detailed steps for how we can reproduce the bug.

  1. TBD

Running PMD through: CLI and Gradle 8.10

Java 21 and 23 (Temurin).

Metadata

Metadata

Assignees

Labels

a:bugPMD crashes or fails to analyse a file.

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions