// // Copyright (C) 2007 United States Government as represented by the // Administrator of the National Aeronautics and Space Administration // (NASA). All Rights Reserved. // // This software is distributed under the NASA Open Source Agreement // (NOSA), version 1.3. The NOSA has been approved by the Open Source // Initiative. See the file NOSA-1.3-JPF at the top of the distribution // directory tree for the complete NOSA document. // // THE SUBJECT SOFTWARE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY OF ANY // KIND, EITHER EXPRESSED, IMPLIED, OR STATUTORY, INCLUDING, BUT NOT // LIMITED TO, ANY WARRANTY THAT THE SUBJECT SOFTWARE WILL CONFORM TO // SPECIFICATIONS, ANY IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR // A PARTICULAR PURPOSE, OR FREEDOM FROM INFRINGEMENT, ANY WARRANTY THAT // THE SUBJECT SOFTWARE WILL BE ERROR FREE, OR ANY WARRANTY THAT // DOCUMENTATION, IF PROVIDED, WILL CONFORM TO THE SUBJECT SOFTWARE. // package gov.nasa.jpf.vm; import java.util.Map; import cmu.conditional.One; import de.fosd.typechef.featureexpr.FeatureExpr; import gov.nasa.jpf.annotation.MJI; /** * @author Nastaran Shafiei <nastaran.shafiei@gmail.com> * * Native peer for java.lang.ClassLoader */ @SuppressWarnings("deprecation") public class JPF_java_lang_ClassLoader extends NativePeer { @MJI public void $init____V (MJIEnv env, int objRef, FeatureExpr ctx) { ClassLoaderInfo systemCl = ClassLoaderInfo.getCurrentSystemClassLoader(); $init__Ljava_lang_ClassLoader_2__V (env, objRef, systemCl.getClassLoaderObjectRef(), ctx); } @MJI public void $init__Ljava_lang_ClassLoader_2__V (MJIEnv env, int objRef, int parentRef, FeatureExpr ctx) { Heap heap = env.getHeap(); //--- Retrieve the parent ClassLoaderInfo ClassLoaderInfo parent = env.getClassLoaderInfo(parentRef); //--- create the internal representation of the classloader ClassLoaderInfo cl = new ClassLoaderInfo(ctx, env.getVM(), objRef, new ClassPath(), parent); //--- initialize the java.lang.ClassLoader object ElementInfo ei = heap.getModifiable(objRef); ei.setIntField(ctx, ClassLoaderInfo.ID_FIELD, new One<>(cl.getId())); // we should use the following block if we ever decide to make systemClassLoader // unavailable if(parent.isSystemClassLoader) { // // we don't want to make the systemCLassLoader available through SUT // parentRef = MJIEnv.NULL; // } ei.setReferenceField(ctx, "parent", new One<>(parentRef)); } @MJI public int getSystemClassLoader____Ljava_lang_ClassLoader_2 (MJIEnv env, int clsObjRef, FeatureExpr ctx) { return ClassLoaderInfo.getCurrentSystemClassLoader().getClassLoaderObjectRef(); } @MJI public int getResource0__Ljava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int resRef, FeatureExpr ctx){ String rname = env.getStringObject(ctx, resRef); ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); String resourcePath = cl.findResource(rname); return env.newString(ctx, resourcePath); } @MJI public int getResources0__Ljava_lang_String_2___3Ljava_lang_String_2 (MJIEnv env, int objRef, int resRef, FeatureExpr ctx) { String rname = env.getStringObject(ctx, resRef); ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); String[] resources = cl.findResources(rname); return env.newStringArray(ctx, resources); } @MJI public int findLoadedClass__Ljava_lang_String_2__Ljava_lang_Class_2 (MJIEnv env, int objRef, int nameRef, FeatureExpr ctx) { String cname = env.getStringObject(ctx, nameRef); ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); ClassInfo ci = cl.getAlreadyResolvedClassInfo(cname); if(ci != null) { return ci.getClassObjectRef(); } return MJIEnv.NULL; } @MJI public int findSystemClass__Ljava_lang_String_2__Ljava_lang_Class_2 (MJIEnv env, int objRef, int nameRef, FeatureExpr ctx) { String cname = env.getStringObject(ctx, nameRef); checkForIllegalName(env, cname, ctx); if(env.hasException()) { return MJIEnv.NULL; } ClassLoaderInfo cl = ClassLoaderInfo.getCurrentSystemClassLoader(); ClassInfo ci = cl.getResolvedClassInfo(ctx, cname); while (ci.isArray()) { ci = ci.getComponentClassInfo(); } if(!ci.isRegistered()) { ci.registerClass(ctx, env.getThreadInfo()); } return ci.getClassObjectRef(); } @MJI public int defineClass0__Ljava_lang_String_2_3BII__Ljava_lang_Class_2 (MJIEnv env, int objRef, int nameRef, int bufferRef, int offset, int length, FeatureExpr ctx) { String cname = env.getStringObject(ctx, nameRef); ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); // determine whether that the corresponding class is already defined by this // classloader, if so, this attempt is invalid, and loading throws a LinkageError if (cl.getDefinedClassInfo(cname) != null) { // attempt to define twice env.throwException(ctx, "java.lang.LinkageError"); return MJIEnv.NULL; } byte[] buffer = env.getByteArrayObjectDeprecated(ctx, bufferRef); try { ClassInfo ci = cl.getResolvedClassInfo( cname, buffer, offset, length); // Note: if the representation is not of a supported major or minor version, loading // throws an UnsupportedClassVersionError. But for now, we do not check for this here // since we don't do much with minor and major versions ThreadInfo ti = env.getThreadInfo(); ci.registerClass(ctx, ti); return ci.getClassObjectRef(); } catch (ClassInfoException cix){ env.throwException(ctx, "java.lang.ClassFormatError"); return MJIEnv.NULL; } } protected static boolean check(MJIEnv env, String cname, byte[] buffer, int offset, int length, FeatureExpr ctx) { // throw SecurityExcpetion if the package prefix is java checkForProhibitedPkg(env, cname, ctx); // throw NoClassDefFoundError if the given class does name might // not be a valid binary name checkForIllegalName(env, cname, ctx); // throw IndexOutOfBoundsException if buffer length is not consistent // with offset checkData(env, buffer, offset, length, ctx); return !env.hasException(); } protected static void checkForProhibitedPkg(MJIEnv env, String name, FeatureExpr ctx) { if(name != null && name.startsWith("java.")) { env.throwException(ctx, "java.lang.SecurityException", "Prohibited package name: " + name); } } protected static void checkForIllegalName(MJIEnv env, String name, FeatureExpr ctx) { if((name == null) || (name.length() == 0)) { return; } if((name.indexOf('/') != -1)) { env.throwException(ctx, java.lang.NoClassDefFoundError.class.getName(), "IllegalName: " + name); } } protected static void checkData(MJIEnv env, byte[] buffer, int offset, int length, FeatureExpr ctx) { if(offset<0 || length<0 || offset+length > buffer.length) { env.throwException(ctx, "java.lang.IndexOutOfBoundsException"); } } static String pkg_class_name = "java.lang.Package"; @MJI public int getPackages_____3Ljava_lang_Package_2 (MJIEnv env, int objRef, FeatureExpr ctx) { ClassLoaderInfo sysLoader = ClassLoaderInfo.getCurrentSystemClassLoader(); ClassInfo pkgClass = null; try { pkgClass = sysLoader.getInitializedClassInfo(ctx, pkg_class_name, env.getThreadInfo()); } catch (ClinitRequired x){ env.handleClinitRequest(ctx, x.getRequiredClassInfo()); return MJIEnv.NULL; } ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); // Returns all of the Packages defined by this class loader and its ancestors Map<String, ClassLoaderInfo> pkgs = cl.getPackages(); int size = pkgs.size(); // create an array of type java.lang.Package int pkgArr = env.newObjectArray(pkg_class_name, size); int i = 0; for(String name: pkgs.keySet()) { int pkgRef = createPackageObject(env, pkgClass, name, cl, ctx); // place the object into the array env.setReferenceArrayElement(ctx, pkgArr, i++, new One<>(pkgRef)); } return pkgArr; } @MJI public int getPackage__Ljava_lang_String_2__Ljava_lang_Package_2 (MJIEnv env, int objRef, int nameRef, FeatureExpr ctx) { ClassLoaderInfo sysLoader = ClassLoaderInfo.getCurrentSystemClassLoader(); ClassInfo pkgClass = null; try { pkgClass = sysLoader.getInitializedClassInfo(ctx, pkg_class_name, env.getThreadInfo()); } catch (ClinitRequired x){ env.handleClinitRequest(ctx, x.getRequiredClassInfo()); return MJIEnv.NULL; } ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); String pkgName = env.getStringObject(ctx, nameRef); if(cl.getPackages().get(pkgName)!=null) { return createPackageObject(env, pkgClass, pkgName, cl, ctx); } else { return MJIEnv.NULL; } } public static int createPackageObject(MJIEnv env, ClassInfo pkgClass, String pkgName, ClassLoaderInfo cl, FeatureExpr ctx) { int pkgRef = env.newObject(ctx, pkgClass); ElementInfo ei = env.getModifiableElementInfo(pkgRef); ei.setReferenceField(ctx, "pkgName", new One<>(env.newString(ctx, pkgName))); ei.setReferenceField(ctx, "loader", new One<>(cl.getClassLoaderObjectRef())); // the rest of the fields set to some dummy value ei.setReferenceField(ctx, "specTitle", new One<>(env.newString(ctx, "spectitle"))); ei.setReferenceField(ctx, "specVersion", new One<>(env.newString(ctx, "specversion"))); ei.setReferenceField(ctx, "specVendor", new One<>(env.newString(ctx, "specvendor"))); ei.setReferenceField(ctx, "implTitle", new One<>(env.newString(ctx, "impltitle"))); ei.setReferenceField(ctx, "implVersion", new One<>(env.newString(ctx, "implversion"))); ei.setReferenceField(ctx, "sealBase", One.MJIEnvNULL); return pkgRef; } @MJI public void setDefaultAssertionStatus__Z__V (MJIEnv env, int objRef, boolean enabled, FeatureExpr ctx) { ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); cl.setDefaultAssertionStatus(enabled); } @MJI public void setPackageAssertionStatus__Ljava_lang_String_2Z__V (MJIEnv env, int objRef, int strRef, boolean enabled, FeatureExpr ctx) { ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); String pkgName = env.getStringObject(ctx, strRef); cl.setPackageAssertionStatus(pkgName, enabled); } @MJI public void setClassAssertionStatus__Ljava_lang_String_2Z__V (MJIEnv env, int objRef, int strRef, boolean enabled, FeatureExpr ctx) { ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); String clsName = env.getStringObject(ctx, strRef); cl.setClassAssertionStatus(clsName, enabled); } @MJI public void clearAssertionStatus____V (MJIEnv env, int objRef, FeatureExpr ctx) { ClassLoaderInfo cl = env.getClassLoaderInfo(objRef); cl.clearAssertionStatus(); } }