136c12e082c0afeea6f6d3db3bbccb34f6fe1927
[jpf-core.git] / src / peers / gov / nasa / jpf / vm / JPF_java_lang_ClassLoader.java
1 /*
2  * Copyright (C) 2014, United States Government, as represented by the
3  * Administrator of the National Aeronautics and Space Administration.
4  * All rights reserved.
5  *
6  * The Java Pathfinder core (jpf-core) platform is licensed under the
7  * Apache License, Version 2.0 (the "License"); you may not use this file except
8  * in compliance with the License. You may obtain a copy of the License at
9  * 
10  *        http://www.apache.org/licenses/LICENSE-2.0. 
11  *
12  * Unless required by applicable law or agreed to in writing, software
13  * distributed under the License is distributed on an "AS IS" BASIS,
14  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15  * See the License for the specific language governing permissions and 
16  * limitations under the License.
17  */
18 package gov.nasa.jpf.vm;
19
20 import java.util.Map;
21
22 import gov.nasa.jpf.annotation.MJI;
23 import gov.nasa.jpf.vm.ClassPath;
24 import gov.nasa.jpf.vm.ClassInfo;
25 import gov.nasa.jpf.vm.ClassLoaderInfo;
26 import gov.nasa.jpf.vm.ClassInfoException;
27 import gov.nasa.jpf.vm.ClinitRequired;
28 import gov.nasa.jpf.vm.ElementInfo;
29 import gov.nasa.jpf.vm.Heap;
30 import gov.nasa.jpf.vm.MJIEnv;
31 import gov.nasa.jpf.vm.NativePeer;
32 import gov.nasa.jpf.vm.ThreadInfo;
33
34 /**
35  * @author Nastaran Shafiei <nastaran.shafiei@gmail.com>
36  * 
37  * Native peer for java.lang.ClassLoader
38  */
39 public class JPF_java_lang_ClassLoader extends NativePeer {
40
41   @MJI
42   public void $init____V (MJIEnv env, int objRef) {
43     ClassLoaderInfo systemCl = ClassLoaderInfo.getCurrentSystemClassLoader();
44     $init__Ljava_lang_ClassLoader_2__V (env, objRef, systemCl.getClassLoaderObjectRef());
45   }
46
47   @MJI
48   public void $init__Ljava_lang_ClassLoader_2__V (MJIEnv env, int objRef, int parentRef) {
49     Heap heap = env.getHeap();
50
51     //--- Retrieve the parent ClassLoaderInfo
52     ClassLoaderInfo parent = env.getClassLoaderInfo(parentRef);
53
54     //--- create the internal representation of the classloader
55     ClassLoaderInfo cl = new ClassLoaderInfo(env.getVM(), objRef, new ClassPath(), parent);
56
57     //--- initialize the java.lang.ClassLoader object
58     ElementInfo ei = heap.getModifiable(objRef);
59     ei.setIntField( ClassLoaderInfo.ID_FIELD, cl.getId());
60
61     // we should use the following block if we ever decide to make systemClassLoader 
62     // unavailable if(parent.isSystemClassLoader) {
63     //  // we don't want to make the systemCLassLoader available through SUT
64     //  parentRef = MJIEnv.NULL;
65     // }
66
67     ei.setReferenceField("parent", parentRef);
68   }
69
70   @MJI
71   public int getSystemClassLoader____Ljava_lang_ClassLoader_2 (MJIEnv env, int clsObjRef) {
72     return ClassLoaderInfo.getCurrentSystemClassLoader().getClassLoaderObjectRef();
73   }
74
75   @MJI
76   public int getResource0__Ljava_lang_String_2__Ljava_lang_String_2 (MJIEnv env, int objRef, int resRef){
77     String rname = env.getStringObject(resRef);
78
79     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
80
81     String resourcePath = cl.findResource(rname);
82
83     return env.newString(resourcePath);
84   }
85
86   @MJI
87   public int getResources0__Ljava_lang_String_2___3Ljava_lang_String_2 (MJIEnv env, int objRef, int resRef) {
88     String rname = env.getStringObject(resRef);
89
90     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
91
92     String[] resources = cl.findResources(rname);
93
94     return env.newStringArray(resources);
95   }
96
97   @MJI
98   public int findLoadedClass__Ljava_lang_String_2__Ljava_lang_Class_2 (MJIEnv env, int objRef, int nameRef) {
99     String cname = env.getStringObject(nameRef);
100
101     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
102
103     ClassInfo ci = cl.getAlreadyResolvedClassInfo(cname);
104     if(ci != null) {
105       return ci.getClassObjectRef();
106     }
107
108     return MJIEnv.NULL;
109   }
110
111   @MJI
112   public int findSystemClass__Ljava_lang_String_2__Ljava_lang_Class_2 (MJIEnv env, int objRef, int nameRef) {
113     String cname = env.getStringObject(nameRef);
114
115     checkForIllegalName(env, cname);
116     if(env.hasException()) {
117       return MJIEnv.NULL;
118     }
119
120     ClassLoaderInfo cl = ClassLoaderInfo.getCurrentSystemClassLoader();
121
122     ClassInfo ci = cl.getResolvedClassInfo(cname);
123
124     if(!ci.isRegistered()) {
125       ci.registerClass(env.getThreadInfo());
126     }
127
128     return ci.getClassObjectRef();
129   }
130
131   @MJI
132   public int defineClass0__Ljava_lang_String_2_3BII__Ljava_lang_Class_2 
133                                       (MJIEnv env, int objRef, int nameRef, int bufferRef, int offset, int length) {
134     String cname = env.getStringObject(nameRef);
135     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
136
137     // determine whether that the corresponding class is already defined by this 
138     // classloader, if so, this attempt is invalid, and loading throws a LinkageError
139     if (cl.getDefinedClassInfo(cname) != null) {  // attempt to define twice
140       env.throwException("java.lang.LinkageError"); 
141       return MJIEnv.NULL;
142     }
143         
144     byte[] buffer = env.getByteArrayObject(bufferRef);
145     
146     try {
147
148       ClassInfo ci = cl.getResolvedClassInfo( cname, buffer, offset, length);
149
150       // Note: if the representation is not of a supported major or minor version, loading
151       // throws an UnsupportedClassVersionError. But for now, we do not check for this here 
152       // since we don't do much with minor and major versions
153
154       ThreadInfo ti = env.getThreadInfo();
155       ci.registerClass(ti);
156
157       return ci.getClassObjectRef();
158       
159     } catch (ClassInfoException cix){
160       env.throwException("java.lang.ClassFormatError");
161       return MJIEnv.NULL;
162     }
163   }
164
165
166   protected static boolean check(MJIEnv env, String cname, byte[] buffer, int offset, int length) {
167     // throw SecurityExcpetion if the package prefix is java
168     checkForProhibitedPkg(env, cname);
169
170     // throw NoClassDefFoundError if the given class does name might 
171     // not be a valid binary name
172     checkForIllegalName(env, cname);
173
174     // throw IndexOutOfBoundsException if buffer length is not consistent
175     // with offset
176     checkData(env, buffer, offset, length);
177
178     return !env.hasException();
179   }
180
181   protected static void checkForProhibitedPkg(MJIEnv env, String name) {
182     if(name != null && name.startsWith("java.")) {
183       env.throwException("java.lang.SecurityException", "Prohibited package name: " + name);
184     }
185   }
186
187   protected static void checkForIllegalName(MJIEnv env, String name) {
188     if((name == null) || (name.length() == 0)) {
189       return;
190     }
191
192     if((name.indexOf('/') != -1) || (name.charAt(0) == '[')) {
193       env.throwException("java.lang.NoClassDefFoundError", "IllegalName: " + name);
194     }
195   }
196
197   protected static void checkData(MJIEnv env, byte[] buffer, int offset, int length) {
198     if(offset<0 || length<0 || offset+length > buffer.length) {
199       env.throwException("java.lang.IndexOutOfBoundsException");
200     }
201   }
202
203   static String pkg_class_name = "java.lang.Package";
204
205   @MJI
206   public int getPackages_____3Ljava_lang_Package_2 (MJIEnv env, int objRef) {
207     ClassLoaderInfo sysLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
208     ClassInfo pkgClass = null; 
209     try {
210       pkgClass = sysLoader.getInitializedClassInfo(pkg_class_name, env.getThreadInfo());
211     } catch (ClinitRequired x){
212       env.handleClinitRequest(x.getRequiredClassInfo());
213       return MJIEnv.NULL;
214     }
215
216     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
217     // Returns all of the Packages defined by this class loader and its ancestors
218     Map<String, ClassLoaderInfo> pkgs = cl.getPackages();
219     int size = pkgs.size();
220     // create an array of type java.lang.Package
221     int pkgArr = env.newObjectArray(pkg_class_name, size);
222
223     int i = 0;
224     for(String name: cl.getPackages().keySet()) {
225       int pkgRef = createPackageObject(env, pkgClass, name, cl);
226       // place the object into the array
227       env.setReferenceArrayElement(pkgArr, i++, pkgRef);
228     }
229
230     return pkgArr;
231   }
232
233   @MJI
234   public int getPackage__Ljava_lang_String_2__Ljava_lang_Package_2 (MJIEnv env, int objRef, int nameRef) {
235     ClassLoaderInfo sysLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
236
237     ClassInfo pkgClass = null; 
238     try {
239       pkgClass = sysLoader.getInitializedClassInfo(pkg_class_name, env.getThreadInfo());
240     } catch (ClinitRequired x){
241       env.handleClinitRequest(x.getRequiredClassInfo());
242       return MJIEnv.NULL;
243     }
244
245     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
246     String pkgName = env.getStringObject(nameRef);
247     if(cl.getPackages().get(pkgName)!=null) {
248       return createPackageObject(env, pkgClass, pkgName, cl);
249     } else {
250       return MJIEnv.NULL;
251     }
252   }
253
254   public static int createPackageObject(MJIEnv env, ClassInfo pkgClass, String pkgName, ClassLoaderInfo cl) {
255     int pkgRef = env.newObject(pkgClass);
256     ElementInfo ei = env.getModifiableElementInfo(pkgRef);
257
258     ei.setReferenceField("pkgName", env.newString(pkgName));
259     ei.setReferenceField("loader", cl.getClassLoaderObjectRef());
260     // the rest of the fields set to some dummy value
261     ei.setReferenceField("specTitle", env.newString("spectitle"));
262     ei.setReferenceField("specVersion", env.newString("specversion"));
263     ei.setReferenceField("specVendor", env.newString("specvendor"));
264     ei.setReferenceField("implTitle", env.newString("impltitle"));
265     ei.setReferenceField("implVersion", env.newString("implversion"));
266     ei.setReferenceField("sealBase", MJIEnv.NULL);
267
268     return pkgRef;
269   }
270
271   @MJI
272   public void setDefaultAssertionStatus__Z__V (MJIEnv env, int objRef, boolean enabled) {
273     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
274     cl.setDefaultAssertionStatus(enabled);
275   }
276
277   @MJI
278   public void setPackageAssertionStatus__Ljava_lang_String_2Z__V (MJIEnv env, int objRef, int strRef, boolean enabled) {
279     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
280     String pkgName = env.getStringObject(strRef);
281     cl.setPackageAssertionStatus(pkgName, enabled);
282   }
283
284   @MJI
285   public void setClassAssertionStatus__Ljava_lang_String_2Z__V (MJIEnv env, int objRef, int strRef, boolean enabled) {
286     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
287     String clsName = env.getStringObject(strRef);
288     cl.setClassAssertionStatus(clsName, enabled);
289   }
290
291   @MJI
292   public void clearAssertionStatus____V (MJIEnv env, int objRef) {
293     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
294     cl.clearAssertionStatus();
295   }
296 }