Skip to content

Commit 86b1b06

Browse files
authored
MachineVerifier: Check stack protector is top-most in frame (#121481)
Somewhat paranoid, but mitigates potential bugs in the future that might place it elsewhere and render the mechanism useless.
1 parent 6504546 commit 86b1b06

File tree

2 files changed

+114
-1
lines changed

2 files changed

+114
-1
lines changed

llvm/lib/CodeGen/MachineVerifier.cpp

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -353,6 +353,8 @@ struct MachineVerifier {
353353
LaneBitmask LaneMask = LaneBitmask::getNone());
354354

355355
void verifyStackFrame();
356+
// Check that the stack protector is the top-most object in the stack.
357+
void verifyStackProtector();
356358

357359
void verifySlotIndexes() const;
358360
void verifyProperties(const MachineFunction &MF);
@@ -709,8 +711,10 @@ void MachineVerifier::visitMachineFunctionBefore() {
709711
// Check that the register use lists are sane.
710712
MRI->verifyUseLists();
711713

712-
if (!MF->empty())
714+
if (!MF->empty()) {
713715
verifyStackFrame();
716+
verifyStackProtector();
717+
}
714718
}
715719

716720
void
@@ -4038,3 +4042,49 @@ void MachineVerifier::verifyStackFrame() {
40384042
}
40394043
}
40404044
}
4045+
4046+
void MachineVerifier::verifyStackProtector() {
4047+
const MachineFrameInfo &MFI = MF->getFrameInfo();
4048+
if (!MFI.hasStackProtectorIndex())
4049+
return;
4050+
// Only applicable when the offsets of frame objects have been determined,
4051+
// which is indicated by a non-zero stack size.
4052+
if (!MFI.getStackSize())
4053+
return;
4054+
const TargetFrameLowering &TFI = *MF->getSubtarget().getFrameLowering();
4055+
bool StackGrowsDown =
4056+
TFI.getStackGrowthDirection() == TargetFrameLowering::StackGrowsDown;
4057+
// Collect the frame indices of the callee-saved registers which are spilled
4058+
// to the stack. These are the registers that are stored above the stack
4059+
// protector.
4060+
SmallSet<unsigned, 4> CalleeSavedFrameIndices;
4061+
if (MFI.isCalleeSavedInfoValid()) {
4062+
for (const CalleeSavedInfo &Info : MFI.getCalleeSavedInfo()) {
4063+
if (!Info.isSpilledToReg())
4064+
CalleeSavedFrameIndices.insert(Info.getFrameIdx());
4065+
}
4066+
}
4067+
unsigned FI = MFI.getStackProtectorIndex();
4068+
int64_t SPStart = MFI.getObjectOffset(FI);
4069+
int64_t SPEnd = SPStart + MFI.getObjectSize(FI);
4070+
for (unsigned I = 0, E = MFI.getObjectIndexEnd(); I != E; ++I) {
4071+
if (I == FI)
4072+
continue;
4073+
// Variable-sized objects do not have a fixed offset.
4074+
if (MFI.isVariableSizedObjectIndex(I))
4075+
continue;
4076+
if (CalleeSavedFrameIndices.contains(I))
4077+
continue;
4078+
int64_t ObjStart = MFI.getObjectOffset(I);
4079+
int64_t ObjEnd = ObjStart + MFI.getObjectSize(I);
4080+
if (SPStart < ObjEnd && ObjStart < SPEnd) {
4081+
report("Stack protector overlaps with another stack object", MF);
4082+
break;
4083+
}
4084+
if ((StackGrowsDown && SPStart <= ObjStart) ||
4085+
(!StackGrowsDown && SPStart >= ObjStart)) {
4086+
report("Stack protector is not the top-most object on the stack", MF);
4087+
break;
4088+
}
4089+
}
4090+
}
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
# REQUIRES: aarch64-registered-target, amdgpu-registered-target
2+
3+
# RUN: split-file %s %t
4+
5+
# RUN: llc -mtriple=aarch64 -run-pass=none -o - %t/valid.mir
6+
# RUN: not --crash llc -mtriple=aarch64 -run-pass=none -o - %t/lower.mir 2>&1 | FileCheck %t/lower.mir
7+
# RUN: not --crash llc -mtriple=aarch64 -run-pass=none -o - %t/overlap.mir 2>&1 | FileCheck %t/overlap.mir
8+
# RUN: not --crash llc -mtriple=amdgcn -run-pass=none -o - %t/higher.mir 2>&1 | FileCheck %t/higher.mir
9+
10+
;--- valid.mir
11+
---
12+
name: valid
13+
frameInfo:
14+
stackSize: 16
15+
stackProtector: '%stack.1'
16+
stack:
17+
- { id: 0, offset: -24, size: 8, alignment: 8, stack-id: default }
18+
- { id: 1, offset: -16, size: 8, alignment: 8, stack-id: default }
19+
body: |
20+
bb.0:
21+
...
22+
23+
;--- lower.mir
24+
# CHECK: *** Bad machine code: Stack protector is not the top-most object on the stack ***
25+
---
26+
name: lower
27+
frameInfo:
28+
stackSize: 16
29+
stackProtector: '%stack.1'
30+
stack:
31+
- { id: 0, offset: -16, size: 8, alignment: 8, stack-id: default }
32+
- { id: 1, offset: -24, size: 8, alignment: 8, stack-id: default }
33+
body: |
34+
bb.0:
35+
...
36+
37+
;--- overlap.mir
38+
# CHECK: *** Bad machine code: Stack protector overlaps with another stack object ***
39+
---
40+
name: overlap
41+
frameInfo:
42+
stackSize: 16
43+
stackProtector: '%stack.1'
44+
stack:
45+
- { id: 0, offset: -20, size: 8, alignment: 4, stack-id: default }
46+
- { id: 1, offset: -16, size: 8, alignment: 8, stack-id: default }
47+
body: |
48+
bb.0:
49+
...
50+
51+
;--- higher.mir
52+
# CHECK: *** Bad machine code: Stack protector is not the top-most object on the stack ***
53+
---
54+
name: higher
55+
frameInfo:
56+
stackSize: 16
57+
stackProtector: '%stack.1'
58+
stack:
59+
- { id: 0, offset: 16, size: 8, alignment: 8, stack-id: default }
60+
- { id: 1, offset: 24, size: 8, alignment: 8, stack-id: default }
61+
body: |
62+
bb.0:
63+
...

0 commit comments

Comments
 (0)