Skip to content

Commit 39f22bb

Browse files
Jan VoungRichard Diamond
Jan Voung
authored and
Richard Diamond
committed
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 [email protected] Review URL: https://codereview.chromium.org/14670017 (cherry picked from commit 77cc10f)
1 parent adabcf3 commit 39f22bb

File tree

2 files changed

+148
-0
lines changed

2 files changed

+148
-0
lines changed

lib/Analysis/NaCl/PNaClABIVerifyModule.cpp

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,9 @@
1717
#include "llvm/ADT/Twine.h"
1818
#include "llvm/Analysis/NaCl.h"
1919
#include "llvm/IR/DerivedTypes.h"
20+
#include "llvm/IR/Intrinsics.h"
2021
#include "llvm/IR/Module.h"
22+
#include "llvm/Support/Debug.h"
2123
#include "llvm/Support/raw_ostream.h"
2224

2325
#include "PNaClABITypeChecker.h"
@@ -28,8 +30,14 @@ cl::opt<bool>
2830
PNaClABIAllowDebugMetadata("pnaclabi-allow-debug-metadata",
2931
cl::desc("Allow debug metadata during PNaCl ABI verification."),
3032
cl::init(false));
33+
3134
}
3235

36+
static cl::opt<bool>
37+
PNaClABIAllowDevIntrinsics("pnaclabi-allow-dev-intrinsics",
38+
cl::desc("Allow all LLVM intrinsics during PNaCl ABI verification."),
39+
cl::init(true)); // TODO(jvoung): Make this false by default.
40+
3341
namespace {
3442
// This pass should not touch function bodies, to stay streaming-friendly
3543
class PNaClABIVerifyModule : public ModulePass {
@@ -55,6 +63,7 @@ class PNaClABIVerifyModule : public ModulePass {
5563
virtual void print(raw_ostream &O, const Module *M) const;
5664
private:
5765
void CheckGlobalValueCommon(const GlobalValue *GV);
66+
bool IsWhitelistedIntrinsic(const Function* F, unsigned ID);
5867
bool IsWhitelistedMetadata(const NamedMDNode *MD);
5968
PNaClABITypeChecker TC;
6069
PNaClABIErrorReporter *Reporter;
@@ -113,6 +122,76 @@ void PNaClABIVerifyModule::CheckGlobalValueCommon(const GlobalValue *GV) {
113122
}
114123
}
115124

125+
bool PNaClABIVerifyModule::IsWhitelistedIntrinsic(const Function* F,
126+
unsigned ID) {
127+
// Keep 3 categories of intrinsics for now.
128+
// (1) Allowed always
129+
// (2) Never allowed
130+
// (3) "Dev" intrinsics, which may or may not be allowed.
131+
// "Dev" intrinsics are controlled by the PNaClABIAllowDevIntrinsics flag.
132+
// Please keep these sorted within each category.
133+
switch(ID) {
134+
// Disallow by default.
135+
default: return false;
136+
// (1) Always allowed.
137+
case Intrinsic::invariant_end:
138+
case Intrinsic::invariant_start:
139+
case Intrinsic::lifetime_end:
140+
case Intrinsic::lifetime_start:
141+
case Intrinsic::memcpy:
142+
case Intrinsic::memmove:
143+
case Intrinsic::memset:
144+
case Intrinsic::nacl_read_tp:
145+
case Intrinsic::trap:
146+
return true;
147+
148+
// (2) Known to be never allowed.
149+
case Intrinsic::not_intrinsic:
150+
case Intrinsic::adjust_trampoline:
151+
case Intrinsic::init_trampoline:
152+
case Intrinsic::stackprotector:
153+
case Intrinsic::vacopy:
154+
case Intrinsic::vaend:
155+
case Intrinsic::vastart:
156+
return false;
157+
158+
// (3) Dev intrinsics.
159+
case Intrinsic::dbg_declare:
160+
case Intrinsic::dbg_value:
161+
return PNaClABIAllowDevIntrinsics || PNaClABIAllowDebugMetadata;
162+
case Intrinsic::bswap: // Support via compiler_rt if arch doesn't have it?
163+
case Intrinsic::cos: // Rounding not defined: support with fast-math?
164+
case Intrinsic::ctlz: // Support via compiler_rt if arch doesn't have it?
165+
case Intrinsic::ctpop: // Support via compiler_rt if arch doesn't have it?
166+
case Intrinsic::cttz: // Support via compiler_rt if arch doesn't have it?
167+
case Intrinsic::eh_dwarf_cfa: // For EH tests.
168+
case Intrinsic::exp: // Rounding not defined: support with fast-math?
169+
case Intrinsic::exp2: // Rounding not defined: support with fast-math?
170+
case Intrinsic::expect: // From __builtin_expect.
171+
case Intrinsic::flt_rounds:
172+
case Intrinsic::frameaddress: // Support for 0-level or not?
173+
case Intrinsic::log: // Rounding not defined: support with fast-math?
174+
case Intrinsic::log2: // Rounding not defined: support with fast-math?
175+
case Intrinsic::log10: // Rounding not defined: support with fast-math?
176+
case Intrinsic::nacl_target_arch: // Used by translator self-build.
177+
case Intrinsic::pow: // Rounding not defined: support with fast-math?
178+
case Intrinsic::prefetch: // Could ignore if target doesn't support?
179+
case Intrinsic::returnaddress: // Support for 0-level or not?
180+
case Intrinsic::sin: // Rounding not defined: support with fast-math?
181+
case Intrinsic::sqrt:
182+
case Intrinsic::stackrestore: // Used to support C99 VLAs.
183+
case Intrinsic::stacksave:
184+
// the *_with_overflow return struct types, so we'll need to fix these.
185+
case Intrinsic::sadd_with_overflow: // Introduced by -ftrapv
186+
case Intrinsic::ssub_with_overflow:
187+
case Intrinsic::uadd_with_overflow:
188+
case Intrinsic::usub_with_overflow:
189+
case Intrinsic::smul_with_overflow:
190+
case Intrinsic::umul_with_overflow: // Introduced by c++ new[x * y].
191+
return PNaClABIAllowDevIntrinsics;
192+
}
193+
}
194+
116195
bool PNaClABIVerifyModule::IsWhitelistedMetadata(const NamedMDNode* MD) {
117196
return MD->getName().startswith("llvm.dbg.") && PNaClABIAllowDebugMetadata;
118197
}
@@ -153,6 +232,13 @@ bool PNaClABIVerifyModule::runOnModule(Module &M) {
153232
}
154233

155234
for (Module::const_iterator MI = M.begin(), ME = M.end(); MI != ME; ++MI) {
235+
// Check intrinsics.
236+
if (MI->isIntrinsic()
237+
&& !IsWhitelistedIntrinsic(MI, MI->getIntrinsicID())) {
238+
Reporter->addError() << "Function " << MI->getName()
239+
<< " is a disallowed LLVM intrinsic\n";
240+
}
241+
156242
// Check types of functions and their arguments
157243
FunctionType *FT = MI->getFunctionType();
158244
if (!TC.isValidType(FT->getReturnType())) {

test/NaCl/PNaClABI/intrinsics.ll

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
; RUN: pnacl-abicheck -pnaclabi-allow-dev-intrinsics=0 < %s | FileCheck %s
2+
; RUN: pnacl-abicheck -pnaclabi-allow-dev-intrinsics=0 \
3+
; RUN: -pnaclabi-allow-debug-metadata < %s | FileCheck %s --check-prefix=DBG
4+
; RUN: pnacl-abicheck -pnaclabi-allow-dev-intrinsics=1 < %s | \
5+
; RUN: FileCheck %s --check-prefix=DEV
6+
7+
; Test that only white-listed intrinsics are allowed.
8+
9+
; ===================================
10+
; Some disallowed "Dev" intrinsics.
11+
; CHECK: Function llvm.dbg.value is a disallowed LLVM intrinsic
12+
; DBG-NOT: Function llvm.dbg.value is a disallowed LLVM intrinsic
13+
; DEV-NOT: Function llvm.dbg.value is a disallowed LLVM intrinsic
14+
declare void @llvm.dbg.value(metadata, i64, metadata)
15+
16+
; CHECK: Function llvm.frameaddress is a disallowed LLVM intrinsic
17+
; DEV-NOT: Function llvm.frameaddress is a disallowed LLVM intrinsic
18+
declare i8* @llvm.frameaddress(i32 %level)
19+
20+
; CHECK: Function llvm.returnaddress is a disallowed LLVM intrinsic
21+
; DEV-NOT: Function llvm.returnaddress is a disallowed LLVM intrinsic
22+
declare i8* @llvm.returnaddress(i32 %level)
23+
24+
; ===================================
25+
; Always allowed intrinsics.
26+
; CHECK-NOT: Function llvm.lifetime.start is a disallowed LLVM intrinsic
27+
; DBG-NOT: Function llvm.lifetime.start is a disallowed LLVM intrinsic
28+
; DEV-NOT: Function llvm.lifetime.start is a disallowed LLVM intrinsic
29+
declare void @llvm.lifetime.start(i64, i8* nocapture)
30+
31+
; CHECK-NOT: Function llvm.lifetime.start is a disallowed LLVM intrinsic
32+
declare void @llvm.lifetime.end(i64, i8* nocapture)
33+
; CHECK-NOT: Function llvm.memcpy.p0i8.p0i8.i32 is a disallowed LLVM intrinsic
34+
declare void @llvm.memcpy.p0i8.p0i8.i32(i8* %dest, i8* %src,
35+
i32 %len, i32 %align, i1 %isvolatile)
36+
; CHECK-NOT: Function llvm.memcpy.p0i8.p0i8.i64 is a disallowed LLVM intrinsic
37+
declare void @llvm.memcpy.p0i8.p0i8.i64(i8* %dest, i8* %src,
38+
i64 %len, i32 %align, i1 %isvolatile)
39+
; CHECK-NOT: Function llvm.nacl.read.tp is a disallowed LLVM intrinsic
40+
declare i8* @llvm.nacl.read.tp()
41+
42+
; ===================================
43+
; Always disallowed intrinsics.
44+
; CHECK: Function llvm.adjust.trampoline is a disallowed LLVM intrinsic
45+
; DBG: Function llvm.adjust.trampoline is a disallowed LLVM intrinsic
46+
; DEV: Function llvm.adjust.trampoline is a disallowed LLVM intrinsic
47+
declare i8* @llvm.adjust.trampoline(i8*)
48+
49+
; CHECK: Function llvm.init.trampoline is a disallowed LLVM intrinsic
50+
; DBG: Function llvm.init.trampoline is a disallowed LLVM intrinsic
51+
; DEV: Function llvm.init.trampoline is a disallowed LLVM intrinsic
52+
declare void @llvm.init.trampoline(i8*, i8*, i8*)
53+
54+
; CHECK: Function llvm.x86.aesni.aeskeygenassist is a disallowed LLVM intrinsic
55+
; DBG: Function llvm.x86.aesni.aeskeygenassist is a disallowed LLVM intrinsic
56+
; DEV: Function llvm.x86.aesni.aeskeygenassist is a disallowed LLVM intrinsic
57+
declare <2 x i64> @llvm.x86.aesni.aeskeygenassist(<2 x i64>, i8)
58+
59+
; CHECK: Function llvm.va_copy is a disallowed LLVM intrinsic
60+
; DBG: Function llvm.va_copy is a disallowed LLVM intrinsic
61+
; DEV: Function llvm.va_copy is a disallowed LLVM intrinsic
62+
declare void @llvm.va_copy(i8*, i8*)

0 commit comments

Comments
 (0)