diff options
-rw-r--r-- | src/runtime_support.cc | 79 | ||||
-rw-r--r-- | src/runtime_support_common.h | 5 | ||||
-rw-r--r-- | test/034-call-null/expected.txt | 2 | ||||
-rw-r--r-- | test/038-inner-null/expected.txt | 2 |
4 files changed, 79 insertions, 9 deletions
diff --git a/src/runtime_support.cc b/src/runtime_support.cc index f5edebf12a..2ecb02e37b 100644 --- a/src/runtime_support.cc +++ b/src/runtime_support.cc @@ -108,10 +108,81 @@ extern "C" void artDeliverPendingExceptionFromCode(Thread* thread, Method** sp) } // Called by generated call to throw a NPE exception -extern "C" void artThrowNullPointerExceptionFromCode(Thread* thread, Method** sp) { - FinishCalleeSaveFrameSetup(thread, sp, Runtime::kSaveAll); - thread->ThrowNewException("Ljava/lang/NullPointerException;", NULL); - thread->DeliverException(); +extern "C" void artThrowNullPointerExceptionFromCode(Thread* self, Method** sp) { + FinishCalleeSaveFrameSetup(self, sp, Runtime::kSaveAll); + Frame fr = self->GetTopOfStack(); + uintptr_t throw_native_pc = fr.GetReturnPC(); + fr.Next(); + Method* throw_method = fr.GetMethod(); + uint32_t dex_pc = throw_method->ToDexPC(throw_native_pc - 2); + const DexFile::CodeItem* code = MethodHelper(throw_method).GetCodeItem(); + CHECK_LT(dex_pc, code->insns_size_in_code_units_); + const Instruction* instr = Instruction::At(&code->insns_[dex_pc]); + DecodedInstruction dec_insn(instr); + switch (instr->Opcode()) { + case Instruction::INVOKE_DIRECT: + case Instruction::INVOKE_DIRECT_RANGE: + ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kDirect); + break; + case Instruction::INVOKE_VIRTUAL: + case Instruction::INVOKE_VIRTUAL_RANGE: + ThrowNullPointerExceptionForMethodAccess(self, throw_method, dec_insn.vB, kVirtual); + break; + case Instruction::IGET: + case Instruction::IGET_WIDE: + case Instruction::IGET_OBJECT: + case Instruction::IGET_BOOLEAN: + case Instruction::IGET_BYTE: + case Instruction::IGET_CHAR: + case Instruction::IGET_SHORT: { + Field* field = + Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false); + ThrowNullPointerExceptionForFieldAccess(self, field, true /* read */); + break; + } + case Instruction::IPUT: + case Instruction::IPUT_WIDE: + case Instruction::IPUT_OBJECT: + case Instruction::IPUT_BOOLEAN: + case Instruction::IPUT_BYTE: + case Instruction::IPUT_CHAR: + case Instruction::IPUT_SHORT: { + Field* field = + Runtime::Current()->GetClassLinker()->ResolveField(dec_insn.vC, throw_method, false); + ThrowNullPointerExceptionForFieldAccess(self, field, false /* write */); + break; + } + case Instruction::AGET: + case Instruction::AGET_WIDE: + case Instruction::AGET_OBJECT: + case Instruction::AGET_BOOLEAN: + case Instruction::AGET_BYTE: + case Instruction::AGET_CHAR: + case Instruction::AGET_SHORT: + self->ThrowNewException("Ljava/lang/NullPointerException;", + "Attempt to read from null array"); + break; + case Instruction::APUT: + case Instruction::APUT_WIDE: + case Instruction::APUT_OBJECT: + case Instruction::APUT_BOOLEAN: + case Instruction::APUT_BYTE: + case Instruction::APUT_CHAR: + case Instruction::APUT_SHORT: + self->ThrowNewException("Ljava/lang/NullPointerException;", + "Attempt to write to null array"); + break; + default: { + const DexFile& dex_file = Runtime::Current()->GetClassLinker() + ->FindDexFile(throw_method->GetDeclaringClass()->GetDexCache()); + std::string message("Null pointer exception during instruction '"); + message += instr->DumpString(&dex_file); + message += "'"; + self->ThrowNewException("Ljava/lang/NullPointerException;", message.c_str()); + break; + } + } + self->DeliverException(); } // Called by generated call to throw an arithmetic divide by zero exception diff --git a/src/runtime_support_common.h b/src/runtime_support_common.h index 8ef9d93657..c5121a99fe 100644 --- a/src/runtime_support_common.h +++ b/src/runtime_support_common.h @@ -104,10 +104,9 @@ static inline void ThrowNullPointerExceptionForMethodAccess(Thread* self, std::ostringstream type_stream; type_stream << type; self->ThrowNewExceptionF("Ljava/lang/NullPointerException;", - "Attempt to invoke %s method '%s' from '%s' on a null object reference", + "Attempt to invoke %s method '%s' on a null object reference", type_stream.str().c_str(), - PrettyMethod(method_idx, dex_file, true).c_str(), - PrettyMethod(caller).c_str()); + PrettyMethod(method_idx, dex_file, true).c_str()); } // Given the context of a calling Method, use its DexCache to resolve a type to a Class. If it diff --git a/test/034-call-null/expected.txt b/test/034-call-null/expected.txt index 582b35e10d..7ed221575a 100644 --- a/test/034-call-null/expected.txt +++ b/test/034-call-null/expected.txt @@ -1,2 +1,2 @@ -java.lang.NullPointerException +java.lang.NullPointerException: Attempt to invoke direct method 'Main.doStuff()V' on a null object reference at Main.main(Main.java:26) diff --git a/test/038-inner-null/expected.txt b/test/038-inner-null/expected.txt index d3aab89c7f..37f984c295 100644 --- a/test/038-inner-null/expected.txt +++ b/test/038-inner-null/expected.txt @@ -1,4 +1,4 @@ new Special() -java.lang.NullPointerException +java.lang.NullPointerException: Attempt to invoke virtual method 'Main$Blort.repaint()V' on a null object reference at Main$Special.callInner(Main.java:31) at Main.main(Main.java:20) |