Make SafeDexInstructionIterator more robust
Make operator++ set the error state when if incrementing would go
past the end of the code region.
Added test in CodeItemOverrun.
Bug: 67104794
Test: test-art-host
Change-Id: I7b27a1ddb60aaae08ae9ed4ba8762ce2a7746770
diff --git a/dexlayout/dexlayout_test.cc b/dexlayout/dexlayout_test.cc
index cdd0219..38d3c6e 100644
--- a/dexlayout/dexlayout_test.cc
+++ b/dexlayout/dexlayout_test.cc
@@ -727,6 +727,13 @@
const_cast<Instruction*>(last_instruction.Inst())->SetOpcode(
Instruction::CONST_STRING_JUMBO);
mutated_successfully = true;
+ // Test that the safe iterator doesn't go past the end.
+ SafeDexInstructionIterator it2(instructions.begin(), instructions.end());
+ while (!it2.IsErrorState()) {
+ ++it2;
+ }
+ EXPECT_TRUE(it2 == last_instruction);
+ EXPECT_TRUE(it2 < instructions.end());
}
}
}
diff --git a/runtime/dex_instruction_iterator.h b/runtime/dex_instruction_iterator.h
index afa8d4a..9e4dea3 100644
--- a/runtime/dex_instruction_iterator.h
+++ b/runtime/dex_instruction_iterator.h
@@ -123,11 +123,16 @@
const size_t size_code_units = Inst()->CodeUnitsRequiredForSizeComputation();
const size_t available = reinterpret_cast<const uint16_t*>(end_) -
reinterpret_cast<const uint16_t*>(Inst());
- if (size_code_units > available) {
+ if (UNLIKELY(size_code_units > available)) {
error_state_ = true;
- } else {
- inst_ = inst_->Next();
+ return *this;
}
+ const size_t instruction_size = inst_->SizeInCodeUnits();
+ if (UNLIKELY(instruction_size > available)) {
+ error_state_ = true;
+ return *this;
+ }
+ inst_ = inst_->RelativeAt(instruction_size);
return *this;
}