ksen007 / janala2

a concolic testing engine for Java
BSD 2-Clause "Simplified" License
102 stars 34 forks source link

java.lang.ArrayIndexOutOfBoundsException #8

Open danglotb opened 6 years ago

danglotb commented 6 years ago

Hello,

I am running CATG on javapoet and I am facing to an exception:

java.lang.ArrayIndexOutOfBoundsException: 6
    at janala.interpreters.ObjectValue.setField(ObjectValue.java:104)
    at janala.interpreters.ConcolicInterpreter.visitPUTFIELD(ConcolicInterpreter.java:1384)
    at janala.logger.inst.PUTFIELD.visit(PUTFIELD.java:16)
    at janala.logger.DirectConcolicExecution.log(DirectConcolicExecution.java:58)
    at janala.logger.AbstractLogger.SPECIAL(AbstractLogger.java:706)
    at janala.logger.DJVM.SPECIAL(DJVM.java:708)
    at com.squareup.javapoet.CodeWriter.<init>(CodeWriter.java:41)
    at com.squareup.javapoet.CodeWriter.<init>(CodeWriter.java:67)
    at com.squareup.javapoet.CodeWriter.<init>(CodeWriter.java:63)
    at com.squareup.javapoet.TypeName.toString(TypeName.java:256)
    at com.squareup.javapoet.AnnotatedTypeNameTest.main(AnnotatedTypeNameTest.java:146)

happening when I try to run CATG on:

public static void main(String[] args) {
        String lit1 = catg.CATG.readString("java.util.List<@");
        String lit2 = catg.CATG.readString(" java.lang.String>");
        String expected = (lit1 + (AnnotatedTypeNameTest.NN)) + lit2;
        TypeName type = TypeName.get(String.class).annotated(annotatedTypeNameTest.NEVER_NULL);
        ClassName list = ClassName.get(List.class);
        String actual = ParameterizedTypeName.get(list, type).toString();
}

I assumed that there is a problem with the fields of the class com.squareup.javapoet.CodeWriter.

Find here, an excerpt of this class:

final class CodeWriter {
  /** Sentinel value that indicates that no user-provided package has been set. */
  private static final String NO_PACKAGE = new String();

  private final String indent;
  private final Appendable out;
  private int indentLevel;

  private boolean javadoc = false;
  private boolean comment = false;
  private String packageName = NO_PACKAGE;
  private final List<TypeSpec> typeSpecStack = new ArrayList<>();
  private final Set<String> staticImportClassNames;
  private final Set<String> staticImports;
  private final Map<String, ClassName> importedTypes;
  private final Map<String, ClassName> importableTypes = new LinkedHashMap<>();
  private final Set<String> referencedNames = new LinkedHashSet<>();
  private boolean trailingNewline;

  /**
   * When emitting a statement, this is the line of the statement currently being written. The first
   * line of a statement is indented normally and subsequent wrapped lines are double-indented. This
   * is -1 when the currently-written line isn't part of a statement.
   */
  int statementLine = -1;

  CodeWriter(Appendable out) {
    this(out, "  ", Collections.<String>emptySet());
  }

  CodeWriter(Appendable out, String indent, Set<String> staticImports) {
    this(out, indent, Collections.<String, ClassName>emptyMap(), staticImports);
  }

  CodeWriter(Appendable out, String indent, Map<String, ClassName> importedTypes,
      Set<String> staticImports) {
    this.out = checkNotNull(out, "out == null");
    this.indent = checkNotNull(indent, "indent == null");
    this.importedTypes = checkNotNull(importedTypes, "importedTypes == null");
    this.staticImports = checkNotNull(staticImports, "staticImports == null");
    this.staticImportClassNames = new LinkedHashSet<>();
    for (String signature : staticImports) {
      staticImportClassNames.add(signature.substring(0, signature.lastIndexOf('.')));
    }
  }

Do you have any idea or tips to fix this issues?

Best regards,

Benjamin.

danglotb commented 6 years ago

Hi,

I am trying to find a way to fix this. I am using the little example provided by @MateusAraujoBorges in #11.

The Exception is raised when the ConcolicInterpreter visit the PUTFIELD.

I tried to log some information about the case: The toString() of the concerned ObjectInfo

ObjectInfo{
  fieldNameToIndex={irrelevant0=1, tmp=0},
  fieldList=[
    FieldInfo{
      className='tests.bugreports.putfieldbug.SienaBuggyExample', 
      fieldName='tmp', 
      isStatic=false, 
      fieldId=1
    },
    FieldInfo{
      className='tests.bugreports.putfieldbug.SienaBuggyExample', 
      fieldName='irrelevant0', 
      isStatic=false, 
      fieldId=-1
    }
  ],
  staticFieldNameToIndex=null, staticFieldList=null, nStaticFields=0, nFields=2, statics=[], className='tests.bugreports.putfieldbug.SienaBuggyExample'
}

I think there is an error in the indexing of fields because the field irrelevant0 has an index = -1 and we can see that the values in fieldNameToIndex does not match with the fieldId in each FieldInfo.

Here, find the instrumentation of the class under test:

public class SienaBuggyExample {
    private int irrelevant0;
    private Object tmp;
    public SienaBuggyExample(int x) {
        label201: {
            DJVM.ALOAD(1025, 1, 0);
            super();
            DJVM.ALOAD(1026, 1, 0);
            DJVM.GETVALUE_Object(this);
            DJVM.NEW(1027, 1, "java/lang/Object", 0);
            DJVM.SPECIAL(0);
            DJVM.DUP(1028, 1);
            Object var10001 = new Object();
            DJVM.PUTFIELD(1029, 1, 1, 0, "Ljava/lang/Object;"); // here the PUTFIELD raising the exception
            this.tmp = var10001;
            DJVM.SPECIAL(0);
            DJVM.ILOAD(1030, 1, 1);
            ...
            ...
            ...

Another things it is maybe the initialization of the ObjectValue. I'll keep going deeper in CATG and find out, but If you have any tips or hint It could be very useful.

Thank you very much!

-- Benjamin.

danglotb commented 6 years ago

Hi again,

According to my finding, the problem is that : here, we get the ref object from the currentFrame field of the ConcolicInterpreter.

The problem is, just before, we push in the stack the value of the field itself with:

DJVM.NEW(1027, 1, "java/lang/Object", 0);

So, it results with when with call:

ObjectValue ref = (ObjectValue) currentFrame.pop();
ref.setField(fi.getFieldId(), value);

the ref is the field itself, and we can't call setField() on it because it is not the corresponding object.

I have found a solution, but I am not sure that it is the good way to do.

please find in: #9

Thank you.