Skip to content

Commit 053d734

Browse files
committed
MachineVerifier: Check stack protector is top-most in frame
Mitigate against potential bugs that might place it elsewhere and render the mechanism useless.
1 parent b7c4cb6 commit 053d734

File tree

2 files changed

+116
-1
lines changed

2 files changed

+116
-1
lines changed

llvm/lib/CodeGen/MachineVerifier.cpp

Lines changed: 53 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,51 @@ 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+
unsigned FI = MFI.getStackProtectorIndex();
4058+
int64_t SPStart = MFI.getObjectOffset(FI);
4059+
int64_t SPEnd = SPStart + MFI.getObjectSize(FI);
4060+
for (unsigned I = 0, E = MFI.getObjectIndexEnd(); I != E; ++I) {
4061+
if (I == FI)
4062+
continue;
4063+
if (MFI.isDeadObjectIndex(I))
4064+
continue;
4065+
// FIXME: Skip non-default stack objects, as some targets may place them
4066+
// above the stack protector. This is a workaround for the fact that
4067+
// backends such as AArch64 may place SVE stack objects *above* the stack
4068+
// protector.
4069+
if (MFI.getStackID(I) != TargetStackID::Default)
4070+
continue;
4071+
// Skip variable-sized objects because they do not have a fixed offset.
4072+
if (MFI.isVariableSizedObjectIndex(I))
4073+
continue;
4074+
// FIXME: Skip spill slots which may be allocated above the stack protector.
4075+
// Ideally this would only skip callee-saved registers, but we don't have
4076+
// that information here. For example, spill-slots used for scavenging are
4077+
// not described in CalleeSavedInfo.
4078+
if (MFI.isSpillSlotObjectIndex(I))
4079+
continue;
4080+
int64_t ObjStart = MFI.getObjectOffset(I);
4081+
int64_t ObjEnd = ObjStart + MFI.getObjectSize(I);
4082+
if (SPStart < ObjEnd && ObjStart < SPEnd) {
4083+
report("Stack protector overlaps with another stack object", MF);
4084+
break;
4085+
}
4086+
if ((StackGrowsDown && SPStart <= ObjStart) ||
4087+
(!StackGrowsDown && SPStart >= ObjStart)) {
4088+
report("Stack protector is not the top-most object on the stack", MF);
4089+
break;
4090+
}
4091+
}
4092+
}
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)