• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * java.lang.reflect.Field
19  */
20 #include "Dalvik.h"
21 #include "native/InternalNativePriv.h"
22 
23 
24 /*
25  * Get the address of a field from an object.  This can be used with "get"
26  * or "set".
27  *
28  * "declaringClass" is the class in which the field was declared.  For an
29  * instance field, "obj" is the object that holds the field data; for a
30  * static field its value is ignored.
31  *
32  * "If the underlying field is static, the class that declared the
33  * field is initialized if it has not already been initialized."
34  *
35  * On failure, throws an exception and returns NULL.
36  *
37  * The documentation lists exceptional conditions and the exceptions that
38  * should be thrown, but doesn't say which exception previals when two or
39  * more exceptional conditions exist at the same time.  For example,
40  * attempting to set a protected field from an unrelated class causes an
41  * IllegalAccessException, while passing in a data type that doesn't match
42  * the field causes an IllegalArgumentException.  If code does both at the
43  * same time, we have to choose one or othe other.
44  *
45  * The expected order is:
46  *  (1) Check for illegal access. Throw IllegalAccessException.
47  *  (2) Make sure the object actually has the field.  Throw
48  *      IllegalArgumentException.
49  *  (3) Make sure the field matches the expected type, e.g. if we issued
50  *      a "getInteger" call make sure the field is an integer or can be
51  *      converted to an int with a widening conversion.  Throw
52  *      IllegalArgumentException.
53  *  (4) Make sure "obj" is not null.  Throw NullPointerException.
54  *
55  * TODO: we're currently handling #3 after #4, because we don't check the
56  * widening conversion until we're actually extracting the value from the
57  * object (which won't work well if it's a null reference).
58  */
getFieldDataAddr(Object * obj,ClassObject * declaringClass,int slot,bool isSetOperation,bool noAccessCheck)59 static JValue* getFieldDataAddr(Object* obj, ClassObject* declaringClass,
60     int slot, bool isSetOperation, bool noAccessCheck)
61 {
62     Field* field;
63     JValue* result;
64 
65     field = dvmSlotToField(declaringClass, slot);
66     assert(field != NULL);
67 
68     /* verify access */
69     if (!noAccessCheck) {
70         if (isSetOperation && dvmIsFinalField(field)) {
71             dvmThrowException("Ljava/lang/IllegalAccessException;",
72                 "field is marked 'final'");
73             return NULL;
74         }
75 
76         ClassObject* callerClass =
77             dvmGetCaller2Class(dvmThreadSelf()->curFrame);
78 
79         /*
80          * We need to check two things:
81          *  (1) Would an instance of the calling class have access to the field?
82          *  (2) If the field is "protected", is the object an instance of the
83          *      calling class, or is the field's declaring class in the same
84          *      package as the calling class?
85          *
86          * #1 is basic access control.  #2 ensures that, just because
87          * you're a subclass of Foo, you can't mess with protected fields
88          * in arbitrary Foo objects from other packages.
89          */
90         if (!dvmCheckFieldAccess(callerClass, field)) {
91             dvmThrowException("Ljava/lang/IllegalAccessException;",
92                 "access to field not allowed");
93             return NULL;
94         }
95         if (dvmIsProtectedField(field)) {
96             bool isInstance, samePackage;
97 
98             if (obj != NULL)
99                 isInstance = dvmInstanceof(obj->clazz, callerClass);
100             else
101                 isInstance = false;
102             samePackage = dvmInSamePackage(declaringClass, callerClass);
103 
104             if (!isInstance && !samePackage) {
105                 dvmThrowException("Ljava/lang/IllegalAccessException;",
106                     "access to protected field not allowed");
107                 return NULL;
108             }
109         }
110     }
111 
112     if (dvmIsStaticField(field)) {
113         /* init class if necessary, then return ptr to storage in "field" */
114         if (!dvmIsClassInitialized(declaringClass)) {
115             if (!dvmInitClass(declaringClass)) {
116                 assert(dvmCheckException(dvmThreadSelf()));
117                 return NULL;
118             }
119         }
120 
121         result = dvmStaticFieldPtr((StaticField*) field);
122     } else {
123         /*
124          * Verify object is of correct type (i.e. it actually has the
125          * expected field in it), then grab a pointer to obj storage.
126          * The call to dvmVerifyObjectInClass throws an NPE if "obj" is NULL.
127          */
128         if (!dvmVerifyObjectInClass(obj, declaringClass)) {
129             assert(dvmCheckException(dvmThreadSelf()));
130             if (obj != NULL) {
131                 LOGD("Wrong type of object for field lookup: %s %s\n",
132                     obj->clazz->descriptor, declaringClass->descriptor);
133             }
134             return NULL;
135         }
136         result = dvmFieldPtr(obj, ((InstField*) field)->byteOffset);
137     }
138 
139     return result;
140 }
141 
142 /*
143  * public int getFieldModifiers(Class declaringClass, int slot)
144  */
Dalvik_java_lang_reflect_Field_getFieldModifiers(const u4 * args,JValue * pResult)145 static void Dalvik_java_lang_reflect_Field_getFieldModifiers(
146     const u4* args, JValue* pResult)
147 {
148     // ignore thisPtr in args[0]
149     ClassObject* declaringClass = (ClassObject*) args[1];
150     int slot = args[2];
151     Field* field;
152 
153     field = dvmSlotToField(declaringClass, slot);
154     RETURN_INT(field->accessFlags & JAVA_FLAGS_MASK);
155 }
156 
157 /*
158  * private Object getField(Object o, Class declaringClass, Class type,
159  *     int slot, boolean noAccessCheck)
160  *
161  * Primitive types need to be boxed.
162  */
Dalvik_java_lang_reflect_Field_getField(const u4 * args,JValue * pResult)163 static void Dalvik_java_lang_reflect_Field_getField(const u4* args,
164     JValue* pResult)
165 {
166     // ignore thisPtr in args[0]
167     Object* obj = (Object*) args[1];
168     ClassObject* declaringClass = (ClassObject*) args[2];
169     ClassObject* fieldType = (ClassObject*) args[3];
170     int slot = args[4];
171     bool noAccessCheck = (args[5] != 0);
172     JValue value;
173     const JValue* fieldPtr;
174     DataObject* result;
175 
176     //dvmDumpClass(obj->clazz, kDumpClassFullDetail);
177 
178     /* get a pointer to the field's data; performs access checks */
179     fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck);
180     if (fieldPtr == NULL)
181         RETURN_VOID();
182 
183     /* copy 4 or 8 bytes out */
184     if (fieldType->primitiveType == PRIM_LONG ||
185         fieldType->primitiveType == PRIM_DOUBLE)
186     {
187         value.j = fieldPtr->j;
188     } else {
189         value.i = fieldPtr->i;
190     }
191 
192     result = dvmWrapPrimitive(value, fieldType);
193     dvmReleaseTrackedAlloc((Object*) result, NULL);
194     RETURN_PTR(result);
195 }
196 
197 /*
198  * private void setField(Object o, Class declaringClass, Class type,
199  *     int slot, boolean noAccessCheck, Object value)
200  *
201  * When assigning into a primitive field we will automatically extract
202  * the value from box types.
203  */
Dalvik_java_lang_reflect_Field_setField(const u4 * args,JValue * pResult)204 static void Dalvik_java_lang_reflect_Field_setField(const u4* args,
205     JValue* pResult)
206 {
207     // ignore thisPtr in args[0]
208     Object* obj = (Object*) args[1];
209     ClassObject* declaringClass = (ClassObject*) args[2];
210     ClassObject* fieldType = (ClassObject*) args[3];
211     int slot = args[4];
212     bool noAccessCheck = (args[5] != 0);
213     Object* valueObj = (Object*) args[6];
214     JValue* fieldPtr;
215     JValue value;
216 
217     /* unwrap primitive, or verify object type */
218     if (!dvmUnwrapPrimitive(valueObj, fieldType, &value)) {
219         dvmThrowException("Ljava/lang/IllegalArgumentException;",
220             "invalid value for field");
221         RETURN_VOID();
222     }
223 
224     /* get a pointer to the field's data; performs access checks */
225     fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
226     if (fieldPtr == NULL)
227         RETURN_VOID();
228 
229     /* store 4 or 8 bytes */
230     if (fieldType->primitiveType == PRIM_LONG ||
231         fieldType->primitiveType == PRIM_DOUBLE)
232     {
233         fieldPtr->j = value.j;
234     } else {
235         fieldPtr->i = value.i;
236     }
237 
238     RETURN_VOID();
239 }
240 
241 /*
242  * Convert a reflection primitive type ordinal (inherited from the previous
243  * VM's reflection classes) to our value.
244  */
convPrimType(int typeNum)245 static PrimitiveType convPrimType(int typeNum)
246 {
247     static const PrimitiveType conv[PRIM_MAX] = {
248         PRIM_NOT, PRIM_BOOLEAN, PRIM_BYTE, PRIM_CHAR, PRIM_SHORT,
249         PRIM_INT, PRIM_FLOAT, PRIM_LONG, PRIM_DOUBLE
250     };
251     if (typeNum <= 0 || typeNum > 8)
252         return PRIM_NOT;
253     return conv[typeNum];
254 }
255 
256 /*
257  * Primitive field getters, e.g.:
258  * private double getIField(Object o, Class declaringClass,
259  *     Class type, int slot, boolean noAccessCheck, int type_no)
260  *
261  * The "type_no" is defined by the java.lang.reflect.Field class.
262  */
Dalvik_java_lang_reflect_Field_getPrimitiveField(const u4 * args,JValue * pResult)263 static void Dalvik_java_lang_reflect_Field_getPrimitiveField(const u4* args,
264     JValue* pResult)
265 {
266     // ignore thisPtr in args[0]
267     Object* obj = (Object*) args[1];
268     ClassObject* declaringClass = (ClassObject*) args[2];
269     ClassObject* fieldType = (ClassObject*) args[3];
270     int slot = args[4];
271     bool noAccessCheck = (args[5] != 0);
272     int typeNum = args[6];
273     PrimitiveType targetType = convPrimType(typeNum);
274     const JValue* fieldPtr;
275     JValue value;
276 
277     if (!dvmIsPrimitiveClass(fieldType)) {
278         dvmThrowException("Ljava/lang/IllegalArgumentException;",
279             "not a primitive field");
280         RETURN_VOID();
281     }
282 
283     /* get a pointer to the field's data; performs access checks */
284     fieldPtr = getFieldDataAddr(obj, declaringClass, slot, false,noAccessCheck);
285     if (fieldPtr == NULL)
286         RETURN_VOID();
287 
288     /* copy 4 or 8 bytes out */
289     if (fieldType->primitiveType == PRIM_LONG ||
290         fieldType->primitiveType == PRIM_DOUBLE)
291     {
292         value.j = fieldPtr->j;
293     } else {
294         value.i = fieldPtr->i;
295     }
296 
297     /* retrieve value, performing a widening conversion if necessary */
298     if (dvmConvertPrimitiveValue(fieldType->primitiveType, targetType,
299         &(value.i), &(pResult->i)) < 0)
300     {
301         dvmThrowException("Ljava/lang/IllegalArgumentException;",
302             "invalid primitive conversion");
303         RETURN_VOID();
304     }
305 }
306 
307 /*
308  * Primitive field setters, e.g.:
309  * private void setIField(Object o, Class declaringClass,
310  *     Class type, int slot, boolean noAccessCheck, int type_no, int value)
311  *
312  * The "type_no" is defined by the java.lang.reflect.Field class.
313  */
Dalvik_java_lang_reflect_Field_setPrimitiveField(const u4 * args,JValue * pResult)314 static void Dalvik_java_lang_reflect_Field_setPrimitiveField(const u4* args,
315     JValue* pResult)
316 {
317     // ignore thisPtr in args[0]
318     Object* obj = (Object*) args[1];
319     ClassObject* declaringClass = (ClassObject*) args[2];
320     ClassObject* fieldType = (ClassObject*) args[3];
321     int slot = args[4];
322     bool noAccessCheck = (args[5] != 0);
323     int typeNum = args[6];
324     const s4* valuePtr = (s4*) &args[7];
325     PrimitiveType srcType = convPrimType(typeNum);
326     JValue* fieldPtr;
327     JValue value;
328 
329     if (!dvmIsPrimitiveClass(fieldType)) {
330         dvmThrowException("Ljava/lang/IllegalArgumentException;",
331             "not a primitive field");
332         RETURN_VOID();
333     }
334 
335     /* convert the 32/64-bit arg to a JValue matching the field type */
336     if (dvmConvertPrimitiveValue(srcType, fieldType->primitiveType,
337         valuePtr, &(value.i)) < 0)
338     {
339         dvmThrowException("Ljava/lang/IllegalArgumentException;",
340             "invalid primitive conversion");
341         RETURN_VOID();
342     }
343 
344     /* get a pointer to the field's data; performs access checks */
345     fieldPtr = getFieldDataAddr(obj, declaringClass, slot, true, noAccessCheck);
346     if (fieldPtr == NULL)
347         RETURN_VOID();
348 
349     /* store 4 or 8 bytes */
350     if (fieldType->primitiveType == PRIM_LONG ||
351         fieldType->primitiveType == PRIM_DOUBLE)
352     {
353         fieldPtr->j = value.j;
354     } else {
355         fieldPtr->i = value.i;
356     }
357 
358     RETURN_VOID();
359 }
360 
361 /*
362  * public Annotation[] getDeclaredAnnotations(Class declaringClass, int slot)
363  *
364  * Return the annotations declared for this field.
365  */
Dalvik_java_lang_reflect_Field_getDeclaredAnnotations(const u4 * args,JValue * pResult)366 static void Dalvik_java_lang_reflect_Field_getDeclaredAnnotations(
367     const u4* args, JValue* pResult)
368 {
369     // ignore thisPtr in args[0]
370     ClassObject* declaringClass = (ClassObject*) args[1];
371     int slot = args[2];
372     Field* field;
373 
374     field = dvmSlotToField(declaringClass, slot);
375     assert(field != NULL);
376 
377     ArrayObject* annos = dvmGetFieldAnnotations(field);
378     dvmReleaseTrackedAlloc((Object*) annos, NULL);
379     RETURN_PTR(annos);
380 }
381 
382 /*
383  * private Object[] getSignatureAnnotation()
384  *
385  * Returns the signature annotation.
386  */
Dalvik_java_lang_reflect_Field_getSignatureAnnotation(const u4 * args,JValue * pResult)387 static void Dalvik_java_lang_reflect_Field_getSignatureAnnotation(const u4* args,
388     JValue* pResult)
389 {
390     // ignore thisPtr in args[0]
391     ClassObject* declaringClass = (ClassObject*) args[1];
392     int slot = args[2];
393     Field* field;
394 
395     field = dvmSlotToField(declaringClass, slot);
396     assert(field != NULL);
397 
398     ArrayObject* arr = dvmGetFieldSignatureAnnotation(field);
399     dvmReleaseTrackedAlloc((Object*) arr, NULL);
400     RETURN_PTR(arr);
401 }
402 
403 const DalvikNativeMethod dvm_java_lang_reflect_Field[] = {
404     { "getFieldModifiers",  "(Ljava/lang/Class;I)I",
405         Dalvik_java_lang_reflect_Field_getFieldModifiers },
406     { "getField",           "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZ)Ljava/lang/Object;",
407         Dalvik_java_lang_reflect_Field_getField },
408     { "getBField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)B",
409         Dalvik_java_lang_reflect_Field_getPrimitiveField },
410     { "getCField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)C",
411         Dalvik_java_lang_reflect_Field_getPrimitiveField },
412     { "getDField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)D",
413         Dalvik_java_lang_reflect_Field_getPrimitiveField },
414     { "getFField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)F",
415         Dalvik_java_lang_reflect_Field_getPrimitiveField },
416     { "getIField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)I",
417         Dalvik_java_lang_reflect_Field_getPrimitiveField },
418     { "getJField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)J",
419         Dalvik_java_lang_reflect_Field_getPrimitiveField },
420     { "getSField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)S",
421         Dalvik_java_lang_reflect_Field_getPrimitiveField },
422     { "getZField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZI)Z",
423         Dalvik_java_lang_reflect_Field_getPrimitiveField },
424     { "setField",           "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZLjava/lang/Object;)V",
425         Dalvik_java_lang_reflect_Field_setField },
426     { "setBField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIB)V",
427         Dalvik_java_lang_reflect_Field_setPrimitiveField },
428     { "setCField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIC)V",
429         Dalvik_java_lang_reflect_Field_setPrimitiveField },
430     { "setDField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZID)V",
431         Dalvik_java_lang_reflect_Field_setPrimitiveField },
432     { "setFField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIF)V",
433         Dalvik_java_lang_reflect_Field_setPrimitiveField },
434     { "setIField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZII)V",
435         Dalvik_java_lang_reflect_Field_setPrimitiveField },
436     { "setJField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIJ)V",
437         Dalvik_java_lang_reflect_Field_setPrimitiveField },
438     { "setSField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIS)V",
439         Dalvik_java_lang_reflect_Field_setPrimitiveField },
440     { "setZField",          "(Ljava/lang/Object;Ljava/lang/Class;Ljava/lang/Class;IZIZ)V",
441         Dalvik_java_lang_reflect_Field_setPrimitiveField },
442     { "getDeclaredAnnotations", "(Ljava/lang/Class;I)[Ljava/lang/annotation/Annotation;",
443         Dalvik_java_lang_reflect_Field_getDeclaredAnnotations },
444     { "getSignatureAnnotation",  "(Ljava/lang/Class;I)[Ljava/lang/Object;",
445         Dalvik_java_lang_reflect_Field_getSignatureAnnotation },
446     { NULL, NULL, NULL },
447 };
448 
449