Skip to content

Commit 3b11cbd

Browse files
authored
Merge pull request #1305 from adrian-prantl/60926115
Fix UB in EmulateInstructionARM64.cpp
2 parents d08d94b + dba03f9 commit 3b11cbd

File tree

5 files changed

+100
-19
lines changed

5 files changed

+100
-19
lines changed

lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.cpp

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,6 @@
88

99
#include "EmulateInstructionARM64.h"
1010

11-
#include <stdlib.h>
12-
1311
#include "lldb/Core/Address.h"
1412
#include "lldb/Core/PluginManager.h"
1513
#include "lldb/Symbol/UnwindPlan.h"
@@ -18,10 +16,14 @@
1816
#include "lldb/Utility/RegisterValue.h"
1917
#include "lldb/Utility/Stream.h"
2018

19+
#include "llvm/Support/CheckedArithmetic.h"
20+
2121
#include "Plugins/Process/Utility/ARMDefines.h"
2222
#include "Plugins/Process/Utility/ARMUtils.h"
2323
#include "Plugins/Process/Utility/lldb-arm64-register-enums.h"
2424

25+
#include <cstdlib>
26+
2527
#define GPR_OFFSET(idx) ((idx)*8)
2628
#define GPR_OFFSET_NAME(reg) 0
2729
#define FPU_OFFSET(idx) ((idx)*16)
@@ -83,23 +85,6 @@ static inline uint64_t LSL(uint64_t x, integer shift) {
8385
return x << shift;
8486
}
8587

86-
// AddWithCarry()
87-
// ===============
88-
static inline uint64_t
89-
AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in,
90-
EmulateInstructionARM64::ProcState &proc_state) {
91-
uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
92-
int64_t signed_sum = SInt(x) + SInt(y) + UInt(carry_in);
93-
uint64_t result = unsigned_sum;
94-
if (N < 64)
95-
result = Bits64(result, N - 1, 0);
96-
proc_state.N = Bit64(result, N - 1);
97-
proc_state.Z = IsZero(result);
98-
proc_state.C = UInt(result) == unsigned_sum;
99-
proc_state.V = SInt(result) == signed_sum;
100-
return result;
101-
}
102-
10388
// ConstrainUnpredictable()
10489
// ========================
10590

@@ -588,6 +573,24 @@ bool EmulateInstructionARM64::ConditionHolds(const uint32_t cond) {
588573
return result;
589574
}
590575

576+
uint64_t EmulateInstructionARM64::
577+
AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bit carry_in,
578+
EmulateInstructionARM64::ProcState &proc_state) {
579+
uint64_t unsigned_sum = UInt(x) + UInt(y) + UInt(carry_in);
580+
llvm::Optional<int64_t> signed_sum = llvm::checkedAdd(SInt(x), SInt(y));
581+
bool overflow = !signed_sum;
582+
if (!overflow)
583+
overflow |= !llvm::checkedAdd(*signed_sum, SInt(carry_in));
584+
uint64_t result = unsigned_sum;
585+
if (N < 64)
586+
result = Bits64(result, N - 1, 0);
587+
proc_state.N = Bit64(result, N - 1);
588+
proc_state.Z = IsZero(result);
589+
proc_state.C = UInt(result) != unsigned_sum;
590+
proc_state.V = overflow;
591+
return result;
592+
}
593+
591594
bool EmulateInstructionARM64::EmulateADDSUBImm(const uint32_t opcode) {
592595
// integer d = UInt(Rd);
593596
// integer n = UInt(Rn);

lldb/source/Plugins/Instruction/ARM64/EmulateInstructionARM64.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,6 +152,9 @@ class EmulateInstructionARM64 : public lldb_private::EmulateInstruction {
152152
} ProcState;
153153

154154
protected:
155+
static uint64_t AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bool carry_in,
156+
EmulateInstructionARM64::ProcState &proc_state);
157+
155158
typedef struct {
156159
uint32_t mask;
157160
uint32_t value;

lldb/unittests/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ add_subdirectory(Editline)
6767
add_subdirectory(Expression)
6868
add_subdirectory(Host)
6969
add_subdirectory(Interpreter)
70+
add_subdirectory(Instruction)
7071
add_subdirectory(Language)
7172
add_subdirectory(ObjectFile)
7273
add_subdirectory(Platform)
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
if("ARM" IN_LIST LLVM_TARGETS_TO_BUILD)
2+
add_lldb_unittest(EmulatorTests
3+
TestAArch64Emulator.cpp
4+
LINK_LIBS
5+
lldbCore
6+
lldbSymbol
7+
lldbTarget
8+
lldbPluginInstructionARM64
9+
LINK_COMPONENTS
10+
Support
11+
${LLVM_TARGETS_TO_BUILD})
12+
endif()
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
//===-- TestAArch64Emulator.cpp ------------------------------------------===//
2+
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
10+
#include "gtest/gtest.h"
11+
12+
#include "lldb/Core/Address.h"
13+
#include "lldb/Core/Disassembler.h"
14+
#include "lldb/Target/ExecutionContext.h"
15+
#include "lldb/Utility/ArchSpec.h"
16+
17+
#include "Plugins/Instruction/ARM64/EmulateInstructionARM64.h"
18+
19+
using namespace lldb;
20+
using namespace lldb_private;
21+
22+
struct Arch64EmulatorTester : public EmulateInstructionARM64 {
23+
Arch64EmulatorTester()
24+
: EmulateInstructionARM64(ArchSpec("arm64-apple-ios")) {}
25+
26+
static uint64_t AddWithCarry(uint32_t N, uint64_t x, uint64_t y, bool carry_in,
27+
EmulateInstructionARM64::ProcState &proc_state) {
28+
return EmulateInstructionARM64::AddWithCarry(N, x, y, carry_in, proc_state);
29+
}
30+
};
31+
32+
class TestAArch64Emulator : public testing::Test {
33+
public:
34+
static void SetUpTestCase();
35+
static void TearDownTestCase();
36+
37+
protected:
38+
};
39+
40+
void TestAArch64Emulator::SetUpTestCase() {
41+
EmulateInstructionARM64::Initialize();
42+
}
43+
44+
void TestAArch64Emulator::TearDownTestCase() {
45+
EmulateInstructionARM64::Terminate();
46+
}
47+
48+
TEST_F(TestAArch64Emulator, TestOverflow) {
49+
EmulateInstructionARM64::ProcState pstate;
50+
memset(&pstate, 0, sizeof(pstate));
51+
uint64_t ll_max = std::numeric_limits<int64_t>::max();
52+
Arch64EmulatorTester emu;
53+
ASSERT_EQ(emu.AddWithCarry(64, ll_max, 0, 0, pstate), ll_max);
54+
ASSERT_EQ(pstate.V, 0ULL);
55+
ASSERT_EQ(pstate.C, 0ULL);
56+
ASSERT_EQ(emu.AddWithCarry(64, ll_max, 1, 0, pstate), (uint64_t)(ll_max + 1));
57+
ASSERT_EQ(pstate.V, 1ULL);
58+
ASSERT_EQ(pstate.C, 0ULL);
59+
ASSERT_EQ(emu.AddWithCarry(64, ll_max, 0, 1, pstate), (uint64_t)(ll_max + 1));
60+
ASSERT_EQ(pstate.V, 1ULL);
61+
ASSERT_EQ(pstate.C, 0ULL);
62+
}

0 commit comments

Comments
 (0)