Tools for finding Shared Mutable data bugs in Java
I have a large legacy system to maintain. The codebase uses threads all over the place and those threads share a lot of mutable data. I know, sounds bad. Anyway, don't answer "rewrite the whole application from scratch" or I'll vote you down :-) I have tried to run some static analysis tools on the codebase, but none of those seem to catch this case which occurs a lot in our source code: multiple threads are reading and writing variables which are not marked as volatile or synchronized at all. Typically this occurs on "runFlag"-type variables. An example of this is on Effective Java 2nd edition page 260:
public class StopThread
{
private static boolean stopRequested;
public static void main(String[] args) throws InterruptedException
{
Thread backgroundThread = new Thread(new Runnable()
{
public void run()
{
int i = 0;
while (!stopRequested)
{
i++;
}
}
});
backgroundThread.start();
Thread.sleep(1000);
stopRequested = true;
}
}
This example never finishes on Windows/Linux with "-server" startup parameter given to Sun JVM. So, is there any (semi-)automatic way to find these issues, or do I have to rely totally on code reviews?
Asked by: Brad805 | Posted: 21-01-2022
Answer 1
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:run
static 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();
}
Answered by: Lenny990 | Posted: 22-02-2022
Answer 2
The latest version of FindBugs will attempt to check that fields marked with the @GuardedBy
annotation are accessed only within the appropriate guard code.
Answer 3
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.
Answered by: Roman774 | Posted: 22-02-2022Answer 4
FindBugs and professional tools based on it are your best hope, but don't count on them finding all of the concurrency woes in your code.
If things are in that bad a shape, then you should supplement the tooling with analysis by a human java concurrency expert.
This is a hard problem because conclusively prooving the correctness of an existing, but modified, code base is probably going to be unrealistic - especially in the face of concurrent usage.
Answered by: Aston524 | Posted: 22-02-2022Answer 5
Coverity makes some static and dynamic analysis tools that may help.
Answered by: Kellan159 | Posted: 22-02-2022Similar questions
java - Finding element using multithreading takes double the time of a single thread
I am trying something similar to Search for an element in array with threads. Instead of using an actual array, the target value will be between 0 and Integer.MAX_VALUE * 10L and the goal is to find that target through the usage of a simple for loop.
The Searcher class w...
multithreading - Java BlockingQueue of Size=1?
Essentially what I want is a BlockingQueue of size=1. I have a "listener" thread that simply waits, blocking until an object is put into the queue, and then retrieves it--and a "producer" thread that actually puts the object into the queue.
I can implement this with some synchronized blocks and a BlockingQueue implementation, but that seems like overkill. Is there a better, simpler way to do what I want?
Ex...
multithreading - HTTP posts and multiple threads in Java
I am writing an internal Java Applet to do file uploads via HTTP. I started using the built in ClientHttpRequest which worked great if I want to post one after another. When I try to have multiple threads post at the same time, something on the server side freaks out and the connection will hang for large files while still uploading the smaller files. (Large seems to be around 10 megs) After lots of looking, I would no...
multithreading - synchronizing io operation in java on a string method argument?
This question already has answers here:
multithreading - Stopping a Thread in Java?
This question already has answers here:
multithreading - Threading issues in a Java HashMap
Something happened that I'm not sure should be possible. Obviously it is, because I've seen it, but I need to find the root cause & I was hoping you all could help.
We have a system that looks up latitude & longitude for a zipcode. Rather than access it every time, we cache the results in a cheap in-memory HashTable cache, since the lat & long of a zip code tend to change less often than we release.
multithreading - Firing a mainline event from a background thread in Java
My question pertains to multi-threading in Java. I'm translating an app I wrote in Visual Basic 2008 into Java. There is a class in VB called BackgroundWorker, which allows the coder to perform a task on another thread, a lot like SwingWorker in Java. The only distinct difference ...
multithreading - Java: Run a Callable in a separate process
Given an instance x of Callable<T>, how can I run x in a separate process such that I can redirect the standard input and output of the process? For example, is there a way to build a Process from a Callable? Is there a standard Executor that gives control over input and output?
[UPDATE] It's not important that the Callable
multithreading - How can you ensure in java that a block of code can not be interrupted by any other thread
exampl:
new Thread(new Runnable() {
public void run() {
while(condition) {
*code that must not be interrupted*
*some more code*
}
}
}).start();
SomeOtherThread.start();
YetAntherThread.start();
How can you ensure that code that must not be interrupted won't be interrupted?
multithreading - Java while loop and Threads!
This question already has answers here:
multithreading - In Java critical sections, what should I synchronize on?
In Java, the idiomatic way to declare critical sections in the code is the following:
private void doSomething() {
// thread-safe code
synchronized(this) {
// thread-unsafe code
}
// thread-safe code
}
Almost all blocks synchronize on this, but is there a particular reason for this? Are there other possibilities? Are there any best practices on what object to sync...
Still can't find your answer? Check out these amazing Java communities for help...
Java Reddit Community | Java Help Reddit Community | Dev.to Java Community | Java Discord | Java Programmers (Facebook) | Java developers (Facebook)