@@ -184,26 +184,30 @@ struct State {
184
184
// / only use register `X30`, and therefore, this vector will probably have
185
185
// / length 1 in the second run.
186
186
std::vector<SmallPtrSet<const MCInst *, 4 >> LastInstWritingReg;
187
+
188
+ // / Construct an empty state.
187
189
State () {}
190
+
188
191
State (unsigned NumRegs, unsigned NumRegsToTrack)
189
192
: SafeToDerefRegs(NumRegs), LastInstWritingReg(NumRegsToTrack) {}
190
193
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
-
199
194
State &merge (const State &StateIn) {
195
+ if (StateIn.empty ())
196
+ return *this ;
197
+ if (empty ())
198
+ return (*this = StateIn);
199
+
200
200
SafeToDerefRegs &= StateIn.SafeToDerefRegs ;
201
201
for (unsigned I = 0 ; I < LastInstWritingReg.size (); ++I)
202
202
for (const MCInst *J : StateIn.LastInstWritingReg [I])
203
203
LastInstWritingReg[I].insert (J);
204
204
return *this ;
205
205
}
206
206
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
+
207
211
bool operator ==(const State &RHS) const {
208
212
return SafeToDerefRegs == RHS.SafeToDerefRegs &&
209
213
LastInstWritingReg == RHS.LastInstWritingReg ;
@@ -226,8 +230,12 @@ static void printLastInsts(
226
230
227
231
raw_ostream &operator <<(raw_ostream &OS, const State &S) {
228
232
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
+ }
231
239
OS << " >" ;
232
240
return OS;
233
241
}
@@ -244,10 +252,16 @@ class PacStatePrinter {
244
252
void PacStatePrinter::print (raw_ostream &OS, const State &S) const {
245
253
RegStatePrinter RegStatePrinter (BC);
246
254
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
+ }
251
265
OS << " >" ;
252
266
}
253
267
@@ -295,14 +309,10 @@ class PacRetAnalysis
295
309
if (BB.isEntryPoint ())
296
310
return createEntryState ();
297
311
298
- return State::getMergeNeutralElement (
299
- NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters ());
312
+ return State ();
300
313
}
301
314
302
- State getStartingStateAtPoint (const MCInst &Point) {
303
- return State::getMergeNeutralElement (
304
- NumRegs, RegsToTrackInstsFor.getNumTrackedRegisters ());
305
- }
315
+ State getStartingStateAtPoint (const MCInst &Point) { return State (); }
306
316
307
317
void doConfluence (State &StateOut, const State &StateIn) {
308
318
PacStatePrinter P (BC);
@@ -336,6 +346,15 @@ class PacRetAnalysis
336
346
dbgs () << " )\n " ;
337
347
});
338
348
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
+
339
358
State Next = Cur;
340
359
BitVector Clobbered (NumRegs, false );
341
360
// Assume a call can clobber all registers, including callee-saved
@@ -452,6 +471,14 @@ Analysis::findGadgets(BinaryFunction &BF,
452
471
MCInstReference Inst (&BB, I);
453
472
const State &S = *PRA.getStateAt (Inst);
454
473
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
+
455
482
if (auto Report = shouldReportReturnGadget (BC, Inst, S))
456
483
Result.Diagnostics .push_back (Report);
457
484
}
0 commit comments