1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
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
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 }