4

Java version: 11.0.13

I have a function that compiles java files into classes at runtime,

on Java 8 everything worked ok, also with java 11.0.13 on windows everything works ok

but on linux(Red Hat Enterprise Linux Server release 6.10) it failes with StackOverflowError

the code:

    public Class<?> compile(String className, String content) {
        Lookup lookup = MethodHandles.lookup();
        ClassLoader cl = lookup.lookupClass().getClassLoader();

        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();

        try {
            ClassFileManager fileManager = new ClassFileManager(compiler.getStandardFileManager(null, null, null));

            List<CharSequenceJavaFileObject> files = new ArrayList<>();
            files.add(new CharSequenceJavaFileObject(className, content));
            StringWriter out = new StringWriter();

            CompilationTask task = compiler.getTask(out, fileManager, null, compilerOptions, null, files);
            task.call();
            if (fileManager.isEmpty())
                throw new CompilationException("Compilation error: " + out);
            }
   //...some more code
  }

I ran it with "-verbose" flag in compilerOption field,

when compiling a specific class(TestClass.java) I am getting the following error in out string

 [parsing started WrappedJavaFileObject[com.package.Compiler$CharSequenceJavaFileObject[string:///TestClass.java]]]
[parsing completed 9ms]
[loading /modules/java.security.jgss/module-info.class]
[loading /modules/jdk.crypto.ec/module-info.class]
[loading /modules/java.smartcardio/module-info.class]
[loading /modules/jdk.jdi/module-info.class]
[loading /modules/jdk.naming.ldap/module-info.class]
[loading /modules/jdk.xml.dom/module-info.class]
[loading /modules/jdk.localedata/module-info.class]
[loading /modules/jdk.compiler/module-info.class]
[loading /modules/jdk.jcmd/module-info.class]
[loading /modules/jdk.crypto.cryptoki/module-info.class]
[loading /modules/jdk.net/module-info.class]
[loading /modules/jdk.security.jgss/module-info.class]
[loading /modules/java.logging/module-info.class]
[loading /modules/java.transaction.xa/module-info.class]
[loading /modules/java.sql/module-info.class]
[loading /modules/java.scripting/module-info.class]
[loading /modules/jdk.scripting.nashorn.shell/module-info.class]
[loading /modules/jdk.internal.vm.compiler/module-info.class]
[loading /modules/jdk.management/module-info.class]
[loading /modules/jdk.scripting.nashorn/module-info.class]
[loading /modules/jdk.jconsole/module-info.class]
[loading /modules/jdk.internal.jvmstat/module-info.class]
[loading /modules/jdk.internal.vm.compiler.management/module-info.class]
[loading /modules/java.compiler/module-info.class]
[loading /modules/java.management.rmi/module-info.class]
[loading /modules/jdk.internal.opt/module-info.class]
[loading /modules/jdk.jsobject/module-info.class]
[loading /modules/java.prefs/module-info.class]
[loading /modules/java.management/module-info.class]
[loading /modules/jdk.rmic/module-info.class]
[loading /modules/jdk.unsupported/module-info.class]
[loading /modules/java.xml/module-info.class]
[loading /modules/java.datatransfer/module-info.class]
[loading /modules/java.sql.rowset/module-info.class]
[loading /modules/jdk.jfr/module-info.class]
[loading /modules/java.xml.crypto/module-info.class]
[loading /modules/java.instrument/module-info.class]
[loading /modules/jdk.hotspot.agent/module-info.class]
[loading /modules/jdk.naming.dns/module-info.class]
[loading /modules/jdk.sctp/module-info.class]
[loading /modules/java.base/module-info.class]
[loading /modules/jdk.management.agent/module-info.class]
[loading /modules/jdk.naming.rmi/module-info.class]
[loading /modules/java.naming/module-info.class]
[loading /modules/jdk.pack/module-info.class]
[loading /modules/jdk.jdeps/module-info.class]
[loading /modules/jdk.accessibility/module-info.class]
[loading /modules/jdk.internal.le/module-info.class]
[loading /modules/java.se/module-info.class]
[loading /modules/jdk.internal.vm.ci/module-info.class]
[loading /modules/jdk.internal.ed/module-info.class]
[loading /modules/jdk.javadoc/module-info.class]
[loading /modules/java.desktop/module-info.class]
[loading /modules/jdk.jdwp.agent/module-info.class]
[loading /modules/jdk.dynalink/module-info.class]
[loading /modules/jdk.charsets/module-info.class]
[loading /modules/jdk.jstatd/module-info.class]
[loading /modules/java.net.http/module-info.class]
[loading /modules/jdk.zipfs/module-info.class]
[loading /modules/jdk.unsupported.desktop/module-info.class]
[loading /modules/jdk.jlink/module-info.class]
[loading /modules/jdk.editpad/module-info.class]
[loading /modules/jdk.management.jfr/module-info.class]
[loading /modules/jdk.jartool/module-info.class]
[loading /modules/jdk.attach/module-info.class]
[loading /modules/jdk.security.auth/module-info.class]
[loading /modules/jdk.httpserver/module-info.class]
[loading /modules/java.rmi/module-info.class]
[loading /modules/jdk.jshell/module-info.class]
[loading /modules/java.security.sasl/module-info.class]
[loading /modules/java.base/java/io/Serializable.class]
[loading /modules/java.base/java/time/LocalDate.class]
[loading /modules/java.base/java/time/LocalDateTime.class]
[loading /home/test.jar(/com/package/TypeName.class)]
[loading /home/test.jar(/com/package/MongoDataSource.class)]
[loading /home/test.jar(/com/package/EqualsBuilder.class)]
[loading /home/test.jar(/com/package/HashCodeBuilder.class)]
[loading /home/test.jar(/com/package/ToStringBuilder.class)]
[loading /modules/java.base/java/lang/Object.class]
[loading /modules/java.base/java/lang/String.class]
[loading /modules/java.base/java/lang/Double.class]
[loading /modules/java.base/java/lang/Deprecated.class]
[loading /modules/java.base/java/lang/annotation/Target.class]
[loading /modules/java.base/java/lang/annotation/ElementType.class]
[loading /modules/java.base/java/lang/annotation/Retention.class]
[loading /modules/java.base/java/lang/annotation/RetentionPolicy.class]
[loading /modules/java.base/java/lang/annotation/Repeatable.class]
[loading /modules/java.base/java/lang/annotation/Annotation.class]
[loading /modules/java.base/java/lang/Override.class]
Round 1:
    input files: {com.package.TestClass}
    annotations: [com.package.MongoDataSource, com.package.TypeName, java.lang.Override]
    last round: false
[loading /modules/java.base/java/util/Collection.class]
[loading /modules/java.base/java/util/Map.class]
Processor org.springframework.boot.configurationprocessor.ConfigurationMetadataAnnotationProcessor matches [/com.packageMongoDataSource, java.base/java.lang.Override, /com.package.TypeName] and returns false.
Round 2:
    input files: {}
    annotations: []
    last round: true
[checking com.package.TestClass]
[loading /modules/java.base/java/lang/AutoCloseable.class]
[total 220ms]
compiler message file broken: key=compiler.misc.msg.bug arguments=11.0.13, {1}, {2}, {3}, {4}, {5}, {6}, {7}
java.lang.StackOverflowError
    at jdk.compiler/com.sun.tools.javac.comp.Check.checkType(Check.java:554)
    at jdk.compiler/com.sun.tools.javac.comp.Attr$ResultInfo.check(Attr.java:518)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.check(Attr.java:250)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.visitLiteral(Attr.java:4187)
    at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCLiteral.accept(JCTree.java:2276)
    at jdk.compiler/com.sun.tools.javac.comp.ArgumentAttr.visitTree(ArgumentAttr.java:207)
    at jdk.compiler/com.sun.tools.javac.tree.JCTree$Visitor.visitLiteral(JCTree.java:3104)
    at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCLiteral.accept(JCTree.java:2276)
    at jdk.compiler/com.sun.tools.javac.comp.ArgumentAttr.attribArg(ArgumentAttr.java:197)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:653)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.attribArgs(Attr.java:751)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.visitApply(Attr.java:1997)
    at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1634)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:655)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.visitSelect(Attr.java:3575)
    at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:2114)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:655)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.visitApply(Attr.java:2006)
    at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCMethodInvocation.accept(JCTree.java:1634)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.attribTree(Attr.java:655)
    at jdk.compiler/com.sun.tools.javac.comp.Attr.visitSelect(Attr.java:3575)
    at jdk.compiler/com.sun.tools.javac.tree.JCTree$JCFieldAccess.accept(JCTree.java:2114)
//... this continues for like 1024 rows

TestClass.java is pure POJO, it has 434 fields of types: String, LocalDateTime, LocalDate, Double

And one long field for serialization: private final static long serialVersionUID = -3497425053595922056L;

it has: getters, setters, toString, equals & hashcode methods.

any help would be appreciated, I am a bit lost here...

Roie Beck
  • 1,113
  • 3
  • 15
  • 30
  • 4
    "434 fields"? This might actually be the problem. You might be causing a Stackoverflow just due to code size. You could try increasing the stack size of the process running the compiler as a work around, but I'd seriously consider restructuring your code to avoid that kind of class. – Joachim Sauer Nov 29 '21 at 14:04
  • 2
    Increasing the stack size sounds like the correct fix to me. While 434 fields is not ideal from software engineering perspective, it's still legal because it's well under the max number of fields as defined by the JVM spec, and the JLS does not define one. Also it feels like some weird coding in the compiler if you think about it - why would it blow up the stack from a _list_ that is too long? – jingx Nov 29 '21 at 14:49
  • @Joachim Sauer, according to spec java limitation for fields is 65k, see here: https://stackoverflow.com/a/48011955/3942132 , this is well below, as this is a user defined class (we let user defined data classes via ui), and as it used to work on java 8, saying I do not support it anymore will probably not be acceptable... – Roie Beck Nov 29 '21 at 15:21
  • 1
    @RoieBeck: yes, I agree it's within the spec and that this is a compiler bug. But it's also the kind of bug that you're likely to run into if you use the system for things it's not explicitly designed for. That's also why I said "consider restructuring" and not "you must change your code". – Joachim Sauer Nov 29 '21 at 15:55
  • 5
    I just tried to compile source code with 50000 fields through the compiler API and it worked, under Windows and Linux. The stacktrace indicates that the culprit is at a combination of method invocation and field access, so the number of fields is a red herring here. We need more information about the actual source code. – Holger Nov 29 '21 at 16:19
  • @Holger, I will get a confirmation to publish the class and will post it. – Roie Beck Nov 29 '21 at 16:59
  • Hi all, first increasing the size to -Xss4m worked, I started to suspect this is due to the fact that we build a graph(for dependencies between the classes) from all our user defined classes and then parallel compile them, so maybe we have a pick of above 1mb, as linux default(unlike windows) is 1mb.. – Roie Beck Nov 30 '21 at 07:32

0 Answers0