98a8dd4fc124376f5723da41f72b4910f1d59890
[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       ClassInfo ci = cl.getResolvedClassInfo( cname, buffer, offset, length);
148
149       // Note: if the representation is not of a supported major or minor version, loading
150       // throws an UnsupportedClassVersionError. But for now, we do not check for this here 
151       // since we don't do much with minor and major versions
152
153       ThreadInfo ti = env.getThreadInfo();
154       ci.registerClass(ti);
155
156       return ci.getClassObjectRef();
157       
158     } catch (ClassInfoException cix){
159       env.throwException("java.lang.ClassFormatError");
160       return MJIEnv.NULL;
161     }
162   }
163
164
165   protected static boolean check(MJIEnv env, String cname, byte[] buffer, int offset, int length) {
166     // throw SecurityExcpetion if the package prefix is java
167     checkForProhibitedPkg(env, cname);
168
169     // throw NoClassDefFoundError if the given class does name might 
170     // not be a valid binary name
171     checkForIllegalName(env, cname);
172
173     // throw IndexOutOfBoundsException if buffer length is not consistent
174     // with offset
175     checkData(env, buffer, offset, length);
176
177     return !env.hasException();
178   }
179
180   protected static void checkForProhibitedPkg(MJIEnv env, String name) {
181     if(name != null && name.startsWith("java.")) {
182       env.throwException("java.lang.SecurityException", "Prohibited package name: " + name);
183     }
184   }
185
186   protected static void checkForIllegalName(MJIEnv env, String name) {
187     if((name == null) || (name.length() == 0)) {
188       return;
189     }
190
191     if((name.indexOf('/') != -1) || (name.charAt(0) == '[')) {
192       env.throwException("java.lang.NoClassDefFoundError", "IllegalName: " + name);
193     }
194   }
195
196   protected static void checkData(MJIEnv env, byte[] buffer, int offset, int length) {
197     if(offset<0 || length<0 || offset+length > buffer.length) {
198       env.throwException("java.lang.IndexOutOfBoundsException");
199     }
200   }
201
202   static String pkg_class_name = "java.lang.Package";
203
204   @MJI
205   public int getPackages_____3Ljava_lang_Package_2 (MJIEnv env, int objRef) {
206     ClassLoaderInfo sysLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
207     ClassInfo pkgClass = null; 
208     try {
209       pkgClass = sysLoader.getInitializedClassInfo(pkg_class_name, env.getThreadInfo());
210     } catch (ClinitRequired x){
211       env.handleClinitRequest(x.getRequiredClassInfo());
212       return MJIEnv.NULL;
213     }
214
215     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
216     // Returns all of the Packages defined by this class loader and its ancestors
217     Map<String, ClassLoaderInfo> pkgs = cl.getPackages();
218     int size = pkgs.size();
219     // create an array of type java.lang.Package
220     int pkgArr = env.newObjectArray(pkg_class_name, size);
221
222     int i = 0;
223     for(String name: cl.getPackages().keySet()) {
224       int pkgRef = createPackageObject(env, pkgClass, name, cl);
225       // place the object into the array
226       env.setReferenceArrayElement(pkgArr, i++, pkgRef);
227     }
228
229     return pkgArr;
230   }
231
232   @MJI
233   public int getPackage__Ljava_lang_String_2__Ljava_lang_Package_2 (MJIEnv env, int objRef, int nameRef) {
234     ClassLoaderInfo sysLoader = ClassLoaderInfo.getCurrentSystemClassLoader();
235
236     ClassInfo pkgClass = null; 
237     try {
238       pkgClass = sysLoader.getInitializedClassInfo(pkg_class_name, env.getThreadInfo());
239     } catch (ClinitRequired x){
240       env.handleClinitRequest(x.getRequiredClassInfo());
241       return MJIEnv.NULL;
242     }
243
244     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
245     String pkgName = env.getStringObject(nameRef);
246     if(cl.getPackages().get(pkgName)!=null) {
247       return createPackageObject(env, pkgClass, pkgName, cl);
248     } else {
249       return MJIEnv.NULL;
250     }
251   }
252
253   public static int createPackageObject(MJIEnv env, ClassInfo pkgClass, String pkgName, ClassLoaderInfo cl) {
254     int pkgRef = env.newObject(pkgClass);
255     ElementInfo ei = env.getModifiableElementInfo(pkgRef);
256
257     ei.setReferenceField("pkgName", env.newString(pkgName));
258     ei.setReferenceField("loader", cl.getClassLoaderObjectRef());
259     // the rest of the fields set to some dummy value
260     ei.setReferenceField("specTitle", env.newString("spectitle"));
261     ei.setReferenceField("specVersion", env.newString("specversion"));
262     ei.setReferenceField("specVendor", env.newString("specvendor"));
263     ei.setReferenceField("implTitle", env.newString("impltitle"));
264     ei.setReferenceField("implVersion", env.newString("implversion"));
265     ei.setReferenceField("sealBase", MJIEnv.NULL);
266
267     return pkgRef;
268   }
269
270   @MJI
271   public void setDefaultAssertionStatus__Z__V (MJIEnv env, int objRef, boolean enabled) {
272     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
273     cl.setDefaultAssertionStatus(enabled);
274   }
275
276   @MJI
277   public void setPackageAssertionStatus__Ljava_lang_String_2Z__V (MJIEnv env, int objRef, int strRef, boolean enabled) {
278     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
279     String pkgName = env.getStringObject(strRef);
280     cl.setPackageAssertionStatus(pkgName, enabled);
281   }
282
283   @MJI
284   public void setClassAssertionStatus__Ljava_lang_String_2Z__V (MJIEnv env, int objRef, int strRef, boolean enabled) {
285     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
286     String clsName = env.getStringObject(strRef);
287     cl.setClassAssertionStatus(clsName, enabled);
288   }
289
290   @MJI
291   public void clearAssertionStatus____V (MJIEnv env, int objRef) {
292     ClassLoaderInfo cl = env.getClassLoaderInfo(objRef);
293     cl.clearAssertionStatus();
294   }
295 }