diff options
author | Jan Voung <jvoung@chromium.org> | 2013-05-07 16:01:21 -0700 |
---|---|---|
committer | Jan Voung <jvoung@chromium.org> | 2013-05-07 16:01:21 -0700 |
commit | 77cc10ffb869891e7eff5a5fa1be4437c3360cf8 (patch) | |
tree | 95e8622b2b1395289d4cf6cb410db47ba8e65afe | |
parent | a4c38e64aa4f485e3caff72dc01cb794ed99af20 (diff) |
Start a whitelist of intrinsics for the PNaCl ABI checker.
This list is currently too small to support our tests
(scons, gcc, llvm). To prevent the tests from breaking,
there is a -pnaclabi-allow-intrinsics flag which defaults
to true. To turn on the checking for real,
set -pnaclabi-allow-intrinsics=0.
We will avoid actually using the -pnaclabi-allow-intrinsics
flags in tests, and try to just stick with the
-pnacl-disable-abi-check flag. Remove this flag soon.
BUG=https://code.google.com/p/nativeclient/issues/detail?id=3378
R=eliben@chromium.org
Review URL: https://codereview.chromium.org/14670017
-rw-r--r-- | lib/Analysis/NaCl/PNaClABIVerifyModule.cpp | 86 | ||||
-rw-r--r-- | test/NaCl/PNaClABI/intrinsics.ll | 62 |
2 files changed, 148 insertions, 0 deletions
diff --git a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp index efb40cf43a..515dbbcc1e 100644 --- a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp +++ b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp @@ -17,7 +17,9 @@ #include "llvm/ADT/Twine.h" #include "llvm/Analysis/NaCl.h" #include "llvm/IR/DerivedTypes.h" +#include "llvm/IR/Intrinsics.h" #include "llvm/IR/Module.h" +#include "llvm/Support/Debug.h" #include "llvm/Support/raw_ostream.h" #include "PNaClABITypeChecker.h" @@ -28,8 +30,14 @@ cl::opt<bool> PNaClABIAllowDebugMetadata("pnaclabi-allow-debug-metadata", cl::desc("Allow debug metadata during PNaCl ABI verification."), cl::init(false)); + } +static cl::opt<bool> +PNaClABIAllowDevIntrinsics("pnaclabi-allow-dev-intrinsics", + cl::desc("Allow all LLVM intrinsics during PNaCl ABI verification."), + cl::init(true)); // TODO(jvoung): Make this false by default. + namespace { // This pass should not touch function bodies, to stay streaming-friendly class PNaClABIVerifyModule : public ModulePass { @@ -55,6 +63,7 @@ class PNaClABIVerifyModule : public ModulePass { virtual void print(raw_ostream &O, const Module *M) const; private: void CheckGlobalValueCommon(const GlobalValue *GV); + bool IsWhitelistedIntrinsic(const Function* F, unsigned ID); bool IsWhitelistedMetadata(const NamedMDNode *MD); PNaClABITypeChecker TC; PNaClABIErrorReporter *Reporter; @@ -113,6 +122,76 @@ void PNaClABIVerifyModule::CheckGlobalValueCommon(const GlobalValue *GV) { } } +bool PNaClABIVerifyModule::IsWhitelistedIntrinsic(const Function* F, + unsigned ID) { + // Keep 3 categories of intrinsics for now. + // (1) Allowed always + // (2) Never allowed + // (3) "Dev" intrinsics, which may or may not be allowed. + // "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag. + // Please keep these sorted within each category. + switch(ID) { + // Disallow by default. + default: return false; + // (1) Always allowed. + case Intrinsic::invariant_end: + case Intrinsic::invariant_start: + case Intrinsic::lifetime_end: + case Intrinsic::lifetime_start: + case Intrinsic::memcpy: + case Intrinsic::memmove: + case Intrinsic::memset: + case Intrinsic::nacl_read_tp: + case Intrinsic::trap: + return true; + + // (2) Known to be never allowed. + case Intrinsic::not_intrinsic: + case Intrinsic::adjust_trampoline: + case Intrinsic::init_trampoline: + case Intrinsic::stackprotector: + case Intrinsic::vacopy: + case Intrinsic::vaend: + case Intrinsic::vastart: + return false; + + // (3) Dev intrinsics. + case Intrinsic::dbg_declare: + case Intrinsic::dbg_value: + return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata; + case Intrinsic::bswap: // Support via compiler_rt if arch doesn't have it? + case Intrinsic::cos: // Rounding not defined: support with fast-math? + case Intrinsic::ctlz: // Support via compiler_rt if arch doesn't have it? + case Intrinsic::ctpop: // Support via compiler_rt if arch doesn't have it? + case Intrinsic::cttz: // Support via compiler_rt if arch doesn't have it? + case Intrinsic::eh_dwarf_cfa: // For EH tests. + case Intrinsic::exp: // Rounding not defined: support with fast-math? + case Intrinsic::exp2: // Rounding not defined: support with fast-math? + case Intrinsic::expect: // From __builtin_expect. + case Intrinsic::flt_rounds: + case Intrinsic::frameaddress: // Support for 0-level or not? + case Intrinsic::log: // Rounding not defined: support with fast-math? + case Intrinsic::log2: // Rounding not defined: support with fast-math? + case Intrinsic::log10: // Rounding not defined: support with fast-math? + case Intrinsic::nacl_target_arch: // Used by translator self-build. + case Intrinsic::pow: // Rounding not defined: support with fast-math? + case Intrinsic::prefetch: // Could ignore if target doesn't support? + case Intrinsic::returnaddress: // Support for 0-level or not? + case Intrinsic::sin: // Rounding not defined: support with fast-math? + case Intrinsic::sqrt: + case Intrinsic::stackrestore: // Used to support C99 VLAs. + case Intrinsic::stacksave: + // the *_with_overflow return struct types, so we'll need to fix these. + case Intrinsic::sadd_with_overflow: // Introduced by -ftrapv + case Intrinsic::ssub_with_overflow: + case Intrinsic::uadd_with_overflow: + case Intrinsic::usub_with_overflow: + case Intrinsic::smul_with_overflow: + case Intrinsic::umul_with_overflow: // Introduced by c++ new[x * y]. + return PNaClABIAllowDevIntrinsics; + } +} + bool PNaClABIVerifyModule::IsWhitelistedMetadata(const NamedMDNode* MD) { return MD->getName().startswith("llvm.dbg.") && PNaClABIAllowDebugMetadata; } @@ -153,6 +232,13 @@ bool PNaClABIVerifyModule::runOnModule(Module &M) { } for (Module::const_iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) { + // Check intrinsics. + if (MI->isIntrinsic() + && !IsWhitelistedIntrinsic(MI, MI->getIntrinsicID())) { + Reporter->addError() << "Function " << MI->getName() + << " is a disallowed LLVM intrinsic\n"; + } + // Check types of functions and their arguments FunctionType *FT = MI->getFunctionType(); if (!TC.isValidType(FT->getReturnType())) { diff --git a/test/NaCl/PNaClABI/intrinsics.ll b/test/NaCl/PNaClABI/intrinsics.ll new file mode 100644 index 0000000000..83c0c69bb5 --- /dev/null +++ b/test/NaCl/PNaClABI/intrinsics.ll @@ -0,0 +1,62 @@ +; RUN: pnacl-abicheck -pnaclabi-allow-dev-intrinsics=0 < %s | FileCheck %s +; RUN: pnacl-abicheck -pnaclabi-allow-dev-intrinsics=0 \ +; RUN: -pnaclabi-allow-debug-metadata < %s | FileCheck %s --check-prefix=DBG +; RUN: pnacl-abicheck -pnaclabi-allow-dev-intrinsics=1 < %s | \ +; RUN: FileCheck %s --check-prefix=DEV + +; Test that only white-listed intrinsics are allowed. + +; =================================== +; Some disallowed "Dev" intrinsics. +; CHECK: Function llvm.dbg.value is a disallowed LLVM intrinsic +; DBG-NOT: Function llvm.dbg.value is a disallowed LLVM intrinsic +; DEV-NOT: Function llvm.dbg.value is a disallowed LLVM intrinsic +declare void @llvm.dbg.value(metadata, i64, metadata) + +; CHECK: Function llvm.frameaddress is a disallowed LLVM intrinsic +; DEV-NOT: Function llvm.frameaddress is a disallowed LLVM intrinsic +declare i8* @llvm.frameaddress(i32 %level) + +; CHECK: Function llvm.returnaddress is a disallowed LLVM intrinsic +; DEV-NOT: Function llvm.returnaddress is a disallowed LLVM intrinsic +declare i8* @llvm.returnaddress(i32 %level) + +; =================================== +; Always allowed intrinsics. +; CHECK-NOT: Function llvm.lifetime.start is a disallowed LLVM intrinsic +; DBG-NOT: Function llvm.lifetime.start is a disallowed LLVM intrinsic +; DEV-NOT: Function llvm.lifetime.start is a disallowed LLVM intrinsic +declare void @llvm.lifetime.start(i64, i8* nocapture) + +; CHECK-NOT: Function llvm.lifetime.start is a disallowed LLVM intrinsic +declare void @llvm.lifetime.end(i64, i8* nocapture) +; CHECK-NOT: Function llvm.memcpy.p0i8.p0i8.i32 is a disallowed LLVM intrinsic +declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src, + i32 %len, i32 %align, i1 %isvolatile) +; CHECK-NOT: Function llvm.memcpy.p0i8.p0i8.i64 is a disallowed LLVM intrinsic +declare void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest, i8* %src, + i64 %len, i32 %align, i1 %isvolatile) +; CHECK-NOT: Function llvm.nacl.read.tp is a disallowed LLVM intrinsic +declare i8* @llvm.nacl.read.tp() + +; =================================== +; Always disallowed intrinsics. +; CHECK: Function llvm.adjust.trampoline is a disallowed LLVM intrinsic +; DBG: Function llvm.adjust.trampoline is a disallowed LLVM intrinsic +; DEV: Function llvm.adjust.trampoline is a disallowed LLVM intrinsic +declare i8* @llvm.adjust.trampoline(i8*) + +; CHECK: Function llvm.init.trampoline is a disallowed LLVM intrinsic +; DBG: Function llvm.init.trampoline is a disallowed LLVM intrinsic +; DEV: Function llvm.init.trampoline is a disallowed LLVM intrinsic +declare void @llvm.init.trampoline(i8*, i8*, i8*) + +; CHECK: Function llvm.x86.aesni.aeskeygenassist is a disallowed LLVM intrinsic +; DBG: Function llvm.x86.aesni.aeskeygenassist is a disallowed LLVM intrinsic +; DEV: Function llvm.x86.aesni.aeskeygenassist is a disallowed LLVM intrinsic +declare <2 x i64> @llvm.x86.aesni.aeskeygenassist(<2 x i64>, i8) + +; CHECK: Function llvm.va_copy is a disallowed LLVM intrinsic +; DBG: Function llvm.va_copy is a disallowed LLVM intrinsic +; DEV: Function llvm.va_copy is a disallowed LLVM intrinsic +declare void @llvm.va_copy(i8*, i8*) |