Chinaunix首页 | 论坛 | 博客
  • 博客访问: 1996995
  • 博文数量: 1647
  • 博客积分: 80000
  • 博客等级: 元帅
  • 技术积分: 9980
  • 用 户 组: 普通用户
  • 注册时间: 2008-10-13 15:15
文章分类

全部博文(1647)

文章存档

2011年(1)

2008年(1646)

我的朋友

分类:

2008-10-28 18:17:17

编写 RuntimeException 捕获检测器

    正如您在 中所学的,编写 bug 模式的第一个步骤是清楚地标识 bug 模式。在这里,bug 模式是捕获 Exceptioncatch 块,这时不存在用于 RuntimeException 的相应捕获块,并且尝试块中的任何方法调用或 throw 语句都不会抛出 Exception。要检测此 bug 模式,则需要知道 try-catch 块的位置、try 块可能抛出的内容以及在 catch 块中将捕获的内容。

    像上个月的操作一样,您可以通过创建 BytecodeScanningDetector 基础类(可实现 Visitor 模式)的子类启动 bug 检测器。在 BytecodeScanningDetector 中有一个 visit(Code) 方法,并且在每次发现 catch 块时,该实现都会调用 visit(CodeException)。如果重写 visit(Code),并从那里调用 super.visit(Code),则当超类 visit(Code) 返回时,它将调用用于该方法中所有 catch 块的 visit(CodeException)。清单 4 了显示实现 visit(Code)visit(CodeException) 的第一步,它将积累方法中所有 catch 块的信息。每个 CodeException 都包含相应 try 块的起始和终止的字节码偏移量,这样您可以方便地确定哪一个 CodeException 对象与 try-catch 块对应。



public class RuntimeExceptionCapture extends BytecodeScanningDetector {
  private BugReporter bugReporter;
  private Method method;
  private OpcodeStack stack = new OpcodeStack();
  private List catchList;
  private List throwList;
  public void visitMethod(Method method) {
    this.method = method;
    super.visitMethod(method)   }
  public void visitCode(Code obj) {
    catchList = new ArrayList();
    throwList = new ArrayList();
    stack.resetForMethodEntry(this);
    super.visitCode(obj);
    // At this point, we've identified all the catch blocks
    // More to come...
  }
  public void visit(CodeException obj) {
    super.visit(obj);
    int type = obj.getCatchType();
    if (type == 0) return;
    String name = 
      getConstantPool().constantToString(getConstantPool().getConstant(type));
    ExceptionCaught caughtException =
new ExceptionCaught(name, obj.getStartPC(), obj.getEndPC(), obj.getHandlerPC());
    catchList.add(caughtException);
  }
}
      

    此时,您已获得了您需要的一半信息:在何处捕获哪些异常。现在必须找出哪些异常被抛出。为此,您需要重写 BytecodeScanningDetectorsawOpcode() 方法,并处理与方法调用和异常抛出相对应的字节码。可以根据 athrow JVM 指令抛出异常。三个 JVM 指令分别用于调用以下方法:invokestaticinvokevirtualinvokespecial。就像使用 visit(CodeException) 一样,在调用超类 visit(Code) 时可以调用 sawOpcode,这样,如果在 sawOpcode() 中收集信息,那么在 super.visit(Code) 返回时,您将获得您需要的、有关捕获和抛出异常的所有信息。

    清单 5 显示了 sawOpcode() 的实现,它将处理上述 JVM 指令。对于 athrow 指令,可以使用 FindBugs 的 OpcodeStack 帮助器类来了解 athrow 操作数的类型。对于方法调用指令,可以使用 Bytecode Engineering Library (BCEL) 类来提取方法声明抛出的已检查异常的类型。在任何一种情况下,都可以积累关于哪些异常在方法中的哪个字节码偏移量被抛出的信息,这样,在完成整个方法的处理后,可以将它们进行匹配。



public void sawOpcode(int seen) {
  stack.mergeJumps(this);
  try {
      switch (seen) {
      case ATHROW:
          if (stack.getStackDepth() > 0) {
              OpcodeStack.Item item = stack.getStackItem(0);
              String signature = item.getSignature();
              if (signature != null && signature.length() > 0) {
                  if (signature.startsWith("L"))
                      signature = SignatureConverter.convert(signature);
                  else
                      signature = signature.replace('/', '.');
                  throwList.add(new ExceptionThrown(signature, getPC()));
              }
          }
          break;
      case INVOKEVIRTUAL:
      case INVOKESPECIAL:
      case INVOKESTATIC:
          String className = getDottedClassConstantOperand();
          try {
              if (!className.startsWith("[")) {
                  Class clazz = Repository.lookupClass(className);
                  Method[] methods = clazz.getMethods();
                  for (Method method : methods) {
                      if (method.getName().equals(getNameConstantOperand())
                 && method.getSignature().equals(getSigConstantOperand())) {
                          ExceptionTable et = method.getExceptionTable();
                          if (et != null) {
                              String[] names = et.getExceptionNames();
                              for (String name : names)
                          throwList.add(new ExceptionThrown(name, getPC()));
                          }
                          break;
                      }
                  }
              }
          } catch (ClassNotFoundException e) {
              bugReporter.reportMissingClass(e);
          }
          break;
      default:
          break;
      }
  } finally {
      stack.sawOpcode(this, seen);
  }
}
      

 

   [2]  

【责编:Peng】

--------------------next---------------------
public void sawOpcode(int seen) {
  stack.mergeJumps(this);
  try {
      switch (seen) {
      case ATHROW:
          if (stack.getStackDepth() > 0) {
              OpcodeStack.Item item = stack.getStackItem(0);
              String signature = item.getSignature();
              if (signature != null && signature.length() > 0) {
                  if (signature.startsWith("L"))
                      signature = SignatureConverter.convert(signature);
                  else
                      signature = signature.replace('/', '.');
                  throwList.add(new ExceptionThrown(signature, getPC()));
              }
          }
          break;
      case INVOKEVIRTUAL:
      case INVOKESPECIAL:
      case INVOKESTATIC:
          String className = getDottedClassConstantOperand();
          try {
              if (!className.startsWith("[")) {
                  Class clazz = Repository.lookupClass(className);
                  Method[] methods = clazz.getMethods();
                  for (Method method : methods) {
                      if (method.getName().equals(getNameConstantOperand())
                 && method.getSignature().equals(getSigConstantOperand())) {
                          ExceptionTable et = method.getExceptionTable();
                          if (et != null) {
                              String[] names = et.getExceptionNames();
                              for (String name : names)
                          throwList.add(new ExceptionThrown(name, getPC()));
                          }
                          break;
                      }
                  }
              }
          } catch (ClassNotFoundException e) {
              bugReporter.reportMissingClass(e);
          }
          break;
      default:
          break;
      }
  } finally {
      stack.sawOpcode(this, seen);
  }
}
      

--------------------next---------------------

阅读(303) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~