common_throws.cc revision ef7d42fca18c16fbaf103822ad16f23246e2905d
1/*
2 * Copyright (C) 2012 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#include "common_throws.h"
18
19#include "base/logging.h"
20#include "class_linker-inl.h"
21#include "dex_file-inl.h"
22#include "dex_instruction-inl.h"
23#include "invoke_type.h"
24#include "mirror/art_method-inl.h"
25#include "mirror/class-inl.h"
26#include "mirror/object-inl.h"
27#include "mirror/object_array-inl.h"
28#include "object_utils.h"
29#include "thread.h"
30#include "verifier/method_verifier.h"
31
32#include <sstream>
33
34namespace art {
35
36static void AddReferrerLocation(std::ostream& os, mirror::Class* referrer)
37    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
38  if (referrer != NULL) {
39    ClassHelper kh(referrer);
40    std::string location(kh.GetLocation());
41    if (!location.empty()) {
42      os << " (declaration of '" << PrettyDescriptor(referrer)
43            << "' appears in " << location << ")";
44    }
45  }
46}
47
48static void ThrowException(const ThrowLocation* throw_location, const char* exception_descriptor,
49                           mirror::Class* referrer, const char* fmt, va_list* args = NULL)
50    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
51  std::ostringstream msg;
52  if (args != NULL) {
53    std::string vmsg;
54    StringAppendV(&vmsg, fmt, *args);
55    msg << vmsg;
56  } else {
57    msg << fmt;
58  }
59  AddReferrerLocation(msg, referrer);
60  Thread* self = Thread::Current();
61  if (throw_location == NULL) {
62    ThrowLocation computed_throw_location = self->GetCurrentLocationForThrow();
63    self->ThrowNewException(computed_throw_location, exception_descriptor, msg.str().c_str());
64  } else {
65    self->ThrowNewException(*throw_location, exception_descriptor, msg.str().c_str());
66  }
67}
68
69// AbstractMethodError
70
71void ThrowAbstractMethodError(mirror::ArtMethod* method) {
72  ThrowException(NULL, "Ljava/lang/AbstractMethodError;", NULL,
73                 StringPrintf("abstract method \"%s\"",
74                              PrettyMethod(method).c_str()).c_str());
75}
76
77// ArithmeticException
78
79void ThrowArithmeticExceptionDivideByZero() {
80  ThrowException(NULL, "Ljava/lang/ArithmeticException;", NULL, "divide by zero");
81}
82
83// ArrayIndexOutOfBoundsException
84
85void ThrowArrayIndexOutOfBoundsException(int index, int length) {
86  ThrowException(NULL, "Ljava/lang/ArrayIndexOutOfBoundsException;", NULL,
87                 StringPrintf("length=%d; index=%d", length, index).c_str());
88}
89
90// ArrayStoreException
91
92void ThrowArrayStoreException(mirror::Class* element_class, mirror::Class* array_class) {
93  ThrowException(NULL, "Ljava/lang/ArrayStoreException;", NULL,
94                 StringPrintf("%s cannot be stored in an array of type %s",
95                              PrettyDescriptor(element_class).c_str(),
96                              PrettyDescriptor(array_class).c_str()).c_str());
97}
98
99// ClassCastException
100
101void ThrowClassCastException(mirror::Class* dest_type, mirror::Class* src_type) {
102  ThrowException(NULL, "Ljava/lang/ClassCastException;", NULL,
103                 StringPrintf("%s cannot be cast to %s",
104                              PrettyDescriptor(src_type).c_str(),
105                              PrettyDescriptor(dest_type).c_str()).c_str());
106}
107
108void ThrowClassCastException(const ThrowLocation* throw_location, const char* msg) {
109  ThrowException(throw_location, "Ljava/lang/ClassCastException;", NULL, msg);
110}
111
112// ClassCircularityError
113
114void ThrowClassCircularityError(mirror::Class* c) {
115  std::ostringstream msg;
116  msg << PrettyDescriptor(c);
117  ThrowException(NULL, "Ljava/lang/ClassCircularityError;", c, msg.str().c_str());
118}
119
120// ClassFormatError
121
122void ThrowClassFormatError(mirror::Class* referrer, const char* fmt, ...) {
123  va_list args;
124  va_start(args, fmt);
125  ThrowException(NULL, "Ljava/lang/ClassFormatError;", referrer, fmt, &args);
126  va_end(args);}
127
128// IllegalAccessError
129
130void ThrowIllegalAccessErrorClass(mirror::Class* referrer, mirror::Class* accessed) {
131  std::ostringstream msg;
132  msg << "Illegal class access: '" << PrettyDescriptor(referrer) << "' attempting to access '"
133      << PrettyDescriptor(accessed) << "'";
134  ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str());
135}
136
137void ThrowIllegalAccessErrorClassForMethodDispatch(mirror::Class* referrer, mirror::Class* accessed,
138                                                   mirror::ArtMethod* called,
139                                                   InvokeType type) {
140  std::ostringstream msg;
141  msg << "Illegal class access ('" << PrettyDescriptor(referrer) << "' attempting to access '"
142      << PrettyDescriptor(accessed) << "') in attempt to invoke " << type
143      << " method " << PrettyMethod(called).c_str();
144  ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str());
145}
146
147void ThrowIllegalAccessErrorMethod(mirror::Class* referrer, mirror::ArtMethod* accessed) {
148  std::ostringstream msg;
149  msg << "Method '" << PrettyMethod(accessed) << "' is inaccessible to class '"
150      << PrettyDescriptor(referrer) << "'";
151  ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str());
152}
153
154void ThrowIllegalAccessErrorField(mirror::Class* referrer, mirror::ArtField* accessed) {
155  std::ostringstream msg;
156  msg << "Field '" << PrettyField(accessed, false) << "' is inaccessible to class '"
157      << PrettyDescriptor(referrer) << "'";
158  ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, msg.str().c_str());
159}
160
161void ThrowIllegalAccessErrorFinalField(mirror::ArtMethod* referrer,
162                                       mirror::ArtField* accessed) {
163  std::ostringstream msg;
164  msg << "Final field '" << PrettyField(accessed, false) << "' cannot be written to by method '"
165      << PrettyMethod(referrer) << "'";
166  ThrowException(NULL, "Ljava/lang/IllegalAccessError;",
167                 referrer != NULL ? referrer->GetClass() : NULL,
168                 msg.str().c_str());
169}
170
171void ThrowIllegalAccessError(mirror::Class* referrer, const char* fmt, ...) {
172  va_list args;
173  va_start(args, fmt);
174  ThrowException(NULL, "Ljava/lang/IllegalAccessError;", referrer, fmt, &args);
175  va_end(args);
176}
177
178// IllegalArgumentException
179
180void ThrowIllegalArgumentException(const ThrowLocation* throw_location, const char* msg) {
181  ThrowException(throw_location, "Ljava/lang/IllegalArgumentException;", NULL, msg);
182}
183
184
185// IncompatibleClassChangeError
186
187void ThrowIncompatibleClassChangeError(InvokeType expected_type, InvokeType found_type,
188                                       mirror::ArtMethod* method,
189                                       mirror::ArtMethod* referrer) {
190  std::ostringstream msg;
191  msg << "The method '" << PrettyMethod(method) << "' was expected to be of type "
192      << expected_type << " but instead was found to be of type " << found_type;
193  ThrowException(NULL, "Ljava/lang/IncompatibleClassChangeError;",
194                 referrer != NULL ? referrer->GetClass() : NULL,
195                 msg.str().c_str());
196}
197
198void ThrowIncompatibleClassChangeErrorClassForInterfaceDispatch(mirror::ArtMethod* interface_method,
199                                                                mirror::Object* this_object,
200                                                                mirror::ArtMethod* referrer) {
201  // Referrer is calling interface_method on this_object, however, the interface_method isn't
202  // implemented by this_object.
203  CHECK(this_object != NULL);
204  std::ostringstream msg;
205  msg << "Class '" << PrettyDescriptor(this_object->GetClass())
206      << "' does not implement interface '"
207      << PrettyDescriptor(interface_method->GetDeclaringClass())
208      << "' in call to '" << PrettyMethod(interface_method) << "'";
209  ThrowException(NULL, "Ljava/lang/IncompatibleClassChangeError;",
210                 referrer != NULL ? referrer->GetClass() : NULL,
211                 msg.str().c_str());
212}
213
214void ThrowIncompatibleClassChangeErrorField(mirror::ArtField* resolved_field, bool is_static,
215                                            mirror::ArtMethod* referrer) {
216  std::ostringstream msg;
217  msg << "Expected '" << PrettyField(resolved_field) << "' to be a "
218      << (is_static ? "static" : "instance") << " field" << " rather than a "
219      << (is_static ? "instance" : "static") << " field";
220  ThrowException(NULL, "Ljava/lang/IncompatibleClassChangeError;", referrer->GetClass(),
221                 msg.str().c_str());
222}
223
224void ThrowIncompatibleClassChangeError(mirror::Class* referrer, const char* fmt, ...) {
225  va_list args;
226  va_start(args, fmt);
227  ThrowException(NULL, "Ljava/lang/IncompatibleClassChangeError;", referrer, fmt, &args);
228  va_end(args);
229}
230
231// IOException
232
233void ThrowIOException(const char* fmt, ...) {
234  va_list args;
235  va_start(args, fmt);
236  ThrowException(NULL, "Ljava/io/IOException;", NULL, fmt, &args);
237  va_end(args);
238}
239
240// LinkageError
241
242void ThrowLinkageError(mirror::Class* referrer, const char* fmt, ...) {
243  va_list args;
244  va_start(args, fmt);
245  ThrowException(NULL, "Ljava/lang/LinkageError;", referrer, fmt, &args);
246  va_end(args);
247}
248
249// NegativeArraySizeException
250
251void ThrowNegativeArraySizeException(int size) {
252  ThrowException(NULL, "Ljava/lang/NegativeArraySizeException;", NULL,
253                 StringPrintf("%d", size).c_str());
254}
255
256void ThrowNegativeArraySizeException(const char* msg) {
257  ThrowException(NULL, "Ljava/lang/NegativeArraySizeException;", NULL, msg);
258}
259
260// NoSuchFieldError
261
262void ThrowNoSuchFieldError(const StringPiece& scope, mirror::Class* c,
263                           const StringPiece& type, const StringPiece& name)
264    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
265  ClassHelper kh(c);
266  std::ostringstream msg;
267  msg << "No " << scope << "field " << name << " of type " << type
268      << " in class " << kh.GetDescriptor() << " or its superclasses";
269  ThrowException(NULL, "Ljava/lang/NoSuchFieldError;", c, msg.str().c_str());
270}
271
272// NoSuchMethodError
273
274void ThrowNoSuchMethodError(InvokeType type, mirror::Class* c, const StringPiece& name,
275                            const Signature& signature) {
276  std::ostringstream msg;
277  ClassHelper kh(c);
278  msg << "No " << type << " method " << name << signature
279      << " in class " << kh.GetDescriptor() << " or its super classes";
280  ThrowException(NULL, "Ljava/lang/NoSuchMethodError;", c, msg.str().c_str());
281}
282
283void ThrowNoSuchMethodError(uint32_t method_idx) {
284  Thread* self = Thread::Current();
285  ThrowLocation throw_location = self->GetCurrentLocationForThrow();
286  mirror::DexCache* dex_cache = throw_location.GetMethod()->GetDeclaringClass()->GetDexCache();
287  const DexFile& dex_file = *dex_cache->GetDexFile();
288  std::ostringstream msg;
289  msg << "No method '" << PrettyMethod(method_idx, dex_file, true) << "'";
290  ThrowException(&throw_location, "Ljava/lang/NoSuchMethodError;",
291                 throw_location.GetMethod()->GetDeclaringClass(), msg.str().c_str());
292}
293
294// NullPointerException
295
296void ThrowNullPointerExceptionForFieldAccess(const ThrowLocation& throw_location,
297                                             mirror::ArtField* field, bool is_read) {
298  std::ostringstream msg;
299  msg << "Attempt to " << (is_read ? "read from" : "write to")
300      << " field '" << PrettyField(field, true) << "' on a null object reference";
301  ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL, msg.str().c_str());
302}
303
304static void ThrowNullPointerExceptionForMethodAccessImpl(const ThrowLocation& throw_location,
305                                                         uint32_t method_idx,
306                                                         const DexFile& dex_file,
307                                                         InvokeType type)
308    SHARED_LOCKS_REQUIRED(Locks::mutator_lock_) {
309  std::ostringstream msg;
310  msg << "Attempt to invoke " << type << " method '"
311      << PrettyMethod(method_idx, dex_file, true) << "' on a null object reference";
312  ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL, msg.str().c_str());
313}
314
315void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location,
316                                              uint32_t method_idx,
317                                              InvokeType type) {
318  mirror::DexCache* dex_cache = throw_location.GetMethod()->GetDeclaringClass()->GetDexCache();
319  const DexFile& dex_file = *dex_cache->GetDexFile();
320  ThrowNullPointerExceptionForMethodAccessImpl(throw_location, method_idx,
321                                               dex_file, type);
322}
323
324void ThrowNullPointerExceptionForMethodAccess(const ThrowLocation& throw_location,
325                                              mirror::ArtMethod* method,
326                                              InvokeType type) {
327  mirror::DexCache* dex_cache = method->GetDeclaringClass()->GetDexCache();
328  const DexFile& dex_file = *dex_cache->GetDexFile();
329  ThrowNullPointerExceptionForMethodAccessImpl(throw_location, method->GetDexMethodIndex(),
330                                               dex_file, type);
331}
332
333void ThrowNullPointerExceptionFromDexPC(const ThrowLocation& throw_location) {
334  const DexFile::CodeItem* code = MethodHelper(throw_location.GetMethod()).GetCodeItem();
335  uint32_t throw_dex_pc = throw_location.GetDexPc();
336  CHECK_LT(throw_dex_pc, code->insns_size_in_code_units_);
337  const Instruction* instr = Instruction::At(&code->insns_[throw_dex_pc]);
338  switch (instr->Opcode()) {
339    case Instruction::INVOKE_DIRECT:
340      ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_35c(), kDirect);
341      break;
342    case Instruction::INVOKE_DIRECT_RANGE:
343      ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_3rc(), kDirect);
344      break;
345    case Instruction::INVOKE_VIRTUAL:
346      ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_35c(), kVirtual);
347      break;
348    case Instruction::INVOKE_VIRTUAL_RANGE:
349      ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_3rc(), kVirtual);
350      break;
351    case Instruction::INVOKE_INTERFACE:
352      ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_35c(), kInterface);
353      break;
354    case Instruction::INVOKE_INTERFACE_RANGE:
355      ThrowNullPointerExceptionForMethodAccess(throw_location, instr->VRegB_3rc(), kInterface);
356      break;
357    case Instruction::INVOKE_VIRTUAL_QUICK:
358    case Instruction::INVOKE_VIRTUAL_RANGE_QUICK: {
359      // Since we replaced the method index, we ask the verifier to tell us which
360      // method is invoked at this location.
361      mirror::ArtMethod* method =
362          verifier::MethodVerifier::FindInvokedMethodAtDexPc(throw_location.GetMethod(),
363                                                             throw_location.GetDexPc());
364      if (method != NULL) {
365        // NPE with precise message.
366        ThrowNullPointerExceptionForMethodAccess(throw_location, method, kVirtual);
367      } else {
368        // NPE with imprecise message.
369        ThrowNullPointerException(&throw_location,
370                                  "Attempt to invoke a virtual method on a null object reference");
371      }
372      break;
373    }
374    case Instruction::IGET:
375    case Instruction::IGET_WIDE:
376    case Instruction::IGET_OBJECT:
377    case Instruction::IGET_BOOLEAN:
378    case Instruction::IGET_BYTE:
379    case Instruction::IGET_CHAR:
380    case Instruction::IGET_SHORT: {
381      mirror::ArtField* field =
382          Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(),
383                                                             throw_location.GetMethod(), false);
384      ThrowNullPointerExceptionForFieldAccess(throw_location, field, true /* read */);
385      break;
386    }
387    case Instruction::IGET_QUICK:
388    case Instruction::IGET_WIDE_QUICK:
389    case Instruction::IGET_OBJECT_QUICK: {
390      // Since we replaced the field index, we ask the verifier to tell us which
391      // field is accessed at this location.
392      mirror::ArtField* field =
393          verifier::MethodVerifier::FindAccessedFieldAtDexPc(throw_location.GetMethod(),
394                                                             throw_location.GetDexPc());
395      if (field != NULL) {
396        // NPE with precise message.
397        ThrowNullPointerExceptionForFieldAccess(throw_location, field, true /* read */);
398      } else {
399        // NPE with imprecise message.
400        ThrowNullPointerException(&throw_location,
401                                  "Attempt to read from a field on a null object reference");
402      }
403      break;
404    }
405    case Instruction::IPUT:
406    case Instruction::IPUT_WIDE:
407    case Instruction::IPUT_OBJECT:
408    case Instruction::IPUT_BOOLEAN:
409    case Instruction::IPUT_BYTE:
410    case Instruction::IPUT_CHAR:
411    case Instruction::IPUT_SHORT: {
412      mirror::ArtField* field =
413          Runtime::Current()->GetClassLinker()->ResolveField(instr->VRegC_22c(),
414                                                             throw_location.GetMethod(), false);
415      ThrowNullPointerExceptionForFieldAccess(throw_location, field, false /* write */);
416      break;
417    }
418    case Instruction::IPUT_QUICK:
419    case Instruction::IPUT_WIDE_QUICK:
420    case Instruction::IPUT_OBJECT_QUICK: {
421      // Since we replaced the field index, we ask the verifier to tell us which
422      // field is accessed at this location.
423      mirror::ArtField* field =
424          verifier::MethodVerifier::FindAccessedFieldAtDexPc(throw_location.GetMethod(),
425                                                             throw_location.GetDexPc());
426      if (field != NULL) {
427        // NPE with precise message.
428        ThrowNullPointerExceptionForFieldAccess(throw_location, field, false /* write */);
429      } else {
430        // NPE with imprecise message.
431        ThrowNullPointerException(&throw_location,
432                                  "Attempt to write to a field on a null object reference");
433      }
434      break;
435    }
436    case Instruction::AGET:
437    case Instruction::AGET_WIDE:
438    case Instruction::AGET_OBJECT:
439    case Instruction::AGET_BOOLEAN:
440    case Instruction::AGET_BYTE:
441    case Instruction::AGET_CHAR:
442    case Instruction::AGET_SHORT:
443      ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL,
444                     "Attempt to read from null array");
445      break;
446    case Instruction::APUT:
447    case Instruction::APUT_WIDE:
448    case Instruction::APUT_OBJECT:
449    case Instruction::APUT_BOOLEAN:
450    case Instruction::APUT_BYTE:
451    case Instruction::APUT_CHAR:
452    case Instruction::APUT_SHORT:
453      ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL,
454                     "Attempt to write to null array");
455      break;
456    case Instruction::ARRAY_LENGTH:
457      ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL,
458                     "Attempt to get length of null array");
459      break;
460    default: {
461      // TODO: We should have covered all the cases where we expect a NPE above, this
462      //       message/logging is so we can improve any cases we've missed in the future.
463      const DexFile& dex_file =
464          *throw_location.GetMethod()->GetDeclaringClass()->GetDexCache()->GetDexFile();
465      ThrowException(&throw_location, "Ljava/lang/NullPointerException;", NULL,
466                     StringPrintf("Null pointer exception during instruction '%s'",
467                                  instr->DumpString(&dex_file).c_str()).c_str());
468      break;
469    }
470  }
471}
472
473void ThrowNullPointerException(const ThrowLocation* throw_location, const char* msg) {
474  ThrowException(throw_location, "Ljava/lang/NullPointerException;", NULL, msg);
475}
476
477// RuntimeException
478
479void ThrowRuntimeException(const char* fmt, ...) {
480  va_list args;
481  va_start(args, fmt);
482  ThrowException(NULL, "Ljava/lang/RuntimeException;", NULL, fmt, &args);
483  va_end(args);
484}
485
486// VerifyError
487
488void ThrowVerifyError(mirror::Class* referrer, const char* fmt, ...) {
489  va_list args;
490  va_start(args, fmt);
491  ThrowException(NULL, "Ljava/lang/VerifyError;", referrer, fmt, &args);
492  va_end(args);
493}
494
495}  // namespace art
496