/*
* FindBugs - Find bugs in Java programs
* Copyright (C) 2004-2006 University of Maryland
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
package edu.umd.cs.findbugs.detect;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import org.apache.bcel.classfile.JavaClass;
import edu.umd.cs.findbugs.BugReporter;
import edu.umd.cs.findbugs.NonReportingDetector;
import edu.umd.cs.findbugs.OpcodeStack;
import edu.umd.cs.findbugs.ba.AnalysisContext;
import edu.umd.cs.findbugs.ba.XClass;
import edu.umd.cs.findbugs.ba.XFactory;
import edu.umd.cs.findbugs.ba.XMethod;
import edu.umd.cs.findbugs.ba.ch.Subtypes2;
import edu.umd.cs.findbugs.bcel.OpcodeStackDetector;
import edu.umd.cs.findbugs.classfile.CheckedAnalysisException;
import edu.umd.cs.findbugs.classfile.ClassDescriptor;
import edu.umd.cs.findbugs.classfile.DescriptorFactory;
import edu.umd.cs.findbugs.classfile.Global;
public class ExplicitSerialization extends OpcodeStackDetector implements NonReportingDetector {
final static XMethod writeObject = XFactory.createXMethod("java.io.ObjectOutputStream", "writeObject", "(Ljava/lang/Object;)V", false);
final static XMethod readObject = XFactory.createXMethod("java.io.ObjectInputStream", "readObject", "()Ljava/lang/Object;", false);
final static ClassDescriptor ObjectOutputStream = DescriptorFactory.createClassDescriptor(ObjectOutputStream.class);
final static ClassDescriptor ObjectInputStream = DescriptorFactory.createClassDescriptor(ObjectInputStream.class);
final UnreadFieldsData unreadFields;
final BugReporter bugReporter;
public ExplicitSerialization(BugReporter bugReporter) {
AnalysisContext context = AnalysisContext.currentAnalysisContext();
unreadFields = context.getUnreadFieldsData();
this.bugReporter = bugReporter;
}
@Override
public boolean shouldVisit(JavaClass obj) {
XClass xClass = getXClass();
return xClass.getCalledClassDescriptors().contains(ObjectOutputStream)
|| xClass.getCalledClassDescriptors().contains(ObjectInputStream);
}
@Override
public void sawOpcode(int seen) {
if (seen == INVOKEVIRTUAL && writeObject.equals(getXMethodOperand())) {
OpcodeStack.Item top = stack.getStackItem(0);
String signature = top.getSignature();
while (signature.charAt(0) == '[')
signature = signature.substring(1);
ClassDescriptor c = DescriptorFactory.createClassDescriptorFromFieldSignature(signature);
if (c == null || !Subtypes2.instanceOf(c, Serializable.class))
return;
try {
XClass xClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, c);
if (xClass.isInterface())
return;
if (xClass.isSynthetic())
return;
if (xClass.isAbstract())
return;
unreadFields.strongEvidenceForIntendedSerialization(c);
} catch (CheckedAnalysisException e) {
bugReporter.logError("Error looking up xClass of " + c, e);
}
}
if (seen == CHECKCAST) {
OpcodeStack.Item top = stack.getStackItem(0);
if (readObject.equals(top.getReturnValueOf())) {
ClassDescriptor c = getClassDescriptorOperand();
if (!Subtypes2.instanceOf(c, Serializable.class))
return;
try {
XClass xClass = Global.getAnalysisCache().getClassAnalysis(XClass.class, c);
if (xClass.isInterface())
return;
if (xClass.isSynthetic())
return;
if (xClass.isAbstract())
return;
unreadFields.strongEvidenceForIntendedSerialization(c);
} catch (CheckedAnalysisException e) {
bugReporter.logError("Error looking up xClass of " + c, e);
}
}
}
}
}