Tools for finding Shared Mutable data bugs in Java Tools for finding Shared Mutable data bugs in Java multithreading multithreading

Tools for finding Shared Mutable data bugs in Java


Chris Grindstaff wrote an article FindBugs, Part 2: Writing custom detectors in which he describes how to use the BCEL to add your own rules. (BCEL isn't the only bytecode library - but it is the one used by FindBugs.)

The code below emits any cases where a method accesses a static method or field. You could run it on any type that implements Runnable.

public class StaticInvocationFinder extends EmptyVisitor {    @Override    public void visitMethod(Method obj) {        System.out.println("==========================");        System.out.println("method:" + obj.getName());        Code code = obj.getCode();        InstructionList instructions = new InstructionList(code.getCode());        for (Instruction instruction : instructions.getInstructions()) {            // static field or method            if (Constants.INVOKESTATIC == instruction.getOpcode()) {                if (instruction instanceof InvokeInstruction) {                    InvokeInstruction invokeInstruction = (InvokeInstruction) instruction;                    ConstantPoolGen cpg = new ConstantPoolGen(obj                            .getConstantPool());                    System.out.println("static access:"                            + invokeInstruction.getMethodName(cpg));                    System.out.println("      on type:"                            + invokeInstruction.getReferenceType(cpg));                }            }        }        instructions.dispose();    }    public static void main(String[] args) throws Exception {        JavaClass javaClass = Repository.lookupClass("StopThread$1");        StaticInvocationFinder visitor = new StaticInvocationFinder();        DescendingVisitor classWalker = new DescendingVisitor(javaClass,                visitor);        classWalker.visit();    }}

This code emits the following:

==========================method:<init>==========================method:runstatic access:access$0      on type:StopThread

It would be possible to then scan the type StopThread, find the field and check to see if it is volatile.

Checking for synchronization is possible, but might get tricky due to multiple MONITOREXIT conditions. Walking up call stacks could be difficult too, but then this isn't a trivial problem. However, I think it would be relatively easy to check for a bug pattern if it has been implemented consistently.

BCEL looks scantly documented and really hairy until you find the BCELifier class. If you run it on a class, it spits out Java source of how you would build the class in BCEL. Running it on StopThread gives this for generating the access$0 synthetic accessor:

  private void createMethod_2() {    InstructionList il = new InstructionList();    MethodGen method = new MethodGen(ACC_STATIC | ACC_SYNTHETIC, Type.BOOLEAN, Type.NO_ARGS, new String[] {  }, "access$0", "StopThread", il, _cp);    InstructionHandle ih_0 = il.append(_factory.createFieldAccess("StopThread", "stopRequested", Type.BOOLEAN, Constants.GETSTATIC));    il.append(_factory.createReturn(Type.INT));    method.setMaxStack();    method.setMaxLocals();    _cg.addMethod(method.getMethod());    il.dispose();  }


The latest version of FindBugs will attempt to check that fields marked with the @GuardedBy annotation are accessed only within the appropriate guard code.


Coverity Thread Analyzer does the job, but that is quite expensive. IBM Multi-Thread Run-time Analysis Tool for Java seems to be able to detect those but it appears somewhat more difficult to set up. These are dynamical analysis tools that detect which actual variables were accessed from different threads without proper synchronization or volatility, so results are more accurate than with static analysis, and are able to find lots of issues that static analysis is unable to detect.

If your code is mostly or at least partly properly synchronized, fixing FindBugs (or other static analysis) concurrency checks might help too, at least rules IS2_INCONSISTENT_SYNC and UG_SYNC_SET_UNSYNC_GET might be good ones to start with.