MopFuzzer

June 27, 2024 · View on GitHub

MopFuzzer is a tool for automated testing of the JDK, utilizing various optimization evoking mutators and profile data-based guidance to rigorously test JVM JIT compilers by maximizing optimization interactions. Our artifact includes the source code of MopFuzzer, the mutation seed files required during the execution of MopFuzzer, and a README file describing the installation process and the bugs discovered by the tool.

The Designed Optimization Evoking Mutators

In this work, we designed 13 Optimization Evoking Mutators, which aim to trigger primarily the following optimization behaviors respectively: LoopUnrolling, LockElimination, LockCoarsening, Inlining, DeReflection, LoopPeeling, LoopUnswitching, Deoptimization, AutoboxElimination, RedundantStoreElimination, AlgebraicSimplification, EscapeAnalysis, DeadCodeElimination.

The remaining mutators can be found at the Supplementary Material of the paper.

Usage of MopFuzzer

Step 1: Prerequisites

MopFuzzer needs the debug build of JVM, so users should download the source code of JVM and set the debug flag. Here we take the OpenJDK (mainline) as an example.

# git clone https://github.com/openjdk/jdk.git
# cd jdk
# bash configure --enable-debug
# make images JOBS=40

Step 2: Run the tool

To use MopFuzzer, users should specify the target test case, the path of the debug build of JVM (at least one), We will check whether the outputs of these JDKs are consistant (if perform differential testing). The following is Parameters of running MopFuzzer.

usage: help [-jdk <arg>] [-project_path <arg>] [-target_case <arg>] [-line_number <arg>] [-is_use_jtreg <arg>] [-max_iter <arg>] [-?] [-enable_profile_guide <arg>]

 -?,--help                     Print this help message
 --project_path <arg>          source code root path. e.g., /home/user/benchmark/jtreg17. Necessary.
 --target_case <arg>           target java file. e.g., a.b.c denotes a/b/c.java. Necessary.
 --use_gc_options              use gc options? e.g., true. Default is false.
 --use_jit_options             use JIT options? e.g., true. Default is false.
 --enable_profile_guide <arg>  enable profile guidance? 
                               Recommend false for faster testing. Default is
                               false.
 --is_use_jtreg <arg>          use Jtreg? e.g., true. Default is false
 --jdk <arg>                   the jdk directory, path to bin/. At least one JDK. Necessary
                               We will check whether the outputs of these JDKs are consistent. 
 --line_number <arg>           line number of target file to be mutated. e.g., 10. Default is null.
 --max_iter <arg>              max iteration times.. e.g., 100. Default is 50

Example Command:

# differential testing of two target jdks
path/to/java17/bin/java -jar MopFuzzer.jar --project_path benchmarks/JavaFuzzer/tests/  --target_case Test0001 --jdk path/to/targetJDK1/bin/,path/to/targetJDK2/bin/ --enable_profile_guide true

# Testing a single jdk using jtreg seeds
path/to/java17/bin/java -jar MopFuzzer.jar --project_path benchmarks/jtreg17/ --target_case compiler.codegen.TestBooleanVect --jdk path/to/targetJDK/bin/ --enable_profile_guide true

Show Cases of Detected Bugs

[log.txt](..%2Ffuzz%2Fmutants%2FTest0001_02_02_23_02_36%2Flog.txt) JDK-8322743

JDK-8322743: assert(held_monitor_count() == jni_monitor_count())

synchronized void write(char[] data, int offset, int length) throws IOException {
    while (--length >= 0) {
        synchronized (new Test8267042()) {
            int var1 = 0;
            while (var1 < 100000) {
                if (var1 == 50000) {
                    getZeroOnStack(offset);
                }
                var1++;
            }
        }
        // original code
        // getZeroOnStack(offset);
        write(data[offset++]);
    }
}

The cause of this bug lies in improper operations during the Just-In-Time (JIT) compiler's escape analysis and On-Stack Replacement (OSR) transformation.

This bug involves optimization processes including escape analysis and lock optimization. Specifically, JVM incorrectly identifies certain objects as non-escaping during escape analysis, leading to incorrect handling of these objects' lock states in the On-Stack Replacement (OSR) transformation, which triggers a crash.

JDK-8324174

JDK-8324174: assert(m->is_entered(current)) failed: invariant

public class Test {

    public static final int CHUNK = 10000;
    public static ArrayList<Object> arr = new ArrayList<>();

    public static void main(String[] args) {
        while (true) {
            synchronized (Test.class) {
                synchronized (new Test()) {
                    synchronized (Test.class) {
                        arr.add(new byte[CHUNK]);
                    }
                }
            }
        }
    }
}

The cause of this bug is improper handling of nested synchronized locks during the deoptimization process. The bug involves optimization processes related to deoptimization and the maintenance of synchronized locks.

JVM attempts to eliminate nested locks and locks on non-escaping allocations in the C2 compiler optimization behavior, but during deoptimization, it handles the unlocking and relocking sequence improperly (starting from the inner frame instead of the outer frame), leading to a crash during the deoptimization process.

OpenJ9 Issue #18756

Issue #18756 · eclipse-openj9/openj9 (github.com)

public class Test {
    public static final int N = 400;

    public static long instanceCount = 3L;
    public static int[] iArrFld = new int[N];

    public void mainTest(String[] strArr1) {
        for (int i0 = 0; i0 < N; i0++) {
            Test.iArrFld[i0] = -1;
        }

        for (int i14 = 343; i14 > 21; --i14) {
            Test.instanceCount += (i14 ^ Test.instanceCount);
        }

        for (int i1 = 0; i1 < N; ++i1) {
            for (int var6 = 0; var6 < 10000; ++var6) {
                if (var6 == 4) {
                }
            }

            int[] tmp = new int[N];
            for (int i2 = 0; i2 < N; i2++) {
                tmp[i2] = 9;
            }
            Test.iArrFld = tmp;

            for (int i18 = 3; i18 < 63; i18++) {
                Test.iArrFld[i18 - 1] <<= (int) Test.instanceCount;
            }
        }

        long sum = 0;
        for (int i : Test.iArrFld) {
            sum += i;
        }
        System.out.println("sum: " + sum);
    }

    public static void main(String[] strArr) {
        Test _instance = new Test();
        _instance.mainTest(strArr);
    }
}

The cause of this bug is the improper handling of shift operation codes by the JVM during automatic SIMD (Single Instruction, Multiple Data) optimization, leading to behavior inconsistent with Java semantics. This bug involves the optimization process of automatic SIMD optimization. Specifically, the JVM improperly handled the VSHL (Vector Shift Left) operation code during the execution of automatic SIMD optimization.

Profile Flags

JVM Flags and the Corresponding Regular Expression Rules for Profiling Optimization Behaviors

JVM FlagsOptimization Behavior TypesRegular Rules
TraceLoopOptsB1: Loop UnrollingUnroll [0-9]+
B2: Loop Peeling(Partial)?Peel\s{2}
B3: Parallel Induction VariablesParallel IV: [0-9]+
B4: Split if^SplitIf$
TraceLoopUnswitchingB5: Loop UnswitchingLoop unswitching orig: [0-9]+ @ [0-9]+ new:
PrintCEEB6: Conditional Expression Elimination[0-9]+\. CEE in B[0-9]+ (B[0-9]+ B[0-9]+)
PrintInliningB7: Function Inlininginline(\s\(hot\))?$
TraceDeoptimizationB8: DeoptimizationUncommon trap
PrintEscapeAnalysisB9: Escape Analysis(UnknownEscape|NoEscape|GlobalEscape|ArgEscape)
PrintEliminateLocksB10: Eliminate Locks(Eliminated: [0-9]+ (Lock|Unlock)|unique_lock)
B11: Locks Coarsening(Coarsened [0-9]+ unlocks|unbalanced coarsened)
PrintOptoStatisticsB12: Conditional Constant PropagationCCP: [0-9]+
PrintEliminateAllocationsB13: Eliminate AutoboxEliminated: [0-9]+ (Allocate|AllocateArray)*
PrintBlockEliminationB14: Block Elimination(replaced If and IfOp|merged B[0-9]+)
PrintPhiFunctionsB15: simplify Phi Functiontry_merge for block B[0-9]+ successful
PrintCanonicalizationB16: Canonicalization^canonicalized to:$
PrintNullCheckEliminationB17: Null Check EliminationDone with null check elimination for method
TraceRangeCheckEliminationB18: Range Check EliminationRange check for instruction [0-9]+ eliminated
PrintOptimizePtrCompareB19: Optimize Ptr Compare\+\+\+\+ Replaced: [0-9]+

Confirmed Bugs

Since unconfirmed bugs cannot be shown in Java Bug System(JBS), we only show the bugs that are confirmed by developers.

OpenJDK Bugs

Bug IDAffected VersionsLink
JDK-831274111https://bugs.openjdk.org/browse/JDK-8312741
JDK-831243811https://bugs.openjdk.org/browse/JDK-8312438
JDK-83227438, 11, 17, 20, 21, 22, 23https://bugs.openjdk.org/browse/JDK-8322743
JDK-83241748, 11, 17, 21, 22, 23https://bugs.openjdk.org/browse/JDK-8324174
JDK-831274422https://bugs.openjdk.org/browse/JDK-8312744
JDK-831274822https://bugs.openjdk.org/browse/JDK-8312748
JDK-831591617, 20, 21, 22https://bugs.openjdk.org/browse/JDK-8315916
JDK-832496917, 21, 23https://bugs.openjdk.org/browse/JDK-8324969
JDK-832503011, 17, 21, 23https://bugs.openjdk.org/browse/JDK-8325030
JDK-832473915, 17, 21, 23https://bugs.openjdk.org/browse/JDK-8324739
JDK-832975717, 21, 22, 23https://bugs.openjdk.org/browse/JDK-8329757
JDK-831399217https://bugs.openjdk.org/browse/JDK-8313992
JDK-832953423https://bugs.openjdk.org/browse/JDK-8329534
JDK-832350722https://bugs.openjdk.org/browse/JDK-8323507
JDK-832786815, 17, 21, 22, 23https://bugs.openjdk.org/browse/JDK-8327868
JDK-83248928https://bugs.openjdk.org/browse/JDK-8324892
JDK-83248538https://bugs.openjdk.org/browse/JDK-8324853
JDK-83255238https://bugs.openjdk.org/browse/JDK-8325523
JDK-83243398https://bugs.openjdk.org/browse/JDK-8324339
JDK-83168628https://bugs.openjdk.org/browse/JDK-8316862
JDK-83182918https://bugs.openjdk.org/browse/JDK-8318291
JDK-83188868, 11https://bugs.openjdk.org/browse/JDK-8318886
JDK-83168638https://bugs.openjdk.org/browse/JDK-8316863
JDK-83175048https://bugs.openjdk.org/browse/JDK-8317504
JDK-83175068https://bugs.openjdk.org/browse/JDK-8317506
JDK-83168648https://bugs.openjdk.org/browse/JDK-8316864
JDK-83169508https://bugs.openjdk.org/browse/JDK-8316950
JDK-832699215, 17, 19https://bugs.openjdk.org/browse/JDK-8326992
JDK-831729917, 20, 22, 23https://bugs.openjdk.org/browse/JDK-8317299
JDK-832953623https://bugs.openjdk.org/browse/JDK-8329536
JDK-832953517, 23https://bugs.openjdk.org/browse/JDK-8329535
JDK-83168658https://bugs.openjdk.org/browse/JDK-8316865
JDK-83168668, 11https://bugs.openjdk.org/browse/JDK-8316866
JDK-832368611https://bugs.openjdk.org/browse/JDK-8323686
JDK-83169528https://bugs.openjdk.org/browse/JDK-8316952
JDK-83173018https://bugs.openjdk.org/browse/JDK-8317301
JDK-83169398https://bugs.openjdk.org/browse/JDK-8316939
JDK-832998415, 17, 21, 23https://bugs.openjdk.org/browse/JDK-8329984
JDK-83175768https://bugs.openjdk.org/browse/JDK-8317576
JDK-83178168, 11https://bugs.openjdk.org/browse/JDK-8317816
JDK-83169378https://bugs.openjdk.org/browse/JDK-8316937
JDK-83169498https://bugs.openjdk.org/browse/JDK-8316949
JDK-83172368https://bugs.openjdk.org/browse/JDK-8317236
JDK-83173468https://bugs.openjdk.org/browse/JDK-8317346
JDK-83248018https://bugs.openjdk.org/browse/JDK-8324801

OpenJ9 Bugs

Issue IDLink
Issue #18756https://github.com/eclipse-openj9/openj9/issues/18756
Issue #18765https://github.com/eclipse-openj9/openj9/issues/18765
Issue #18777https://github.com/eclipse-openj9/openj9/issues/18777
Issue #18919https://github.com/eclipse-openj9/openj9/issues/18919
Issue #18860https://github.com/eclipse-openj9/openj9/issues/18860
Issue #18836https://github.com/eclipse-openj9/openj9/issues/18836
Issue #18834https://github.com/eclipse-openj9/openj9/issues/18834
Issue #18955https://github.com/eclipse-openj9/openj9/issues/18955
Issue #19220https://github.com/eclipse-openj9/openj9/issues/19220
Issue #19079https://github.com/eclipse-openj9/openj9/issues/19079
Issue #19012https://github.com/eclipse-openj9/openj9/issues/19012
Issue #19013https://github.com/eclipse-openj9/openj9/issues/19013
Issue #19218https://github.com/eclipse-openj9/openj9/issues/19218
Issue #19080https://github.com/eclipse-openj9/openj9/issues/19080