OPAL is an OPen, extensible Analysis Library for Java bytecode which is written in Scala and which consist of multiple projects which build on top of each other. At the core is a newly developed, highly configurable and adaptable bytecode toolkit. On top of that we provide you with a framework for the abstract interpretation of Java Bytecode. These two frameworks are the foundation for various tools targeted towards developers who want to improve the quality of their software. In particular tools for specifying and validating software architectures as well as for finding bugs.



The BugPicker is a tool for finding data-flow dependent issues in your source code.

Software Quality Assurance using BugPicker

BugPicker helps you to identify data-flow dependent bugs and issues in your source code and was successfully used to identify numerous issues in industrial-strength, mature source code.

First Example

One trivial issue found in the Open JDK 8/9:
public int getGlyphCharIndex(int ix) {
	if (ix < 0 && ix >= glyphs.length) {
		throw new IndexOutOfBoundsException("" + ix);
In this case the condition will never evaluate to true and, hence, the IndexOutOtBoundsException will never be thrown.
Here, the developer probably wanted to use the logical or operator (||) instead of the logical and operator (&&).

Second Example

A more complex example found in the Open JDK 8:
if (maxBits > 4 || maxBits < 8) {
	maxBits = 8;
if (maxBits > 8) {
	maxBits = 16;
Here, the developer probably wanted to use the logical and operator (&&) in the first line instead of the logical or operator (||) and also wanted to write maxBits <= 8. However, given the current code the condition of the first if statement will always evaluate to true and, hence, the condition of the second if statement will always evaluate to false. That is, maxBits will always be 8.


The Core Frameworks

Bytecode Representation

OPAL's native Java bytecode representation makes it easy to write concise, expressive and powerful analyses.
Building on top of Scala, OPAL provides an API that offers extensive support for pattern matching on Java bytecode. This greatly facilitates writing analyses that identify typical bug patterns. For example, let's write an analysis to find instances of the following issue:
double value = 1.0d;
int i = (new Double(value)).intValue // << the issue
//Intended: int i = (int) value
I.e., let's find code where we wrap a primitive value and immediately unwrap it. (Such code generally hinders comprehensibility and wastes CPU cycles; a real instance can be found in the OpenJDK 8.)

The complete(!) analysis to find the described bug pattern is shown next.
import org.opalj.br._
import org.opalj.br.instructions._
import org.opalj.br.reader.Java8Framework.ClassFiles

val project = ClassFiles(new java.io.File("/Library/Java/JavaVirtualMachines/jdk1.8.0.jdk/Contents/Home/jre/lib"))
val theMethods = Set(
for {
    classFile ← project.par.map(_._1) // for all classes (let's do it in parallel)
    method @ MethodWithBody(body) ← classFile.methods // for all non-abstract, non-native methods
    pc ← body.matchPair({ // find a sequence of two instructions where...
        case (
            INVOKESPECIAL(receiver1, _, TheArgument(parameterType: BaseType)),
            INVOKEVIRTUAL(receiver2, name, NoArgumentMethodDescriptor(returnType: BaseType))
            ) ⇒ { (receiver1 eq receiver2) &&
                   receiver1.isPrimitiveTypeWrapper &&
                   theMethods.contains(name) }
        case _ ⇒ false
} println (classFile.fqn +"{"+ method.toJava+"::"+ method.body.get.lineNumber(pc)+"}")
You can paste the analysis in the Scala REPL to directly execute it. In this case, you'll get – for the OpenJDK 8 – the following result:
com/sun/org/apache/xalan/internal/lib/ExsltMath{double constant(java.lang.String,double)::Some(379)}
On a notebook (Core i7, 2,3 GHz, 8GB, SSD) loading the JDK takes 2 to 3 seconds, the analysis itself takes roughly 0.04 seconds for the entire JDK.

Read more about OPAL's bytecode representation...

Abstract Interpretation

OPAL implements a scalable, highly customizable framework for the abstract interpretation of Java bytecode.
The abstract interpretation framework is an easily useable and also extensible framework that greatly facilitates the development of static analyses that require data-flow information.

For example, let's assume that we want to develop an analysis that finds conditions (e.g., a < b) that always result in the same value (i.e., we can statically determine that the condition is always true or false).

Such an analysis could detect code such as the following one (taken from Java 8's com.sun.imageio.plugins.png.PNGMetadata { void mergeStandardTree (...) } - line 1842ff):
if (maxBits > 4 || maxBits < 8) {
	maxBits = 8;
if (maxBits > 8) { // [Identified:] always evaluates to false
	maxBits = 16;
In this case, the developer probably wanted to use the && operator in the first line. However, the condition of the second if will always evaluate to false.

The complete code of the analysis is shown next and demonstrates the most basic usage of the abstract interpretation framework. The idea is to iterate over all methods and to perform a simple, abstract interpretation of each method. After the abstract interpretation check for each condition if it always compares two simple values and – if so – reports that case.

package org.opalj
package ai

import java.net.URL
import org.opalj.br._
import org.opalj.br.analyses._
import org.opalj.br.instructions.IFICMPInstruction

object UselessComputationsMinimal extends AnalysisExecutor with Analysis[URL, BasicReport] {

    val analysis = this

    class AnalysisDomain(val project: Project[URL], val method: Method)
        extends Domain
        with domain.DefaultDomainValueBinding
        with domain.DefaultHandlingOfMethodResults
        with domain.IgnoreSynchronization
        with domain.ThrowAllPotentialExceptionsConfiguration
        with domain.l0.DefaultTypeLevelFloatValues
        with domain.l0.DefaultTypeLevelDoubleValues
        with domain.l0.TypeLevelFieldAccessInstructions
        with domain.l0.TypeLevelInvokeInstructions
        with domain.l1.DefaultReferenceValuesBinding
        with domain.l1.DefaultIntegerRangeValues
        with domain.l1.DefaultLongValues
        with domain.l1.DefaultConcretePrimitiveValuesConversions
        with domain.l1.LongValuesShiftOperators
        with domain.TheProject[java.net.URL]
        with domain.TheMethod
        with domain.ProjectBasedClassHierarchy

    def analyze(theProject: Project[URL], parameters: Seq[String]) = {

        val results = (for {
            clazz ← theProject.classFiles.par
            method @ MethodWithBody(body) ← clazz.methods
            result = BaseAI(clazz, method, new AnalysisDomain(theProject, method))
        } yield {
            import result.domain.ConcreteIntegerValue
            collectWithOperandsAndIndex(result.domain)(body, result.operandsArray) {
                case (
                    pc, _: IFICMPInstruction, Seq(ConcreteIntegerValue(a), ConcreteIntegerValue(b), _*)
                    ) ⇒
                    s"${clazz.thisType.toJava}{${method.toJava}{/*pc=$pc:*/ useless comp.: $a and $b}}"

        BasicReport(results.mkString(s"${results.size} Useless code:\n", "\n", "\n"))

Sourcecode Dependencies

OPAL supports the extraction of dependencies between source code elements to facilitate the writing of software quality tools.

Dependencies between the top-level packages of the OpenJDK 8.

If you move your mouse over a connection you'll get further information about the direction of the dependencies.



The overall goal of OPAL is to provide a library and tools that help to improve software quality!


We are always searching for motivated individuals who want to develop cool static analyses.

We are in particular looking for motivated students who want to do a Bachelor or Master Thesis in the context of the OPAL project. Alternatively, we regularly offer a lab if you just want to code and don't want to write a thesis.

If you want to contribute to OPAL contact me or come to my office TU Darmstadt, Building S2/02, Software Technology Group, Room A206.