diff options
author | 2022-02-04 14:15:01 +0000 | |
---|---|---|
committer | 2022-02-18 11:06:25 +0000 | |
commit | 14e8d6429839c58f873f6fdfc5663151aa803b37 (patch) | |
tree | 105619787c7747818650085669035f34a6ea36a7 | |
parent | 5171813632baff231dc2a9b0e794a13c908ab344 (diff) |
Update null pointer exception message to print out the method
Let's add the method in the logging string for context when debugging failures. This should help developers debug more quickly.
Bug: 217171086
Test: art/test/testrunner/testrunner.py --host --64 --optimizing -b
Change-Id: I1aadeaa536f58a22dccaf6f1c783df23c9430c7a
-rw-r--r-- | runtime/common_throws.cc | 12 | ||||
-rw-r--r-- | runtime/common_throws.h | 3 | ||||
-rw-r--r-- | runtime/entrypoints/quick/quick_field_entrypoints.cc | 2 | ||||
-rw-r--r-- | runtime/interpreter/interpreter_common.h | 16 | ||||
-rw-r--r-- | test/201-built-in-except-detail-messages/src/Main.java | 8 |
5 files changed, 23 insertions, 18 deletions
diff --git a/runtime/common_throws.cc b/runtime/common_throws.cc index c6e7cfb5ae..17a0a8a714 100644 --- a/runtime/common_throws.cc +++ b/runtime/common_throws.cc @@ -23,6 +23,7 @@ #include "art_field-inl.h" #include "art_method-inl.h" +#include "art_method.h" #include "class_linker-inl.h" #include "debug_print.h" #include "dex/dex_file-inl.h" @@ -406,10 +407,11 @@ void ThrowNoSuchMethodError(InvokeType type, // NullPointerException -void ThrowNullPointerExceptionForFieldAccess(ArtField* field, bool is_read) { +void ThrowNullPointerExceptionForFieldAccess(ArtField* field, ArtMethod* method, bool is_read) { std::ostringstream msg; - msg << "Attempt to " << (is_read ? "read from" : "write to") - << " field '" << ArtField::PrettyField(field, true) << "' on a null object reference"; + msg << "Attempt to " << (is_read ? "read from" : "write to") << " field '" + << ArtField::PrettyField(field) << "' on a null object reference in method '" + << ArtMethod::PrettyMethod(method) << "'"; ThrowException("Ljava/lang/NullPointerException;", nullptr, msg.str().c_str()); } @@ -585,7 +587,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) { ArtField* field = Runtime::Current()->GetClassLinker()->ResolveField(instr.VRegC_22c(), method, false); Thread::Current()->ClearException(); // Resolution may fail, ignore. - ThrowNullPointerExceptionForFieldAccess(field, /* is_read= */ true); + ThrowNullPointerExceptionForFieldAccess(field, method, /* is_read= */ true); break; } case Instruction::IPUT: @@ -598,7 +600,7 @@ void ThrowNullPointerExceptionFromDexPC(bool check_address, uintptr_t addr) { ArtField* field = Runtime::Current()->GetClassLinker()->ResolveField( instr.VRegC_22c(), method, /* is_static= */ false); Thread::Current()->ClearException(); // Resolution may fail, ignore. - ThrowNullPointerExceptionForFieldAccess(field, /* is_read= */ false); + ThrowNullPointerExceptionForFieldAccess(field, method, /* is_read= */ false); break; } case Instruction::AGET: diff --git a/runtime/common_throws.h b/runtime/common_throws.h index 3a723f7f5a..843c455878 100644 --- a/runtime/common_throws.h +++ b/runtime/common_throws.h @@ -210,8 +210,7 @@ void ThrowNoSuchMethodError(InvokeType type, // NullPointerException -void ThrowNullPointerExceptionForFieldAccess(ArtField* field, - bool is_read) +void ThrowNullPointerExceptionForFieldAccess(ArtField* field, ArtMethod* method, bool is_read) REQUIRES_SHARED(Locks::mutator_lock_) COLD_ATTR; void ThrowNullPointerExceptionForMethodAccess(uint32_t method_idx, diff --git a/runtime/entrypoints/quick/quick_field_entrypoints.cc b/runtime/entrypoints/quick/quick_field_entrypoints.cc index 618f7636da..d32aa39996 100644 --- a/runtime/entrypoints/quick/quick_field_entrypoints.cc +++ b/runtime/entrypoints/quick/quick_field_entrypoints.cc @@ -85,7 +85,7 @@ ALWAYS_INLINE static inline ArtField* FindInstanceField(uint32_t field_idx, HandleWrapper<mirror::Object> h(hs.NewHandleWrapper(obj)); ArtField* field = FindFieldFromCode<type, kAccessCheck>(field_idx, referrer, self, size); if (LIKELY(field != nullptr) && UNLIKELY(h == nullptr)) { - ThrowNullPointerExceptionForFieldAccess(field, (type & FindFieldFlags::ReadBit) != 0); + ThrowNullPointerExceptionForFieldAccess(field, referrer, (type & FindFieldFlags::ReadBit) != 0); return nullptr; } return field; diff --git a/runtime/interpreter/interpreter_common.h b/runtime/interpreter/interpreter_common.h index 95e3bd521e..df18eeb124 100644 --- a/runtime/interpreter/interpreter_common.h +++ b/runtime/interpreter/interpreter_common.h @@ -393,9 +393,9 @@ ALWAYS_INLINE bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Ins uint16_t inst_data) REQUIRES_SHARED(Locks::mutator_lock_) { const bool is_static = (find_type == StaticObjectRead) || (find_type == StaticPrimitiveRead); const uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c(); - ArtField* f = - FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self, - Primitive::ComponentSize(field_type)); + ArtMethod* method = shadow_frame.GetMethod(); + ArtField* f = FindFieldFromCode<find_type, do_access_check>( + field_idx, method, self, Primitive::ComponentSize(field_type)); if (UNLIKELY(f == nullptr)) { CHECK(self->IsExceptionPending()); return false; @@ -413,7 +413,7 @@ ALWAYS_INLINE bool DoFieldGet(Thread* self, ShadowFrame& shadow_frame, const Ins } else { obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); if (UNLIKELY(obj == nullptr)) { - ThrowNullPointerExceptionForFieldAccess(f, true); + ThrowNullPointerExceptionForFieldAccess(f, method, true); return false; } } @@ -492,9 +492,9 @@ ALWAYS_INLINE bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, const bool do_assignability_check = do_access_check; bool is_static = (find_type == StaticObjectWrite) || (find_type == StaticPrimitiveWrite); uint32_t field_idx = is_static ? inst->VRegB_21c() : inst->VRegC_22c(); - ArtField* f = - FindFieldFromCode<find_type, do_access_check>(field_idx, shadow_frame.GetMethod(), self, - Primitive::ComponentSize(field_type)); + ArtMethod* method = shadow_frame.GetMethod(); + ArtField* f = FindFieldFromCode<find_type, do_access_check>( + field_idx, method, self, Primitive::ComponentSize(field_type)); if (UNLIKELY(f == nullptr)) { CHECK(self->IsExceptionPending()); return false; @@ -505,7 +505,7 @@ ALWAYS_INLINE bool DoFieldPut(Thread* self, const ShadowFrame& shadow_frame, } else { obj = shadow_frame.GetVRegReference(inst->VRegB_22c(inst_data)); if (UNLIKELY(obj == nullptr)) { - ThrowNullPointerExceptionForFieldAccess(f, false); + ThrowNullPointerExceptionForFieldAccess(f, method, false); return false; } } diff --git a/test/201-built-in-except-detail-messages/src/Main.java b/test/201-built-in-except-detail-messages/src/Main.java index 9fc47f6409..edc8baab31 100644 --- a/test/201-built-in-except-detail-messages/src/Main.java +++ b/test/201-built-in-except-detail-messages/src/Main.java @@ -311,7 +311,9 @@ public class Main { int i = a.i; fail(); } catch (NullPointerException ex) { - assertEquals("Attempt to read from field 'int A.i' on a null object reference", ex.getMessage()); + assertEquals( + "Attempt to read from field 'int A.i' on a null object reference in method 'void Main.nullPointers()'", + ex.getMessage()); } // Write field. @@ -320,7 +322,9 @@ public class Main { a.i = 1; fail(); } catch (NullPointerException ex) { - assertEquals("Attempt to write to field 'int A.i' on a null object reference", ex.getMessage()); + assertEquals( + "Attempt to write to field 'int A.i' on a null object reference in method 'void Main.nullPointers()'", + ex.getMessage()); } // Read array. |