blob: 9bf81a11879066881288d86275e377f9426bb993 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/
package org.codehaus.groovy.ant;
import org.apache.tools.ant.BuildException;
import org.apache.tools.ant.taskdefs.MatchingTask;
import org.objectweb.asm.ClassReader;
import org.objectweb.asm.ClassWriter;
import org.objectweb.asm.tree.AbstractInsnNode;
import org.objectweb.asm.tree.ClassNode;
import org.objectweb.asm.tree.MethodNode;
import org.objectweb.asm.tree.analysis.Analyzer;
import org.objectweb.asm.tree.analysis.SimpleVerifier;
import org.objectweb.asm.util.CheckClassAdapter;
import org.objectweb.asm.util.TraceMethodVisitor;
import java.io.BufferedInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
/**
* Verify Class files. This task can take the following
* arguments:
* <ul>
* <li>dir
* </ul>
* When this task executes, it will recursively scan the dir and
* look for class files to verify.
*/
public class VerifyClass extends MatchingTask {
private String topDir = null;
private boolean verbose = false;
public VerifyClass() {
}
@Override
public void execute() throws BuildException {
if (topDir == null) throw new BuildException("no dir attribute is set");
File top = new File(topDir);
if (!top.exists()) throw new BuildException("the directory " + top + " does not exist");
log("top dir is " + top);
int fails = execute(top);
if (fails == 0) {
log("no bytecode problems found");
} else {
log("found " + fails + " failing classes");
}
}
public void setDir(String dir) throws BuildException {
topDir = dir;
}
public void setVerbose(boolean v) {
verbose = v;
}
private int execute(File dir) {
int fails = 0;
File[] files = dir.listFiles();
if (files != null) {
for (File f : files) {
if (f.isDirectory()) {
fails += execute(f);
} else if (f.getName().endsWith(".class")) {
try {
boolean ok = readClass(f.getCanonicalPath());
if (!ok) fails++;
} catch (IOException ioe) {
log(ioe.getMessage());
throw new BuildException(ioe);
}
}
}
}
return fails;
}
private boolean readClass(String clazz) throws IOException {
ClassNode ca;
try (final InputStream inputStream =
new BufferedInputStream(
new FileInputStream(clazz))) {
ClassReader cr = new ClassReader(inputStream);
ca = new ClassNode() {
@Override
public void visitEnd() {
//accept(cv);
}
};
cr.accept(new CheckClassAdapter(ca), ClassWriter.COMPUTE_MAXS);
}
boolean failed = false;
List<MethodNode> methods = ca.methods;
for (MethodNode method : methods) {
if (method.instructions.size() > 0) {
Analyzer<?> a = new Analyzer<>(new SimpleVerifier());
try {
a.analyze(ca.name, method);
continue;
} catch (Exception e) {
e.printStackTrace();
}
if (!failed) {
failed = true;
log("verifying of class " + clazz + " failed");
}
if (verbose) log(method.name + method.desc);
TraceMethodVisitor mv = new TraceMethodVisitor(null);
for (int j = 0; j < method.instructions.size(); ++j) {
AbstractInsnNode insn = method.instructions.get(j);
if (insn != null) {
insn.accept(mv);
} else {
mv.visitLabel(null);
}
}
mv.visitMaxs(0, 0);
}
}
return !failed;
}
}