Skip to content

Commit 345ad00

Browse files
committed
Handle empty state explicitly
1 parent 7e77ccb commit 345ad00

File tree

3 files changed

+58
-21
lines changed

3 files changed

+58
-21
lines changed

bolt/lib/Passes/PAuthGadgetScanner.cpp

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -184,26 +184,30 @@ struct State {
184184
/// only use register `X30`, and therefore, this vector will probably have
185185
/// length 1 in the second run.
186186
std::vector<SmallPtrSet<const MCInst *, 4>> LastInstWritingReg;
187+
188+
/// Construct an empty state.
187189
State() {}
190+
188191
State(unsigned NumRegs, unsigned NumRegsToTrack)
189192
: SafeToDerefRegs(NumRegs), LastInstWritingReg(NumRegsToTrack) {}
190193

191-
/// Returns S, so that S.merge(S1) == S1.merge(S) == S1.
192-
static State getMergeNeutralElement(unsigned NumRegs,
193-
unsigned NumRegsToTrack) {
194-
State S(NumRegs, NumRegsToTrack);
195-
S.SafeToDerefRegs.set();
196-
return S;
197-
}
198-
199194
State &merge(const State &StateIn) {
195+
if (StateIn.empty())
196+
return *this;
197+
if (empty())
198+
return (*this = StateIn);
199+
200200
SafeToDerefRegs &= StateIn.SafeToDerefRegs;
201201
for (unsigned I = 0; I < LastInstWritingReg.size(); ++I)
202202
for (const MCInst *J : StateIn.LastInstWritingReg[I])
203203
LastInstWritingReg[I].insert(J);
204204
return *this;
205205
}
206206

207+
/// Returns true if this object does not store state of any registers -
208+
/// neither safe, nor unsafe ones.
209+
bool empty() const { return SafeToDerefRegs.empty(); }
210+
207211
bool operator==(const State &RHS) const {
208212
return SafeToDerefRegs == RHS.SafeToDerefRegs &&
209213
LastInstWritingReg == RHS.LastInstWritingReg;
@@ -226,8 +230,12 @@ static void printLastInsts(
226230

227231
raw_ostream &operator<<(raw_ostream &OS, const State &S) {
228232
OS << "pacret-state<";
229-
OS << "SafeToDerefRegs: " << S.SafeToDerefRegs << ", ";
230-
printLastInsts(OS, S.LastInstWritingReg);
233+
if (S.empty()) {
234+
OS << "empty";
235+
} else {
236+
OS << "SafeToDerefRegs: " << S.SafeToDerefRegs << ", ";
237+
printLastInsts(OS, S.LastInstWritingReg);
238+
}
231239
OS << ">";
232240
return OS;
233241
}
@@ -244,10 +252,16 @@ class PacStatePrinter {
244252
void PacStatePrinter::print(raw_ostream &OS, const State &S) const {
245253
RegStatePrinter RegStatePrinter(BC);
246254
OS << "pacret-state<";
247-
OS << "SafeToDerefRegs: ";
248-
RegStatePrinter.print(OS, S.SafeToDerefRegs);
249-
OS << ", ";
250-
printLastInsts(OS, S.LastInstWritingReg);
255+
if (S.empty()) {
256+
assert(S.SafeToDerefRegs.empty());
257+
assert(S.LastInstWritingReg.empty());
258+
OS << "empty";
259+
} else {
260+
OS << "SafeToDerefRegs: ";
261+
RegStatePrinter.print(OS, S.SafeToDerefRegs);
262+
OS << ", ";
263+
printLastInsts(OS, S.LastInstWritingReg);
264+
}
251265
OS << ">";
252266
}
253267

@@ -295,14 +309,10 @@ class PacRetAnalysis
295309
if (BB.isEntryPoint())
296310
return createEntryState();
297311

298-
return State::getMergeNeutralElement(
299-
NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
312+
return State();
300313
}
301314

302-
State getStartingStateAtPoint(const MCInst &Point) {
303-
return State::getMergeNeutralElement(
304-
NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters());
305-
}
315+
State getStartingStateAtPoint(const MCInst &Point) { return State(); }
306316

307317
void doConfluence(State &StateOut, const State &StateIn) {
308318
PacStatePrinter P(BC);
@@ -336,6 +346,15 @@ class PacRetAnalysis
336346
dbgs() << ")\n";
337347
});
338348

349+
// If this instruction is reachable, a non-empty state will be propagated
350+
// to it from the entry basic block sooner or later. Until then, it is both
351+
// more efficient and easier to reason about to skip computeNext().
352+
if (Cur.empty()) {
353+
LLVM_DEBUG(
354+
{ dbgs() << "Skipping computeNext(Point, Cur) as Cur is empty.\n"; });
355+
return State();
356+
}
357+
339358
State Next = Cur;
340359
BitVector Clobbered(NumRegs, false);
341360
// Assume a call can clobber all registers, including callee-saved
@@ -452,6 +471,14 @@ Analysis::findGadgets(BinaryFunction &BF,
452471
MCInstReference Inst(&BB, I);
453472
const State &S = *PRA.getStateAt(Inst);
454473

474+
// If non-empty state was never propagated from the entry basic block
475+
// to Inst, assume it to be unreachable and report a warning.
476+
if (S.empty()) {
477+
Result.Diagnostics.push_back(std::make_shared<GenericReport>(
478+
Inst, "Warning: unreachable instruction found"));
479+
continue;
480+
}
481+
455482
if (auto Report = shouldReportReturnGadget(BC, Inst, S))
456483
Result.Diagnostics.push_back(Report);
457484
}

bolt/test/binary-analysis/AArch64/gs-pacret-autiasp.s

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -227,6 +227,16 @@ f_callclobbered_calleesaved:
227227
ret x19
228228
.size f_callclobbered_calleesaved, .-f_callclobbered_calleesaved
229229

230+
.globl f_unreachable_instruction
231+
.type f_unreachable_instruction,@function
232+
f_unreachable_instruction:
233+
// CHECK-LABEL: GS-PAUTH: Warning: unreachable instruction found in function f_unreachable_instruction, basic block {{[0-9a-zA-Z.]+}}, at address
234+
// CHECK-NEXT: The instruction is {{[0-9a-f]+}}: add x0, x1, x2
235+
b 1f
236+
add x0, x1, x2
237+
1:
238+
ret
239+
.size f_unreachable_instruction, .-f_unreachable_instruction
230240

231241
/// Now do a basic sanity check on every different Authentication instruction:
232242

bolt/test/binary-analysis/AArch64/gs-pauth-debug-output.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ simple:
4545
// CHECK-NEXT: PacRetAnalysis::ComputeNext( b [[BB1]], pacret-state<SafeToDerefRegs: , Insts: >)
4646
// CHECK-NEXT: .. result: (pacret-state<SafeToDerefRegs: , Insts: >)
4747
// CHECK-NEXT: PacRetAnalysis::Confluence(
48-
// CHECK-NEXT: State 1: pacret-state<SafeToDerefRegs: (all), Insts: >
48+
// CHECK-NEXT: State 1: pacret-state<empty>
4949
// CHECK-NEXT: State 2: pacret-state<SafeToDerefRegs: , Insts: >)
5050
// CHECK-NEXT: merged state: pacret-state<SafeToDerefRegs: , Insts: >
5151
// CHECK-NEXT: PacRetAnalysis::ComputeNext( hint #29, pacret-state<SafeToDerefRegs: , Insts: >)

0 commit comments

Comments
 (0)