yWorks/yGuard

Crash when using IntStream

adrianbn opened this issue ยท 4 comments

Seems like yGuard has some trouble obfuscating code that uses IntStream. Here's a sample application that fails:

import java.util.Random;

public class Test {
    private Random rng;

    public Test(long seed) {
        this.rng = new Random(seed);
    }
    /*
     * Generates alphanumeric strings of given length
     */
    public String randomAlphaString(int targetStringLength) {
        int leftLimit = 48; // '0'
        int rightLimit = 122; // 'z'

        return rng.ints(leftLimit, rightLimit + 1)
                .filter(i -> (i <= 57 || i >= 65) && (i <= 90 || i >= 97))
                .limit(targetStringLength)
                .collect(StringBuilder::new, StringBuilder::appendCodePoint, StringBuilder::append)
                .toString();
    }

    public static void main(String[] args) {
        Test t = new Test(1337);
        System.out.println(t.randomAlphaString(10));
    }
}

After obfuscating the jar, trying to execute it results in:

> java -jar build/libs/test-1.0-SNAPSHOT_obf.jar
Error: Unable to initialize main class com.example.Test
Caused by: java.lang.VerifyError: Operand stack underflow
Exception Details:
  Location:
    com/example/Test.A(I)Ljava/lang/String; @17: invokeinterface
  Reason:
    Attempt to pop empty stack.
  Current Frame:
    bci: @17
    flags: { }
    locals: { 'com/example/Test', integer, integer, integer }
    stack: { 'java/util/stream/IntStream' }
  Bytecode:
    0000000: 1030 3d10 7a3e 2ab4 0014 1c1d 0460 b600
    0000010: 23b9 0029 0200 1b85 b900 2d03 00b9 0031
    0000020: 0400 c000 33b6 0037 b0
yGuy commented

How exactly did you obfuscate the jar? Did you try to use the shrinker? There are some known incompatibilities: https://yworks.github.io/yGuard/compatibility/

We have plans to improve the situation, though. @Fohlen - where is the corresponding issue, I can't seem to find it.

it's #48 . I'll give your example a try once the PR is merged!

Hey @yGuy,

this is what I used to obfuscate:

task obfuscate {
    dependsOn jar
    group 'yGuard'
    description 'Obfuscates and shrinks the java archive.'

    doLast {
        ant.taskdef(
                name: 'yguard',
                classname: 'com.yworks.yguard.YGuardTask',
                classpath: sourceSets.main.runtimeClasspath.asPath
        )
        println(jar.archivePath)
        def archivePath = jar.archivePath.absolutePath

        ant.yguard {
            inoutpair(in: archivePath, out: archivePath.replace(".jar", "_obf.jar"))
            shrink(logfile: "${buildDir}/yshrink.log.xml") {
                keep {
                    method(name: "void main(java.lang.String[])", "class": application.mainClassName)
                }
            }
            rename(mainclass: application.mainClassName, logfile: "${buildDir}/yguard.log.xml") {
                property(name: "error-checking", value: "pedantic")
            }
        }
    }

The shrink(logfile: "${buildDir}/yshrink.log.xml") {...} part of your ant.yguard target means that you are shrinking your application. Shrinking is not yet supported for Java 8 and newer class files.