View Javadoc

1   /*
2    $Id: VerifyClass.java,v 1.3 2006/01/19 00:06:50 blackdrag Exp $
3   
4    Copyright 2003 (C) James Strachan and Bob Mcwhirter. All Rights Reserved.
5   
6    Redistribution and use of this software and associated documentation
7    ("Software"), with or without modification, are permitted provided
8    that the following conditions are met:
9   
10   1. Redistributions of source code must retain copyright
11      statements and notices.  Redistributions must also contain a
12      copy of this document.
13  
14   2. Redistributions in binary form must reproduce the
15      above copyright notice, this list of conditions and the
16      following disclaimer in the documentation and/or other
17      materials provided with the distribution.
18  
19   3. The name "groovy" must not be used to endorse or promote
20      products derived from this Software without prior written
21      permission of The Codehaus.  For written permission,
22      please contact info@codehaus.org.
23  
24   4. Products derived from this Software may not be called "groovy"
25      nor may "groovy" appear in their names without prior written
26      permission of The Codehaus. "groovy" is a registered
27      trademark of The Codehaus.
28  
29   5. Due credit should be given to The Codehaus -
30      http://groovy.codehaus.org/
31  
32   THIS SOFTWARE IS PROVIDED BY THE CODEHAUS AND CONTRIBUTORS
33   ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT
34   NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
35   FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL
36   THE CODEHAUS OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
37   INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
38   (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
39   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
40   HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
41   STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
42   ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
43   OF THE POSSIBILITY OF SUCH DAMAGE.
44  
45   */
46  package org.codehaus.groovy.ant;
47  
48  import java.io.File;
49  import java.io.FileInputStream;
50  import java.io.IOException;
51  import java.util.List;
52  
53  import org.apache.tools.ant.BuildException;
54  import org.apache.tools.ant.taskdefs.MatchingTask;
55  import org.objectweb.asm.ClassReader;
56  import org.objectweb.asm.Label;
57  import org.objectweb.asm.util.CheckClassAdapter;
58  import org.objectweb.asm.util.TraceMethodVisitor;
59  import org.objectweb.asm.tree.AbstractInsnNode ;
60  import org.objectweb.asm.tree.ClassNode ;
61  import org.objectweb.asm.tree.MethodNode ;
62  import org.objectweb.asm.tree.analysis.Analyzer ;
63  import org.objectweb.asm.tree.analysis.Frame ;
64  import org.objectweb.asm.tree.analysis.SimpleVerifier ;
65  
66  /***
67   * Verify Class files. This task can take the following
68   * arguments:
69   * <ul>
70   * <li>dir
71   * </ul>
72   * When this task executes, it will recursively scan the dir and 
73   * look for class files to verify.  
74   */
75  public class VerifyClass extends MatchingTask {
76      private String topDir=null;
77      private boolean verbose = false;
78      
79      public VerifyClass() {}
80  
81      public void execute() throws BuildException {
82          if (topDir==null) throw new BuildException("no dir attribute is set");
83          File top = new File(topDir);
84          if (!top.exists()) throw new BuildException("the directory "+top+" does not exist");
85          log ("top dir is "+top);
86          int fails = execute(top);
87          if (fails==0) {
88              log ("no bytecode problems found");
89          } else {
90              log ("found "+fails+" failing classes");
91          }
92      }
93      
94      public void setDir(String dir) throws BuildException {
95          topDir = dir;
96      }
97      
98      public void setVerbose(boolean v) {
99          verbose = v;
100     }
101     
102     private int execute(File dir) {
103         int fails = 0;
104         File[] files = dir.listFiles();
105         for (int i = 0; i < files.length; i++) {
106             File f =files[i];
107             if (f.isDirectory()) {
108                 fails += execute(f);
109             } else if (f.getName().endsWith(".class")) {
110                 try {
111                     boolean ok = readClass(f.getCanonicalPath());
112                     if (!ok) fails++;
113                 } catch (IOException ioe) {
114                     log(ioe.getMessage());
115                     throw new BuildException(ioe);
116                 } 
117             }
118         }
119         return fails;
120     }
121     
122     private boolean readClass(String clazz) throws IOException {
123         ClassReader cr = new ClassReader(new FileInputStream(clazz));
124         ClassNode ca = new ClassNode ( ) 
125           {
126             public void visitEnd () {
127               //accept(cv);
128             }
129           } ;
130         cr.accept(new CheckClassAdapter(ca), true);
131         boolean failed=false;
132         
133         List methods = ca.methods;
134         for (int i = 0; i < methods.size(); ++i) {
135           MethodNode method = (MethodNode)methods.get(i);
136           if (method.instructions.size() > 0) {
137             Analyzer a = new Analyzer(new SimpleVerifier());
138             try {
139               a.analyze(ca.name, method);
140               continue;
141             } catch (Exception e) {
142               e.printStackTrace();
143             }
144             final Frame[] frames = a.getFrames();
145 
146             if (!failed) {
147                 failed=true;
148                 log("verifying of class "+clazz+" failed");
149             }
150             if (verbose) log(method.name + method.desc);
151             TraceMethodVisitor cv = new TraceMethodVisitor(null) {
152               public void visitMaxs (int maxStack, int maxLocals) {
153                 StringBuffer buffer = new StringBuffer();
154                 for (int i = 0; i < text.size(); ++i) {
155                   String s = frames[i] == null ? "null" : frames[i].toString();
156                   while (s.length() < maxStack+maxLocals+1) {
157                     s += " ";
158                   }
159                   buffer.append(Integer.toString(i + 100000).substring(1));
160                   buffer.append(" ");
161                   buffer.append(s);
162                   buffer.append(" : ");
163                   buffer.append(text.get(i));
164                 }
165                 if (verbose) log(buffer.toString());
166               }
167             };
168             for (int j = 0; j < method.instructions.size(); ++j) {
169               Object insn = method.instructions.get(j);
170               if (insn instanceof AbstractInsnNode) {
171                 ((AbstractInsnNode)insn).accept(cv);
172               } else {
173                 cv.visitLabel((Label)insn);
174               }
175             }
176             cv.visitMaxs(method.maxStack, method.maxLocals);
177           }
178         }
179         return !failed;
180     }
181     
182 }