Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(1237)

Unified Diff: src/IceTargetLoweringX86BaseImpl.h

Issue 1338633005: Subzero: Add a flag to mock up bounds checking on unsafe references. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Fix comment Created 5 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « src/IceTargetLoweringX86Base.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/IceTargetLoweringX86BaseImpl.h
diff --git a/src/IceTargetLoweringX86BaseImpl.h b/src/IceTargetLoweringX86BaseImpl.h
index 99a1aeb2a8080cbf0885681a8848e190e8bbf6f0..c8bf29fad9370efce845beda24f9d1d3e7452f79 100644
--- a/src/IceTargetLoweringX86BaseImpl.h
+++ b/src/IceTargetLoweringX86BaseImpl.h
@@ -4066,14 +4066,16 @@ inline void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base,
if (Func->getVMetadata()->isMultiBlock(Base) /* || Base->getUseCount() > 1*/)
return;
+ const bool MockBounds = Func->getContext()->getFlags().getMockBoundsCheck();
const VariablesMetadata *VMetadata = Func->getVMetadata();
bool Continue = true;
while (Continue) {
const Inst *Reason = nullptr;
if (matchTransitiveAssign(VMetadata, Base, Reason) ||
matchTransitiveAssign(VMetadata, Index, Reason) ||
- matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason) ||
- matchShiftedIndex(VMetadata, Index, Shift, Reason) ||
+ (!MockBounds &&
+ matchCombinedBaseIndex(VMetadata, Base, Index, Shift, Reason)) ||
+ (!MockBounds && matchShiftedIndex(VMetadata, Index, Shift, Reason)) ||
matchOffsetBase(VMetadata, Base, Offset, Reason)) {
dumpAddressOpt(Func, Base, Index, Shift, Offset, Reason);
} else {
@@ -4104,6 +4106,65 @@ inline void computeAddressOpt(Cfg *Func, const Inst *Instr, Variable *&Base,
}
}
+/// Add a mock bounds check on the memory address before using it as a load or
+/// store operand. The basic idea is that given a memory operand [reg], we
+/// would first add bounds-check code something like:
+///
+/// cmp reg, <lb>
+/// jl out_of_line_error
+/// cmp reg, <ub>
+/// jg out_of_line_error
+///
+/// In reality, the specific code will depend on how <lb> and <ub> are
+/// represented, e.g. an immediate, a global, or a function argument.
+///
+/// As such, we need to enforce that the memory operand does not have the form
+/// [reg1+reg2], because then there is no simple cmp instruction that would
+/// suffice. However, we consider [reg+offset] to be OK because the offset is
+/// usually small, and so <ub> could have a safety buffer built in and then we
+/// could instead branch to a custom out_of_line_error that does the precise
+/// check and jumps back if it turns out OK.
+///
+/// For the purpose of mocking the bounds check, we'll do something like this:
+///
+/// cmp reg, 0
+/// je label
+/// cmp reg, 1
+/// je label
+/// label:
+///
+/// Also note that we don't need to add a bounds check to a dereference of a
+/// simple global variable address.
+template <class Machine>
+void TargetX86Base<Machine>::doMockBoundsCheck(Operand *Opnd) {
+ if (!Ctx->getFlags().getMockBoundsCheck())
+ return;
+ if (auto *Mem = llvm::dyn_cast<typename Traits::X86OperandMem>(Opnd)) {
+ if (Mem->getIndex()) {
+ llvm::report_fatal_error("doMockBoundsCheck: Opnd contains index reg");
+ }
+ Opnd = Mem->getBase();
+ }
+ // At this point Opnd could be nullptr, or Variable, or Constant, or perhaps
+ // something else. We only care if it is Variable.
+ auto *Var = llvm::dyn_cast_or_null<Variable>(Opnd);
+ if (Var == nullptr)
+ return;
+ // We use lowerStore() to copy out-args onto the stack. This creates a memory
+ // operand with the stack pointer as the base register. Don't do bounds
+ // checks on that.
+ if (Var->getRegNum() == Traits::RegisterSet::Reg_esp)
+ return;
+
+ typename Traits::Insts::Label *Label =
+ Traits::Insts::Label::create(Func, this);
+ _cmp(Opnd, Ctx->getConstantZero(IceType_i32));
+ _br(Traits::Cond::Br_e, Label);
+ _cmp(Opnd, Ctx->getConstantInt32(1));
+ _br(Traits::Cond::Br_e, Label);
+ Context.insert(Label);
+}
+
template <class Machine>
void TargetX86Base<Machine>::lowerLoad(const InstLoad *Load) {
// A Load instruction can be treated the same as an Assign instruction, after
@@ -4114,6 +4175,7 @@ void TargetX86Base<Machine>::lowerLoad(const InstLoad *Load) {
Variable *DestLoad = Load->getDest();
Type Ty = DestLoad->getType();
Operand *Src0 = formMemoryOperand(Load->getSourceAddress(), Ty);
+ doMockBoundsCheck(Src0);
InstAssign *Assign = InstAssign::create(Func, DestLoad, Src0);
lowerAssign(Assign);
}
@@ -4307,6 +4369,7 @@ void TargetX86Base<Machine>::lowerStore(const InstStore *Inst) {
Operand *Addr = Inst->getAddr();
typename Traits::X86OperandMem *NewAddr =
formMemoryOperand(Addr, Value->getType());
+ doMockBoundsCheck(NewAddr);
Type Ty = NewAddr->getType();
if (!Traits::Is64Bit && Ty == IceType_i64) {
@@ -4661,6 +4724,7 @@ void TargetX86Base<Machine>::lowerRMW(
Operand *Src = RMW->getData();
Type Ty = Src->getType();
typename Traits::X86OperandMem *Addr = formMemoryOperand(RMW->getAddr(), Ty);
+ doMockBoundsCheck(Addr);
if (!Traits::Is64Bit && Ty == IceType_i64) {
Src = legalizeUndef(Src);
Operand *SrcLo = legalize(loOperand(Src), Legal_Reg | Legal_Imm);
« no previous file with comments | « src/IceTargetLoweringX86Base.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698