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

Unified Diff: src/WasmTranslator.cpp

Issue 1913153003: Subzero. Wasm. Implement sbrk and correctly do bounds checks. (Closed) Base URL: https://chromium.googlesource.com/native_client/pnacl-subzero.git@master
Patch Set: Cleanup Created 4 years, 8 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
« runtime/wasm-runtime.cpp ('K') | « runtime/wasm-runtime.cpp ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: src/WasmTranslator.cpp
diff --git a/src/WasmTranslator.cpp b/src/WasmTranslator.cpp
index a3ca88d4d2ba0c68c39ec1780992ad9f8e334ba4..af37e729bd39bb53e36a32377e33799bc7c6badc 100644
--- a/src/WasmTranslator.cpp
+++ b/src/WasmTranslator.cpp
@@ -1065,9 +1065,7 @@ public:
assert(Module);
const auto &IndirectTable = Module->function_table;
- // TODO(eholk): This should probably actually call abort instead.
- auto *Abort = Func->makeNode();
- Abort->appendInst(InstUnreachable::create(Func));
+ auto *Abort = getAbortTarget();
assert(Args[0].toOperand());
@@ -1137,14 +1135,23 @@ public:
Operand *sanitizeAddress(Operand *Base, uint32_t Offset) {
SizeT MemSize = Module->module->min_mem_pages * WASM_PAGE_SIZE;
- SizeT MemMask = MemSize - 1;
bool ConstZeroBase = false;
// first, add the index and the offset together.
if (auto *ConstBase = llvm::dyn_cast<ConstantInteger32>(Base)) {
uint32_t RealOffset = Offset + ConstBase->getValue();
- RealOffset &= MemMask;
+ if (RealOffset >= MemSize) {
+ // We've proven this will always be an out of bounds access, so insert
+ // an unconditional trap.
+ Control()->appendInst(InstUnreachable::create(Func));
+ // It doesn't matter what we return here, so return something that will
+ // allow the rest of code generation to happen.
+ //
+ // We might be tempted to just abort translation here, but out of bounds
+ // memory access is a runtime trap, not a compile error.
+ return Base;
Jim Stichnoth 2016/04/22 20:48:54 Another possibility is GlobalContext::getConstantZ
Eric Holk 2016/04/22 22:32:48 Returning 0 is better. It means that even this der
+ }
Base = Ctx->getConstantInt32(RealOffset);
ConstZeroBase = (0 == RealOffset);
} else if (0 != Offset) {
@@ -1156,12 +1163,18 @@ public:
Base = Addr;
}
+ // Do the bounds check.
Jim Stichnoth 2016/04/22 20:48:54 Maybe in a separate CL, but can you add a flag to
Eric Holk 2016/04/22 22:32:48 I added a TODO.
if (!llvm::dyn_cast<ConstantInteger32>(Base)) {
- auto *ClampedAddr = makeVariable(Ice::getPointerType());
+ auto *CheckPassed = Func->makeNode();
+ auto *CheckFailed = getAbortTarget();
+
+ auto *Check = makeVariable(IceType_i1);
+ Control()->appendInst(InstIcmp::create(Func, InstIcmp::Ult, Check, Base,
+ Ctx->getConstantInt32(MemSize)));
Control()->appendInst(
- InstArithmetic::create(Func, InstArithmetic::And, ClampedAddr, Base,
- Ctx->getConstantInt32(MemSize - 1)));
- Base = ClampedAddr;
+ InstBr::create(Func, Check, CheckPassed, CheckFailed));
+
+ *ControlPtr = OperandNode(CheckPassed);
Jim Stichnoth 2016/04/22 20:48:54 This one is definitely for a separate CL. I think
Eric Holk 2016/04/22 22:32:48 I added a TODO, with a link to this comment.
}
Ice::Operand *RealAddr = nullptr;
@@ -1261,6 +1274,8 @@ private:
class Cfg *Func;
GlobalContext *Ctx;
+ CfgNode *AbortTarget = nullptr;
+
SizeT NextArg = 0;
CfgUnorderedMap<Operand *, InstPhi *> PhiMap;
@@ -1297,6 +1312,16 @@ private:
return Iter->second;
}
+ CfgNode *getAbortTarget() {
Karl 2016/04/22 19:18:14 Does this need an atomic or a mutex to avoid multi
Jim Stichnoth 2016/04/22 20:48:54 I don't think there's any concurrency at this leve
Eric Holk 2016/04/22 21:02:10 I think unless we have plans to parallelize Wasm d
+ if (!AbortTarget) {
+ AbortTarget = Func->makeNode();
Jim Stichnoth 2016/04/22 20:48:54 I think it's best if you can somehow force this no
Eric Holk 2016/04/22 22:32:48 Do you know a good strategy for doing this off han
Jim Stichnoth 2016/04/23 16:23:04 I would probably just do a post-pass that heavy-ha
+ // TODO(eholk): This should probably actually call abort instead.
+ AbortTarget->appendInst(InstUnreachable::create(Func));
+ }
+
+ return AbortTarget;
+ }
+
template <typename F = std::function<void(Ostream &)>> void log(F Fn) const {
if (BuildDefs::dump() && (getFlags().getVerbose() & IceV_Wasm)) {
Fn(Ctx->getStrDump());
@@ -1470,6 +1495,14 @@ void WasmTranslator::translate(
WritePtr += Seg.source_size;
}
+ // Save the size of the initialized data in a global variable so the runtime
+ // can use it to determine the initial heap break.
+ auto *GlobalDataSize = VariableDeclaration::createExternal(Globals.get());
+ GlobalDataSize->setName(Ctx->getGlobalString("WASM_DATA_SIZE"));
+ GlobalDataSize->addInitializer(VariableDeclaration::DataInitializer::create(
+ Globals.get(), reinterpret_cast<const char *>(&WritePtr),
+ sizeof(WritePtr)));
+
// Pad the rest with zeros
SizeT DataSize = Module->min_mem_pages * WASM_PAGE_SIZE;
if (WritePtr < DataSize) {
@@ -1477,7 +1510,16 @@ void WasmTranslator::translate(
Globals.get(), DataSize - WritePtr));
}
+ // Save the number of pages for the runtime
+ auto *GlobalNumPages = VariableDeclaration::createExternal(Globals.get());
+ GlobalNumPages->setName(Ctx->getGlobalString("WASM_NUM_PAGES"));
+ GlobalNumPages->addInitializer(VariableDeclaration::DataInitializer::create(
+ Globals.get(), reinterpret_cast<const char *>(&Module->min_mem_pages),
+ sizeof(Module->min_mem_pages)));
+
Globals->push_back(WasmMemory);
+ Globals->push_back(GlobalDataSize);
+ Globals->push_back(GlobalNumPages);
lowerGlobals(std::move(Globals));
}
« runtime/wasm-runtime.cpp ('K') | « runtime/wasm-runtime.cpp ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698