janino-compiler / janino

Janino is a super-small, super-fast Java™ compiler.
http://janino-compiler.github.io/janino
Other
1.21k stars 205 forks source link

Limit the maximum bytecode size of methods/units #221

Closed enexusde closed 1 month ago

enexusde commented 1 month ago

Janino compiles java-source to bytecode. The bytecode can be stored in .class-files. Those class-files can be stored in .jar-files (Let us call them janino-jars for a moment).

Those janino-jar-files can be executed in a JVM very well. You also can Unit-Test the janino-jars very well.

What you can NOT (or almost not) do is to run coverage-tests on those janino-jars! The reason: In order to coverage-test those janino-jars the coverage-instrument (JaCoCo in example) must wrap additional bytecode around the janino-methods.

Solution: In order to allow other tools to add additional bytecode a limit should limitate the janino-bytecode per method.

See: https://github.com/jacoco/jacoco/issues/1607#issuecomment-2028899860

Geolykt commented 1 month ago

I don't quite understand, why would this be an issue with janino but not with javac? Further, how do you think such a limit would resolve your issues? If janino was to arbitrarily reduce the maximum method size below the size allowed by the JVMS, then either it'd need to split it up into multiple methods (certainly not impossible, but I have my doubts on whether janino is well equipped for such logistical hurdles) or plainly just fail compilation.

Instead I think you should reduce the size of the methods you are compiling in the first place.

enexusde commented 1 month ago

Yes, fail the compilation would be great! Maybe with an special exception. Maybe we call it BytecodeLimitExceededException? Javac have the same problem as you can read here: https://docs.oracle.com/javase/specs/jvms/se6/html/ClassFile.doc.html#6254

Instead I think you should reduce the size of the methods you are compiling in the first place.

That is a good idea. Since the methods may be created due to user inputs the User is responsible to reduce the size of the inputs. Think about a input-validator that check the size of the code-generation. As soon as the Exception BytecodeLimitExceededException is thrown: the validation of the user's input fail.

enexusde commented 1 month ago

Hm, you know what? I may could measure the resulting janino-classes myself...

Geolykt commented 1 month ago

For reference currently if the code grows beyond the allowed maximum size (as per the JVMS) an exception is thrown here: https://github.com/janino-compiler/janino/blob/4db1b8117bda36056f4eeab2d29e1f524b21b13c/janino/src/main/java/org/codehaus/janino/CodeContext.java#L699

However, I'm not sure if it isn't a bit out of scope for janino to allow users to reduce that limit further than that (especially since I am not 100% sure how that'd be done in the first place since you'd either use a system property or funnel a argument into that method one way or another - but I suppose that is for the implementor to figure out).


For reference, you could easily write a tool to get the size of your CodeAttribute yourself as you noted. Libraries such as for example Cafedude can easily do that. In case of Cafedude that can be done via https://github.com/Col-E/CAFED00D/blob/68f2332c0904cb2d34580cf77ae7f4a98e6d773f/core/src/main/java/software/coley/cafedude/classfile/attribute/CodeAttribute.java#L159-L180.

enexusde commented 1 month ago

Yes, please do not implement this request. I will measure the bytecode after compilation myself. This also have the advantage that I am not bound to janino and could use any Apache Commons JCI implementation.

Sorry for the inconvenience.

aunkrig commented 1 month ago

Summarized: If the bytecode of a method grows beyond 64K, then Janino will throw an exception; if the size is slightly below 64K, but subsequent code instrumentators break the size limit, then the instrumentator throws the exception. In either case, your software should catch the exception and ask the user to shorten her code.