Beispiel #1
0
 public ITable get(SootClass clazz) {
   if (!clazz.isInterface()) {
     throw new IllegalArgumentException("Not an interface: " + clazz.getName());
   }
   ITable itable = cache.get(clazz.getName());
   if (itable != null) {
     return itable;
   }
   itable = new ITable(clazz);
   cache.put(clazz.getName(), itable);
   return itable;
 }
Beispiel #2
0
  public static HashSet<SootMethod> getAllImplementations(SootMethod method) {
    Chain appClasses = Scene.v().getApplicationClasses();
    HashSet<SootClass> implementingClasses = new HashSet<SootClass>(1);
    HashSet<SootMethod> overridingMethods = new HashSet<SootMethod>(1);

    SootClass t = method.getDeclaringClass();
    if (
    /*t.isAbstract() || */ t.isPhantom() || t.isPhantomClass()) {
      boolean b1 = t.isAbstract();
      boolean be = t.isPhantom();
      boolean b3 = t.isPhantomClass();

      try {
        throw new Exception("Need to implement for Plantom Classes");
      } catch (Exception e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
      }
    }
    if (t.isAbstract()) {
      for (Object object : appClasses) {
        SootClass clazz = (SootClass) object;
        SootClass superClass = clazz.getSuperclass();
        {
          if (superClass.getName().equals(t.toString())) {
            implementingClasses.add(clazz);
            SootMethod m2 =
                clazz.getMethod(
                    method.getName(), method.getParameterTypes(), method.getReturnType());
            overridingMethods.add(m2);
          }
        }
      }
    }
    if (t.isInterface()) {
      for (Object object : appClasses) {
        SootClass clazz = (SootClass) object;
        Chain<SootClass> interfaces = clazz.getInterfaces();
        for (SootClass sootClass : interfaces) {
          if (sootClass.getName().equals(t.toString())) {
            implementingClasses.add(clazz);
            SootMethod m2 =
                clazz.getMethod(
                    method.getName(), method.getParameterTypes(), method.getReturnType());
            overridingMethods.add(m2);
          }
        }
      }
    }
    return overridingMethods;
  }
Beispiel #3
0
 public static boolean isInstanceOfClass(SootClass sc, String className) {
   SootClass clazz = sc;
   if (className.equals(clazz.getName())) {
     return true;
   }
   return isSubclass(sc, className);
 }
Beispiel #4
0
 public VTable get(SootClass clazz) {
   if (clazz.isInterface()) {
     throw new IllegalArgumentException("Expected a class got an interface: " + clazz.getName());
   }
   VTable vtable = cache.get(clazz.getName());
   if (vtable != null) {
     return vtable;
   }
   VTable parent = null;
   if (clazz.hasSuperclass()) {
     parent = get(clazz.getSuperclass());
   }
   vtable = new VTable(clazz, parent);
   cache.put(clazz.getName(), vtable);
   return vtable;
 }
 protected List<OpenCLField> getRefFields(SootClass soot_class) {
   OpenCLClass ocl_class = OpenCLScene.v().getOpenCLClass(soot_class);
   if (ocl_class == null) {
     System.out.println("ocl_class == null: " + soot_class.getName());
   }
   return ocl_class.getInstanceRefFields();
 }
 public void caseStaticInvokeExpr(StaticInvokeExpr arg0) {
   SootMethod soot_method = arg0.getMethod();
   SootClass soot_class = soot_method.getDeclaringClass();
   if (soot_class.getName().equals("java.lang.Object")) return;
   OpenCLMethod ocl_method = new OpenCLMethod(soot_method, soot_class);
   m_output.append(ocl_method.getStaticInvokeString(arg0));
   setCheckException();
 }
 public static boolean isAccessRestricted(SootClass sc) {
   for (String pkg : restrictedPackages) {
     String name = sc.getName();
     if (name.startsWith(pkg)) {
       return true;
     }
   }
   return false;
 }
  private boolean isImportantJavaAlloc(SootClass clz) {
    String packageName = clz.getName();

    for (String packPrefix : IMPORTANT_ALLOCATORS_FROM_JAVA) {
      if (packageName.startsWith(packPrefix)) return true;
    }

    return false;
  }
  private String buildImportantAllocs() {
    StringBuffer sb = new StringBuffer();

    for (SootClass clz : Scene.v().getClasses()) {
      if (Project.v().isSrcClass(clz)
          ||
          /*isImportantJavaAlloc(clz) ||*/
          clz.getName().startsWith(Project.DS_GENERATED_CLASSES_PREFIX)
          || clz.getName().startsWith("droidsafe.runtime")) {
        logger.info("Adding class to important alloc list of spark: {}", clz);
        sb.append(clz + ",");
      }
    }
    String ret = sb.toString();

    ret = ret.substring(0, ret.length() - 1);

    return ret;
  }
Beispiel #10
0
 public static boolean isSubclass(SootClass sc, String className) {
   SootClass clazz = sc;
   while (clazz.hasSuperclass()) {
     clazz = clazz.getSuperclass();
     if (className.equals(clazz.getName())) {
       return true;
     }
   }
   return false;
 }
 private boolean shouldMap(SootClass soot_class) {
   if (m_classRemapping.containsKey(soot_class.getName())) {
     String curr_class = m_currMethod.getDeclaringClass().toString();
     if (m_modified.contains(curr_class) == false) {
       m_modified.add(curr_class);
     }
     return true;
   } else {
     return false;
   }
 }
Beispiel #12
0
  public void caseAFile(AFile node) {
    inAFile(node);
    {
      Object temp[] = node.getModifier().toArray();
      for (int i = 0; i < temp.length; i++) {
        ((PModifier) temp[i]).apply(this);
      }
    }
    if (node.getFileType() != null) {
      node.getFileType().apply(this);
    }
    if (node.getClassName() != null) {
      node.getClassName().apply(this);
    }

    String className = (String) mProductions.removeLast();

    if (mSootClass == null) {
      mSootClass = new SootClass(className);
      mSootClass.setResolvingLevel(SootClass.BODIES);
    } else {
      if (!mSootClass.getName().equals(className))
        throw new RuntimeException(
            "Invalid SootClass for this JimpleAST. The SootClass provided is of type: >"
                + mSootClass.getName()
                + "< whereas this parse tree is for type: >"
                + className
                + "<");
    }

    if (node.getExtendsClause() != null) {
      node.getExtendsClause().apply(this);
    }
    if (node.getImplementsClause() != null) {
      node.getImplementsClause().apply(this);
    }
    if (node.getFileBody() != null) {
      node.getFileBody().apply(this);
    }
    outAFile(node);
  }
  protected void readNonRefField(OpenCLField field) {
    SootField soot_field = field.getSootField();
    String function_name = "read" + getTypeString(soot_field);

    BytecodeLanguage bcl = m_bcl.top();
    bcl.pushMethod(m_currMem.top(), function_name, soot_field.getType());
    Local data = bcl.invokeMethodRet(m_currMem.top());

    SootClass soot_class = Scene.v().getSootClass(soot_field.getDeclaringClass().getName());
    if (soot_class.isApplicationClass()) {
      if (field.isInstance()) {
        bcl.setInstanceField(soot_field, m_objSerializing.top(), data);
      } else {
        bcl.setStaticField(soot_field, data);
      }
    } else {
      SootClass obj = Scene.v().getSootClass("java.lang.Object");
      SootClass string = Scene.v().getSootClass("java.lang.String");
      String static_str;
      SootClass first_param_type;
      Value first_param;
      if (field.isInstance()) {
        static_str = "";
        first_param_type = obj;
        first_param = m_objSerializing.top();
      } else {
        static_str = "Static";
        first_param_type = Scene.v().getSootClass("java.lang.Class");
        first_param = ClassConstant.v(soot_class.getName());
      }
      String private_field_fun_name = "write" + static_str + getTypeString(soot_field);
      Local private_fields = bcl.newInstance("org.trifort.rootbeer.runtime.PrivateFields");
      bcl.pushMethod(
          private_fields,
          private_field_fun_name,
          VoidType.v(),
          first_param_type.getType(),
          string.getType(),
          string.getType(),
          soot_field.getType());
      bcl.invokeMethodNoRet(
          private_fields,
          first_param,
          StringConstant.v(soot_field.getName()),
          StringConstant.v(soot_field.getDeclaringClass().getName()),
          data);
    }
  }
Beispiel #14
0
 public StructureConstant getStruct(SootClass clazz) {
   if (clazz.isInterface()) {
     throw new IllegalArgumentException("Expected a class got an interface: " + clazz.getName());
   }
   ArrayConstantBuilder table = new ArrayConstantBuilder(I8_PTR);
   for (Entry entry : entries) {
     ResolvedEntry resolvedEntry = entry.resolve(clazz);
     if (resolvedEntry == null || Modifier.isAbstract(resolvedEntry.getModifiers())) {
       table.add(new ConstantBitcast(BC_ABSTRACT_METHOD_CALLED, I8_PTR));
     } else if (!Modifier.isPublic(resolvedEntry.getModifiers())) {
       table.add(new ConstantBitcast(BC_NON_PUBLIC_METHOD_CALLED, I8_PTR));
     } else {
       table.add(new ConstantBitcast(resolvedEntry.getFunctionRef(), I8_PTR));
     }
   }
   return new StructureConstantBuilder()
       .add(new IntegerConstant((short) entries.length))
       .add(table.build())
       .build();
 }
  public ReverseClassHierarchy(Map<String, OpenCLClass> classes) {
    m_Hierarchy = new ArrayList<TreeNode>();
    m_Classes = classes;

    addClass("java.lang.String");

    Set<String> key_set = classes.keySet();
    Set<String> visited = new HashSet<String>();
    for (String key : key_set) {
      OpenCLClass ocl_class = classes.get(key);
      SootClass soot_class = Scene.v().getSootClass(ocl_class.getJavaName());
      if (soot_class.hasSuperclass() == false) continue;
      SootClass parent = soot_class.getSuperclass();
      if (parent.getName().equals("java.lang.Object")) {
        TreeNode tree = new TreeNode(soot_class, ocl_class);
        m_Hierarchy.add(tree);
        visited.add(key);
      }
    }

    boolean modified;
    do {
      modified = false;

      key_set = classes.keySet();
      for (String key : key_set) {
        if (visited.contains(key)) continue;
        OpenCLClass ocl_class = classes.get(key);
        SootClass soot_class = Scene.v().getSootClass(ocl_class.getJavaName());
        if (soot_class.hasSuperclass() == false) continue;
        SootClass parent = soot_class.getSuperclass();
        TreeNode node = getNode(parent);
        if (node == null) continue;
        node.addChild(soot_class, ocl_class);
        modified = true;
        visited.add(key);
      }

    } while (modified);
  }
 private void visit(SootMethod method) {
   SootClass soot_class = method.getDeclaringClass();
   if (m_classRemapping.containsKey(soot_class.getName())) {
     return;
   }
   if (method.isConcrete() == false) {
     return;
   }
   Body body = method.retrieveActiveBody();
   if (body == null) return;
   m_currMethod = method;
   fixArguments(method);
   Iterator<Unit> iter = body.getUnits().iterator();
   while (iter.hasNext()) {
     Unit curr = iter.next();
     List<ValueBox> boxes = curr.getUseAndDefBoxes();
     for (ValueBox box : boxes) {
       Value value = box.getValue();
       value = mutate(value);
       box.setValue(value);
     }
   }
 }
Beispiel #17
0
 public static String getInternalName(SootClass sc) {
   return sc.getName().replace('.', '/');
 }
 private SootClass getMapping(SootClass soot_class) {
   String new_class = m_classRemapping.get(soot_class.getName());
   return Scene.v().getSootClass(new_class);
 }
  private StructureType getStructType(SootClass clazz, boolean checkEmpty) {
    int n = 0;
    for (SootMethod method : clazz.getMethods()) {
      n = Math.max(getStructMemberOffset(method) + 1, n);
    }

    Type[] result = new Type[n + 1];

    StructureType superType = null;
    if (clazz.hasSuperclass()) {
      SootClass superclass = clazz.getSuperclass();
      if (!superclass.getName().equals("org.robovm.rt.bro.Struct")) {
        superType = getStructType(superclass, false);
      }
    }
    result[0] = superType != null ? superType : new StructureType();

    for (SootMethod method : clazz.getMethods()) {
      int offset = getStructMemberOffset(method);
      if (offset != -1) {
        if (!method.isNative() && !method.isStatic()) {
          throw new IllegalArgumentException(
              "@StructMember annotated method " + method + " must be native and not static");
        }
        Type type = null;
        if (method.getParameterCount() == 0) {
          soot.Type sootType = method.getReturnType();
          // Possibly a getter
          if (hasPointerAnnotation(method) && !sootType.equals(LongType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated getter "
                    + method
                    + " must be of type long when annotated with @Pointer");
          }
          if (hasMachineSizedFloatAnnotation(method)
              && !sootType.equals(DoubleType.v())
              && !sootType.equals(FloatType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated getter "
                    + method
                    + " must be of type float or double when annotated with @MachineSizedFloat");
          }
          if ((hasMachineSizedSIntAnnotation(method) || hasMachineSizedUIntAnnotation(method))
              && !sootType.equals(LongType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated getter "
                    + method
                    + " must be of type long when annotated with @MachineSizedSInt or @MachineSizedUInt");
          }
          if (sootType instanceof soot.ArrayType && !hasArrayAnnotation(method)) {
            throw new IllegalArgumentException(
                "@Array annotation expected on struct member getter " + method);
          }
        } else if (method.getParameterCount() == 1) {
          soot.Type sootType = method.getParameterType(0);
          if (hasPointerAnnotation(method, 0) && !sootType.equals(LongType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated setter "
                    + method
                    + " must be of type long when annotated with @Pointer");
          }
          if (hasMachineSizedFloatAnnotation(method, 0)
              && !sootType.equals(DoubleType.v())
              && !sootType.equals(FloatType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated setter "
                    + method
                    + " must be of type float or double when annotated with @MachineSizedFloat");
          }
          if ((hasMachineSizedSIntAnnotation(method, 0) || hasMachineSizedUIntAnnotation(method))
              && !sootType.equals(LongType.v())) {
            throw new IllegalArgumentException(
                "@StructMember("
                    + offset
                    + ") annotated setter "
                    + method
                    + " must be of type long when annotated with @MachineSizedSInt or @MachineSizedUInt");
          }
          if (sootType instanceof soot.ArrayType && !hasArrayAnnotation(method, 0)) {
            throw new IllegalArgumentException(
                "@Array annotation expected on first parameter of struct member setter " + method);
          }
          soot.Type retType = method.getReturnType();
          // The return type of the setter must be void or this
          if (!retType.equals(VoidType.v())
              && !(retType instanceof RefType
                  && ((RefType) retType).getSootClass().equals(clazz))) {
            throw new IllegalArgumentException(
                "Setter "
                    + method
                    + " for "
                    + "@StructMember("
                    + offset
                    + ") "
                    + " must either return nothing or return a "
                    + clazz);
          }
        } else {
          throw new IllegalArgumentException(
              "@StructMember annotated method " + method + " has too many parameters");
        }

        type = getStructMemberType(method);
        int index = offset + 1;
        if (result[index] == null) {
          result[index] = type;
        } else if (type != result[index]) {
          // Two members mapped to the same offset (union). Pick
          // the type with the largest alignment and pad with bytes
          // up to the largest size.
          result[index] = mergeStructMemberTypes(config.getDataLayout(), type, result[index]);
        }
      }
    }

    for (int i = 1; i < result.length; i++) {
      if (result[i] == null) {
        throw new IllegalArgumentException("No @StructMember(" + i + ") defined in class " + clazz);
      }
    }

    if (!clazz.isAbstract() && checkEmpty && n == 0 && superType == null) {
      throw new IllegalArgumentException(
          "Struct class " + clazz + " has no @StructMember annotated methods");
    }

    return new StructureType(result);
  }
 protected SootClass getClassForType(RefType ref_type) {
   SootClass soot_class = ref_type.getSootClass();
   soot_class = Scene.v().getSootClass(soot_class.getName());
   return soot_class;
 }
  public boolean DoAnalysis(boolean verbose) {
    Stack<List<Set<SootClass>>> current_exception_sets = new Stack<List<Set<SootClass>>>();
    {
      List<Set<SootClass>> exception_sets = new ArrayList<Set<SootClass>>();
      exception_sets.add(method_exception_set);
      current_exception_sets.push(exception_sets);
    }

    PatchingChain<Unit> chain = body.getUnits();
    Unit next = chain.getFirst();

    int previous_class_count = method_exception_set.size();
    for (Map.Entry<Unit, List<TwoValuePair<Trap, Set<SootClass>>>> entry :
        trap_begin_exception_sets.entrySet()) {
      for (TwoValuePair<Trap, Set<SootClass>> tvp : entry.getValue()) {
        previous_class_count += tvp.w.size();
      }
    }

    do {

      if (trap_begin_exception_sets.containsKey(next)) {
        List<TwoValuePair<Trap, Set<SootClass>>> tvps = trap_begin_exception_sets.get(next);
        List<Set<SootClass>> sets_to_add = new ArrayList<Set<SootClass>>();
        for (TwoValuePair<Trap, Set<SootClass>> tvp : tvps) {
          sets_to_add.add(tvp.w);
        }
        current_exception_sets.push(sets_to_add);
      }
      if (next instanceof InvokeStmt || next instanceof AssignStmt) {
        SootMethod callee = null;

        if (next instanceof AssignStmt) {
          if (((AssignStmt) next).getRightOp() instanceof InvokeExpr) {
            callee = ((InvokeExpr) ((AssignStmt) next).getRightOp()).getMethod();
          }
        } else {
          callee = ((InvokeStmt) next).getInvokeExpr().getMethod();
        }

        if (callee != null) { // invocation only

          Collection<SootClass> exception_classes;
          if (class_map.containsKey(callee.getDeclaringClass())) {
            assert class_map.get(callee.getDeclaringClass()).method_analysis.containsKey(callee);

            exception_classes =
                class_map
                    .get(callee.getDeclaringClass())
                    .method_analysis
                    .get(callee)
                    .method_exception_set;
          } else {
            exception_classes = callee.getExceptions();
          }
          for (SootClass exception_class : exception_classes) {
            for (Set<SootClass> current_exception_set : current_exception_sets.peek()) {
              current_exception_set.add(exception_class);
            }
          }
        }

      } else if (next instanceof ThrowStmt) {

        assert chain.getPredOf(next) instanceof JInvokeStmt;
        assert ((JInvokeStmt) chain.getPredOf(next)).getInvokeExpr() instanceof SpecialInvokeExpr;
        assert ((SpecialInvokeExpr) ((JInvokeStmt) chain.getPredOf(next)).getInvokeExpr()).getBase()
            instanceof JimpleLocal;
        assert ((JimpleLocal)
                    ((SpecialInvokeExpr) ((JInvokeStmt) chain.getPredOf(next)).getInvokeExpr())
                        .getBase())
                .getType()
            instanceof RefType;

        SootClass exception_class =
            ((RefType)
                    ((JimpleLocal)
                            ((SpecialInvokeExpr)
                                    ((JInvokeStmt) chain.getPredOf(next)).getInvokeExpr())
                                .getBase())
                        .getType())
                .getSootClass();

        for (Set<SootClass> current_exception_set : current_exception_sets.peek()) {
          current_exception_set.add(exception_class);
        }
      }

      if (trap_end_exception_sets.containsKey(next)) {

        List<TwoValuePair<Trap, Set<SootClass>>> tvps = trap_end_exception_sets.get(next);

        if (verbose) {
          for (Set<SootClass> current_exception_set : current_exception_sets.peek()) {
            if (current_exception_set.size() == 0) {
              for (TwoValuePair<Trap, Set<SootClass>> tvp : tvps) {
                if (!tvp.v.getException().getName().equals("java.lang.RuntimeException"))
                  System.out.println(
                      "Warning: In "
                          + method.toString()
                          + ": Unncessary exception handler for catching "
                          + tvp.v.getException().getName());
              }
            }
          }
        }

        for (TwoValuePair<Trap, Set<SootClass>> tvp : tvps) {

          Iterator<SootClass> i = tvp.w.iterator();
          while (i.hasNext()) {
            SootClass exception_class = i.next();

            if (tvp.v.getException()
                == exception_class) { // getting properly caught by the handler.
              i.remove();
            } else {
              SootClass super_exception_class = exception_class;
              while (super_exception_class != null) {

                if (tvp.v.getException() == super_exception_class) {
                  i.remove();
                  if (verbose
                      && super_exception_class != exception_class
                      && GetMostRestrictiveFormOfException(tvps, exception_class)
                          == tvp.v.getException()
                      && !super_exception_class.getName().equals("java.lang.RuntimeException")) {
                    System.out.println(
                        "Warning: In "
                            + method.toString()
                            + ": attempting to catch "
                            + exception_class.getName()
                            + " with "
                            + super_exception_class.getName()
                            + " Consider catching the most restrictive exception class");
                  }
                  break;
                }
                try {
                  super_exception_class = super_exception_class.getSuperclass();
                } catch (
                    RuntimeException
                        e) { // unfortunately soot doesn't have a specific exception class for "no
                  // superclass for java.lang.Object" exception
                  super_exception_class = null;
                }
              }
            }
          }
        }

        current_exception_sets.pop();

        for (Set<SootClass> current_exception_set :
            current_exception_sets
                .peek()) { // This list iteration is not necessary if we are still making the
          // assumption that there's only one unique set that contains exception
          // classes if the range for traps are the same
          for (TwoValuePair<Trap, Set<SootClass>> tvp : tvps) {
            for (SootClass exception_class : tvp.w) {
              current_exception_set.add(exception_class);
            }
          }
        }
      }
      next = chain.getSuccOf(next);
    } while (next != null);

    int new_class_count = method_exception_set.size();
    for (Map.Entry<Unit, List<TwoValuePair<Trap, Set<SootClass>>>> entry :
        trap_begin_exception_sets.entrySet()) {
      for (TwoValuePair<Trap, Set<SootClass>> tvp : entry.getValue()) {
        new_class_count += tvp.w.size();
      }
    }

    return new_class_count != previous_class_count;
  }
Beispiel #22
0
  private StructureConstant createClassInfoErrorStruct() {
    /*
     * Check that clazz can be loaded, i.e. that the superclass
     * and interfaces of the class exist and are accessible to the
     * class. Also check that any exception the class uses in catch
     * clauses exist and is accessible to the class. If the class
     * cannot be loaded we override the ClassInfoHeader struct
     * produced by the ClassCompiler for the class with one which
     * tells the code in bc.c to throw an appropriate exception
     * whenever clazz is accessed.
     */

    int errorType = ClassCompiler.CI_ERROR_TYPE_NONE;
    String errorMessage = null;
    if (!sootClass.isInterface() && sootClass.hasSuperclass()) {
      // Check superclass
      SootClass superclazz = sootClass.getSuperclass();
      if (superclazz.isPhantom()) {
        errorType = ClassCompiler.CI_ERROR_TYPE_NO_CLASS_DEF_FOUND;
        errorMessage = superclazz.getName();
      } else if (!checkClassAccessible(superclazz, sootClass)) {
        errorType = ClassCompiler.CI_ERROR_TYPE_ILLEGAL_ACCESS;
        errorMessage = String.format(ILLEGAL_ACCESS_ERROR_CLASS, superclazz, sootClass);
      } else if (superclazz.isInterface()) {
        errorType = ClassCompiler.CI_ERROR_TYPE_INCOMPATIBLE_CLASS_CHANGE;
        errorMessage =
            String.format("class %s has interface %s as super class", sootClass, superclazz);
      }
      // No need to check for ClassCircularityError. Soot doesn't handle
      // such problems so the compilation will fail earlier.
    }

    if (errorType == ClassCompiler.CI_ERROR_TYPE_NONE) {
      // Check interfaces
      for (SootClass interfaze : sootClass.getInterfaces()) {
        if (interfaze.isPhantom()) {
          errorType = ClassCompiler.CI_ERROR_TYPE_NO_CLASS_DEF_FOUND;
          errorMessage = interfaze.getName();
          break;
        } else if (!checkClassAccessible(interfaze, sootClass)) {
          errorType = ClassCompiler.CI_ERROR_TYPE_ILLEGAL_ACCESS;
          errorMessage = String.format(ILLEGAL_ACCESS_ERROR_CLASS, interfaze, sootClass);
          break;
        } else if (!interfaze.isInterface()) {
          errorType = ClassCompiler.CI_ERROR_TYPE_INCOMPATIBLE_CLASS_CHANGE;
          errorMessage =
              String.format(
                  "class %s tries to implement class %s as interface", sootClass, interfaze);
          break;
        }
      }
    }

    if (errorType == ClassCompiler.CI_ERROR_TYPE_NONE) {
      // Check exceptions used in catch clauses. I cannot find any info in
      // the VM spec specifying that this has to be done when the class is loaded.
      // However, this is how it's done in other VMs so we do it too.
      for (String exName : catches) {
        Clazz ex = config.getClazzes().load(exName);
        if (ex == null || ex.getSootClass().isPhantom()) {
          errorType = ClassCompiler.CI_ERROR_TYPE_NO_CLASS_DEF_FOUND;
          errorMessage = exName;
          break;
        } else if (!checkClassAccessible(ex.getSootClass(), sootClass)) {
          errorType = ClassCompiler.CI_ERROR_TYPE_ILLEGAL_ACCESS;
          errorMessage = String.format(ILLEGAL_ACCESS_ERROR_CLASS, ex, sootClass);
          break;
        }
      }
    }

    if (errorType == ClassCompiler.CI_ERROR_TYPE_NONE) {
      return null;
    }

    // Create a ClassInfoError struct
    StructureConstantBuilder error = new StructureConstantBuilder();
    error.add(new NullConstant(I8_PTR)); // Points to the runtime Class struct
    error.add(new IntegerConstant(ClassCompiler.CI_ERROR));
    error.add(getString(getInternalName(sootClass)));
    error.add(new IntegerConstant(errorType));
    error.add(getString(errorMessage));
    return error.build();
  }