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