diff options
author | Calder Kitagawa <ckitagawa@chromium.org> | 2018-07-04 20:44:27 +0000 |
---|---|---|
committer | Copybara-Service <copybara-worker@google.com> | 2021-07-25 20:07:32 -0700 |
commit | 40a74cc5a9ef13950080571497f8b0e3b36d6599 (patch) | |
tree | 757aa862ad5a3436c0f9ae14b70476de03174d9f /disassembler_dex.cc | |
parent | cd8becf50509b9846b9baf3a5b8239eb6dfe4f4f (diff) | |
download | zucchini-40a74cc5a9ef13950080571497f8b0e3b36d6599.tar.gz |
[Zucchini] Enforce valid casts on Rel codes
The MakeWriteRelCodeXX used base::checked_cast which results in a
crash. To fail gracefully we instead use base::CheckedNumeric.
The appearance of this bug results from the input files being bad
resulting in the output from gen also being bad which then propagates
to the apply step.
Bug: 860128
Change-Id: I38fc91b0a1495ce0c337d778fb51cfe56537e766
Reviewed-on: https://chromium-review.googlesource.com/1126178
Reviewed-by: Samuel Huang <huangs@chromium.org>
Commit-Queue: Calder Kitagawa <ckitagawa@chromium.org>
Cr-Commit-Position: refs/heads/master@{#572648}
NOKEYCHECK=True
GitOrigin-RevId: 2d78c3c15a71b517d3ef226010f1cfc4b13e5ea1
Diffstat (limited to 'disassembler_dex.cc')
-rw-r--r-- | disassembler_dex.cc | 43 |
1 files changed, 31 insertions, 12 deletions
diff --git a/disassembler_dex.cc b/disassembler_dex.cc index 01d5e98..8a1b339 100644 --- a/disassembler_dex.cc +++ b/disassembler_dex.cc @@ -1446,12 +1446,17 @@ std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteMethodId32( std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode8( MutableBufferView image) { auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) { - ptrdiff_t byte_diff = static_cast<ptrdiff_t>(ref.target) - ref.location; - DCHECK_EQ(0, byte_diff % kInstrUnitSize); + ptrdiff_t unsafe_byte_diff = + static_cast<ptrdiff_t>(ref.target) - ref.location; + DCHECK_EQ(0, unsafe_byte_diff % kInstrUnitSize); // |delta| is relative to start of instruction, which is 1 unit before // |ref.location|. The subtraction above removed too much, so +1 to fix. - ptrdiff_t delta = (byte_diff / kInstrUnitSize) + 1; - image.write<int8_t>(ref.location, base::checked_cast<int8_t>(delta)); + base::CheckedNumeric<int8_t> delta((unsafe_byte_diff / kInstrUnitSize) + 1); + if (!delta.IsValid()) { + LOG(ERROR) << "Invalid reference at: " << AsHex<8>(ref.location); + return; + } + image.write<int8_t>(ref.location, delta.ValueOrDie()); }); return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer)); } @@ -1459,12 +1464,18 @@ std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode8( std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode16( MutableBufferView image) { auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) { - ptrdiff_t byte_diff = static_cast<ptrdiff_t>(ref.target) - ref.location; - DCHECK_EQ(0, byte_diff % kInstrUnitSize); + ptrdiff_t unsafe_byte_diff = + static_cast<ptrdiff_t>(ref.target) - ref.location; + DCHECK_EQ(0, unsafe_byte_diff % kInstrUnitSize); // |delta| is relative to start of instruction, which is 1 unit before // |ref.location|. The subtraction above removed too much, so +1 to fix. - ptrdiff_t delta = (byte_diff / kInstrUnitSize) + 1; - image.write<int16_t>(ref.location, base::checked_cast<int16_t>(delta)); + base::CheckedNumeric<int16_t> delta((unsafe_byte_diff / kInstrUnitSize) + + 1); + if (!delta.IsValid()) { + LOG(ERROR) << "Invalid reference at: " << AsHex<8>(ref.location); + return; + } + image.write<int16_t>(ref.location, delta.ValueOrDie()); }); return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer)); } @@ -1472,10 +1483,18 @@ std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode16( std::unique_ptr<ReferenceWriter> DisassemblerDex::MakeWriteRelCode32( MutableBufferView image) { auto writer = base::BindRepeating([](Reference ref, MutableBufferView image) { - ptrdiff_t byte_diff = static_cast<ptrdiff_t>(ref.target) - ref.location; - DCHECK_EQ(0, byte_diff % kInstrUnitSize); - ptrdiff_t delta = (byte_diff / kInstrUnitSize) + 1; - image.write<int32_t>(ref.location, base::checked_cast<int32_t>(delta)); + ptrdiff_t unsafe_byte_diff = + static_cast<ptrdiff_t>(ref.target) - ref.location; + DCHECK_EQ(0, unsafe_byte_diff % kInstrUnitSize); + // |delta| is relative to start of instruction, which is 1 unit before + // |ref.location|. The subtraction above removed too much, so +1 to fix. + base::CheckedNumeric<int32_t> delta((unsafe_byte_diff / kInstrUnitSize) + + 1); + if (!delta.IsValid()) { + LOG(ERROR) << "Invalid reference at: " << AsHex<8>(ref.location); + return; + } + image.write<int32_t>(ref.location, delta.ValueOrDie()); }); return std::make_unique<ReferenceWriterAdaptor>(image, std::move(writer)); } |