用于在Java中查找Shared Mutable数据错误的工具 [英] Tools for finding Shared Mutable data bugs in Java

查看:127
本文介绍了用于在Java中查找Shared Mutable数据错误的工具的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个庞大的遗留系统需要维护。代码库使用遍布各处的线程,这些线程共享大量可变数据。我知道,听起来不错。无论如何,不​​回答从头开始重写整个应用程序或者我会投票给你:-)我试图在代码库上运行一些静态分析工具,但这些似乎都没有抓住这种情况发生了很多在我们的源代码中:多个线程正在读取和写入未标记为volatile或同步的变量。通常这发生在runFlag类型的变量上。这方面的一个例子是在Effective Java第2版第260页:

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;
    }
}

这个例子永远不会在Windows / Linux上完成 - 服务器提供给Sun JVM的启动参数。那么,是否有任何(半)自动方式来查找这些问题,或者我是否必须完全依赖代码审查?

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?

推荐答案

< Chris Grindstaff写了一篇文章 FindBugs,第2部分:编写自定义探测器其中他描述了如何使用 BCEL 添加您自己的规则。 (BCEL不是唯一的字节码库 - 但它是FindBugs使用的字节码库。)

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.)

下面的代码会发出方法访问静态方法或字段的任何情况。您可以在任何实现 Runnable 的类型上运行它。

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

然后可以扫描类型 StopThread ,找到该字段并检查它是否 volatile

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

检查同步是可能的,但由于多个MONITOREXIT条件可能会变得棘手。向上调用堆栈也很困难,但这不是一个小问题。但是,我认为检查错误模式是否相对容易,如果它已经一致地实现。

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看起来很难记录并且非常毛茸茸直到找到 BCELifier 类。如果你在一个类上运行它,它会向你发出如何在BCEL中构建类的Java源代码。在 StopThread 上运行它可以生成 access $ 0 合成访问器:

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();
  }

这篇关于用于在Java中查找Shared Mutable数据错误的工具的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆