aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorEli Bendersky <eliben@chromium.org>2013-07-02 08:55:49 -0700
committerEli Bendersky <eliben@chromium.org>2013-07-02 08:55:49 -0700
commit43102ff480a59a1661a6390422835a705f199582 (patch)
tree02ccf79af79023f5e0b2b47af8b18b3f448ee692
parent777f0e911fc0cbd0b07f9b3ae395b5361d19b270 (diff)
Enable ABI verification check for whitelisting external symbols
BUG=https://code.google.com/p/nativeclient/issues/detail?id=3339 R=mseaborn@chromium.org Review URL: https://codereview.chromium.org/18426002
-rw-r--r--lib/Analysis/NaCl/PNaClABIVerifyModule.cpp20
-rw-r--r--test/NaCl/PNaClABI/abi-aliases.ll2
-rw-r--r--test/NaCl/PNaClABI/abi-alignment.ll4
-rw-r--r--test/NaCl/PNaClABI/abi-arithmetic-attributes.ll4
-rw-r--r--test/NaCl/PNaClABI/abi-debug-info.ll4
-rw-r--r--test/NaCl/PNaClABI/abi-externals-whitelist.ll24
-rw-r--r--test/NaCl/PNaClABI/abi-flattened-globals.ll42
-rw-r--r--test/NaCl/PNaClABI/abi-stripped-pointers.ll12
-rw-r--r--test/NaCl/PNaClABI/abi-switch.ll4
-rw-r--r--test/NaCl/PNaClABI/global-attributes.ll20
-rw-r--r--test/NaCl/PNaClABI/instructions.ll28
-rw-r--r--test/NaCl/PNaClABI/types.ll12
12 files changed, 109 insertions, 67 deletions
diff --git a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
index b276e1cf2b..8bf0848fd7 100644
--- a/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
+++ b/lib/Analysis/NaCl/PNaClABIVerifyModule.cpp
@@ -68,6 +68,10 @@ class PNaClABIVerifyModule : public ModulePass {
private:
void checkGlobalValueCommon(const GlobalValue *GV);
bool isWhitelistedMetadata(const NamedMDNode *MD);
+
+ /// Returns whether \p GV is an allowed external symbol in stable bitcode.
+ bool isWhitelistedExternal(const GlobalValue *GV);
+
void checkGlobalIsFlattened(const GlobalVariable *GV);
PNaClABIErrorReporter *Reporter;
bool ReporterIsOwned;
@@ -126,8 +130,13 @@ void PNaClABIVerifyModule::checkGlobalValueCommon(const GlobalValue *GV) {
const char *GVTypeName = isa<GlobalVariable>(GV) ?
"Variable " : "Function ";
switch (GV->getLinkage()) {
- // TODO(dschuff): Disallow external linkage
case GlobalValue::ExternalLinkage:
+ if (!isWhitelistedExternal(GV)) {
+ Reporter->addError()
+ << GV->getName()
+ << " is not a valid external symbol (disallowed)\n";
+ }
+ break;
case GlobalValue::InternalLinkage:
break;
default:
@@ -299,6 +308,15 @@ bool PNaClABIVerifyModule::isWhitelistedMetadata(const NamedMDNode *MD) {
return MD->getName().startswith("llvm.dbg.") && PNaClABIAllowDebugMetadata;
}
+bool PNaClABIVerifyModule::isWhitelistedExternal(const GlobalValue *GV) {
+ if (const Function *Func = dyn_cast<const Function>(GV)) {
+ if (Func->getName().equals("_start") || Func->isIntrinsic()) {
+ return true;
+ }
+ }
+ return false;
+}
+
static bool isPtrToIntOfGlobal(const Constant *C) {
if (const ConstantExpr *CE = dyn_cast<ConstantExpr>(C)) {
return CE->getOpcode() == Instruction::PtrToInt &&
diff --git a/test/NaCl/PNaClABI/abi-aliases.ll b/test/NaCl/PNaClABI/abi-aliases.ll
index f245635236..0a1bf9ab11 100644
--- a/test/NaCl/PNaClABI/abi-aliases.ll
+++ b/test/NaCl/PNaClABI/abi-aliases.ll
@@ -1,6 +1,6 @@
; RUN: pnacl-abicheck < %s | FileCheck %s
-@aliased_var = global [1 x i8] c"x"
+@aliased_var = internal global [1 x i8] c"x"
; CHECK-NOT: disallowed
@alias1 = alias [1 x i8]* @aliased_var
diff --git a/test/NaCl/PNaClABI/abi-alignment.ll b/test/NaCl/PNaClABI/abi-alignment.ll
index 443fe44507..a31914e4be 100644
--- a/test/NaCl/PNaClABI/abi-alignment.ll
+++ b/test/NaCl/PNaClABI/abi-alignment.ll
@@ -10,7 +10,7 @@ declare void @llvm.memmove.p0i8.p0i8.i32(i8*, i8*, i32, i32, i1)
declare void @llvm.memset.p0i8.i32(i8*, i8, i32, i32, i1)
-define void @allowed_cases(i32 %ptr, float %f, double %d) {
+define internal void @allowed_cases(i32 %ptr, float %f, double %d) {
%ptr.i32 = inttoptr i32 %ptr to i32*
load i32* %ptr.i32, align 1
store i32 123, i32* %ptr.i32, align 1
@@ -49,7 +49,7 @@ define void @allowed_cases(i32 %ptr, float %f, double %d) {
; CHECK-NOT: disallowed
-define void @rejected_cases(i32 %ptr, float %f, double %d, i32 %align) {
+define internal void @rejected_cases(i32 %ptr, float %f, double %d, i32 %align) {
%ptr.i32 = inttoptr i32 %ptr to i32*
load i32* %ptr.i32, align 4
store i32 123, i32* %ptr.i32, align 4
diff --git a/test/NaCl/PNaClABI/abi-arithmetic-attributes.ll b/test/NaCl/PNaClABI/abi-arithmetic-attributes.ll
index 03304fb08c..c223830ac5 100644
--- a/test/NaCl/PNaClABI/abi-arithmetic-attributes.ll
+++ b/test/NaCl/PNaClABI/abi-arithmetic-attributes.ll
@@ -4,7 +4,7 @@
; unsigned wrap" and "no signed wrap") and "exact" are disallowed by
; the PNaCl ABI verifier.
-define void @allowed_cases() {
+define internal void @allowed_cases() {
%add = add i32 1, 2
%shl = shl i32 3, 4
%udiv = udiv i32 4, 2
@@ -15,7 +15,7 @@ define void @allowed_cases() {
; CHECK-NOT: disallowed
-define void @rejected_cases() {
+define internal void @rejected_cases() {
%add = add nsw i32 1, 2
; CHECK: disallowed: has "nsw" attribute: %add
%shl1 = shl nuw i32 3, 4
diff --git a/test/NaCl/PNaClABI/abi-debug-info.ll b/test/NaCl/PNaClABI/abi-debug-info.ll
index 95efa0ced7..49b31bab91 100644
--- a/test/NaCl/PNaClABI/abi-debug-info.ll
+++ b/test/NaCl/PNaClABI/abi-debug-info.ll
@@ -15,7 +15,7 @@ declare void @llvm.dbg.value(metadata, i64, metadata)
; CHECK: Function llvm.dbg.value is a disallowed LLVM intrinsic
-define void @debug_declare(i32 %val) {
+define internal void @debug_declare(i32 %val) {
; We normally expect llvm.dbg.declare to be used on an alloca.
%var = alloca [4 x i8]
tail call void @llvm.dbg.declare(metadata !{[4 x i8]* %var}, metadata !{})
@@ -23,7 +23,7 @@ define void @debug_declare(i32 %val) {
ret void
}
-define void @debug_value(i32 %ptr_as_int, i32 %val) {
+define internal void @debug_value(i32 %ptr_as_int, i32 %val) {
%ptr = inttoptr i32 %ptr_as_int to i8*
tail call void @llvm.dbg.value(metadata !{i8* %ptr}, i64 2, metadata !{})
tail call void @llvm.dbg.value(metadata !{i32 %val}, i64 1, metadata !{})
diff --git a/test/NaCl/PNaClABI/abi-externals-whitelist.ll b/test/NaCl/PNaClABI/abi-externals-whitelist.ll
new file mode 100644
index 0000000000..e0ec6e896b
--- /dev/null
+++ b/test/NaCl/PNaClABI/abi-externals-whitelist.ll
@@ -0,0 +1,24 @@
+; RUN: pnacl-abicheck < %s | FileCheck %s
+
+; Make sure that external symbols are properly rejected or accepted
+
+define void @foo() {
+ ret void
+}
+
+; CHECK: foo is not a valid external symbol (disallowed)
+
+define external void @main() {
+ ret void
+}
+; CHECK: main is not a valid external symbol (disallowed)
+
+define external void @_start() {
+ ret void
+}
+; _start is whitelisted
+; CHECK-NOT: _start is not a valid external symbol (disallowed)
+
+; Intrinsics can be external too
+declare void @llvm.trap()
+
diff --git a/test/NaCl/PNaClABI/abi-flattened-globals.ll b/test/NaCl/PNaClABI/abi-flattened-globals.ll
index c1c7235995..38f9ca8109 100644
--- a/test/NaCl/PNaClABI/abi-flattened-globals.ll
+++ b/test/NaCl/PNaClABI/abi-flattened-globals.ll
@@ -3,25 +3,25 @@
; Allowed cases
-@bytes = global [7 x i8] c"abcdefg"
+@bytes = internal global [7 x i8] c"abcdefg"
-@ptr_to_ptr = global i32 ptrtoint (i32* @ptr to i32)
-@ptr_to_func = global i32 ptrtoint (void ()* @func to i32)
+@ptr_to_ptr = internal global i32 ptrtoint (i32* @ptr to i32)
+@ptr_to_func = internal global i32 ptrtoint (void ()* @func to i32)
-@compound = global <{ [3 x i8], i32 }>
+@compound = internal global <{ [3 x i8], i32 }>
<{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
-@ptr = global i32 ptrtoint ([7 x i8]* @bytes to i32)
+@ptr = internal global i32 ptrtoint ([7 x i8]* @bytes to i32)
-@addend_ptr = global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
-@addend_negative = global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
+@addend_ptr = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 1)
+@addend_negative = internal global i32 add (i32 ptrtoint (i32* @ptr to i32), i32 -1)
-@addend_array1 = global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
-@addend_array2 = global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
-@addend_array3 = global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
+@addend_array1 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 1)
+@addend_array2 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 7)
+@addend_array3 = internal global i32 add (i32 ptrtoint ([7 x i8]* @bytes to i32), i32 9)
-@addend_struct1 = global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
-@addend_struct2 = global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
+@addend_struct1 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 1)
+@addend_struct2 = internal global i32 add (i32 ptrtoint (<{ [3 x i8], i32 }>* @compound to i32), i32 4)
; CHECK-NOT: disallowed
@@ -31,39 +31,39 @@
@bad_external = external global [1 x i8]
; CHECK: Global variable bad_external has no initializer (disallowed)
-@bad_int = global i32 0
+@bad_int = internal global i32 0
; CHECK: Global variable bad_int has non-flattened initializer (disallowed): i32 0
-@bad_size = global i64 ptrtoint ([7 x i8]* @bytes to i64)
+@bad_size = internal global i64 ptrtoint ([7 x i8]* @bytes to i64)
; CHECK: Global variable bad_size has non-flattened initializer
; "null" is not allowed.
-@bad_ptr = global i8* null
+@bad_ptr = internal global i8* null
; CHECK: Global variable bad_ptr has non-flattened initializer
-@bad_ptr2 = global i64 ptrtoint (i8* null to i64)
+@bad_ptr2 = internal global i64 ptrtoint (i8* null to i64)
; CHECK: Global variable bad_ptr2 has non-flattened initializer
-@bad_sub = global i32 sub (i32 ptrtoint (i32* @ptr to i32), i32 1)
+@bad_sub = internal global i32 sub (i32 ptrtoint (i32* @ptr to i32), i32 1)
; CHECK: Global variable bad_sub has non-flattened initializer
; i16 not allowed here.
-@bad_compound = global <{ i32, i16 }>
+@bad_compound = internal global <{ i32, i16 }>
<{ i32 ptrtoint (void ()* @func to i32), i16 0 }>
; CHECK: Global variable bad_compound has non-flattened initializer
; The struct type must be packed.
-@non_packed_struct = global { [3 x i8], i32 }
+@non_packed_struct = internal global { [3 x i8], i32 }
{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }
; CHECK: Global variable non_packed_struct has non-flattened initializer
; The struct type must be anonymous.
%struct = type <{ [3 x i8], i32 }>
-@named_struct = global %struct
+@named_struct = internal global %struct
<{ [3 x i8] c"foo", i32 ptrtoint (void ()* @func to i32) }>
; CHECK: Global variable named_struct has non-flattened initializer
-define void @func() {
+define internal void @func() {
ret void
}
diff --git a/test/NaCl/PNaClABI/abi-stripped-pointers.ll b/test/NaCl/PNaClABI/abi-stripped-pointers.ll
index 07516fb290..8f23cbce16 100644
--- a/test/NaCl/PNaClABI/abi-stripped-pointers.ll
+++ b/test/NaCl/PNaClABI/abi-stripped-pointers.ll
@@ -10,26 +10,26 @@
declare i8* @llvm.nacl.read.tp()
-define void @pointer_arg(i8* %arg) {
+define internal void @pointer_arg(i8* %arg) {
ret void
}
; CHECK: Function pointer_arg has disallowed type
-define i8* @pointer_return() {
+define internal i8* @pointer_return() {
unreachable
}
; CHECK-NEXT: Function pointer_return has disallowed type
-define void @func() {
+define internal void @func() {
ret void
}
-define void @func_with_arg(i32 %arg) {
+define internal void @func_with_arg(i32 %arg) {
ret void
}
-define void @allowed_cases(i32 %arg) {
+define internal void @allowed_cases(i32 %arg) {
inttoptr i32 123 to i8*
ptrtoint [4 x i8]* @var to i32
@@ -75,7 +75,7 @@ define void @allowed_cases(i32 %arg) {
; CHECK-NOT: disallowed
-define void @bad_cases() {
+define internal void @bad_cases() {
entry:
ptrtoint [4 x i8]* @var to i16
; CHECK: Function bad_cases disallowed: non-i32 ptrtoint
diff --git a/test/NaCl/PNaClABI/abi-switch.ll b/test/NaCl/PNaClABI/abi-switch.ll
index a3b5e631fc..c545f4e1f7 100644
--- a/test/NaCl/PNaClABI/abi-switch.ll
+++ b/test/NaCl/PNaClABI/abi-switch.ll
@@ -1,11 +1,11 @@
; RUN: pnacl-abicheck < %s | FileCheck %s
-@var = global [4 x i8] c"xxxx"
+@var = internal global [4 x i8] c"xxxx"
; CHECK-NOT: disallowed
-define void @bad_cases() {
+define internal void @bad_cases() {
; ConstantExprs should be rejected here.
switch i32 ptrtoint ([4 x i8]* @var to i32), label %next [i32 0, label %next]
; CHECK: disallowed: bad switch condition
diff --git a/test/NaCl/PNaClABI/global-attributes.ll b/test/NaCl/PNaClABI/global-attributes.ll
index c5253b3b63..45ed9c2fb6 100644
--- a/test/NaCl/PNaClABI/global-attributes.ll
+++ b/test/NaCl/PNaClABI/global-attributes.ll
@@ -3,16 +3,16 @@
; Global variable attributes
; CHECK: Variable var_with_section has disallowed "section" attribute
-@var_with_section = global [1 x i8] zeroinitializer, section ".some_section"
+@var_with_section = internal global [1 x i8] zeroinitializer, section ".some_section"
; PNaCl programs can depend on data alignments in general, so we allow
; "align" on global variables.
; CHECK-NOT: var_with_alignment
-@var_with_alignment = global [4 x i8] zeroinitializer, align 8
+@var_with_alignment = internal global [4 x i8] zeroinitializer, align 8
; TLS variables must be expanded out by ExpandTls.
; CHECK-NEXT: Variable tls_var has disallowed "thread_local" attribute
-@tls_var = thread_local global [4 x i8] zeroinitializer
+@tls_var = internal thread_local global [4 x i8] zeroinitializer
; CHECK-NEXT: Variable var_with_unnamed_addr has disallowed "unnamed_addr" attribute
@var_with_unnamed_addr = internal unnamed_addr constant [1 x i8] c"x"
@@ -24,37 +24,37 @@
; Function attributes
; CHECK-NEXT: Function func_with_attrs has disallowed attributes: noreturn nounwind
-define void @func_with_attrs() noreturn nounwind {
+define internal void @func_with_attrs() noreturn nounwind {
ret void
}
; CHECK-NEXT: Function func_with_arg_attrs has disallowed attributes: inreg zeroext
-define void @func_with_arg_attrs(i32 inreg zeroext) {
+define internal void @func_with_arg_attrs(i32 inreg zeroext) {
ret void
}
; CHECK-NEXT: Function func_with_callingconv has disallowed calling convention: 8
-define fastcc void @func_with_callingconv() {
+define internal fastcc void @func_with_callingconv() {
ret void
}
; CHECK-NEXT: Function func_with_section has disallowed "section" attribute
-define void @func_with_section() section ".some_section" {
+define internal void @func_with_section() section ".some_section" {
ret void
}
; CHECK-NEXT: Function func_with_alignment has disallowed "align" attribute
-define void @func_with_alignment() align 1 {
+define internal void @func_with_alignment() align 1 {
ret void
}
; CHECK-NEXT: Function func_with_gc has disallowed "gc" attribute
-define void @func_with_gc() gc "my_gc_func" {
+define internal void @func_with_gc() gc "my_gc_func" {
ret void
}
; CHECK-NEXT: Function func_with_unnamed_addr has disallowed "unnamed_addr" attribute
-define void @func_with_unnamed_addr() unnamed_addr {
+define internal void @func_with_unnamed_addr() unnamed_addr {
ret void
}
diff --git a/test/NaCl/PNaClABI/instructions.ll b/test/NaCl/PNaClABI/instructions.ll
index 49e8df5126..eb659cbffb 100644
--- a/test/NaCl/PNaClABI/instructions.ll
+++ b/test/NaCl/PNaClABI/instructions.ll
@@ -4,7 +4,7 @@
target datalayout = "e-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-p:32:32:32-v128:32:32"
target triple = "le32-unknown-nacl"
-define void @terminators() {
+define internal void @terminators() {
; Terminator instructions
terminators:
ret void
@@ -18,7 +18,7 @@ next2:
indirectbr i8* undef, [label %next, label %next2]
}
-define void @binops() {
+define internal void @binops() {
; Binary operations
%a1 = add i32 0, 0
%a2 = sub i32 0, 0
@@ -41,7 +41,7 @@ define void @binops() {
ret void
}
-define void @vectors() {
+define internal void @vectors() {
; CHECK-NOT: disallowed
; CHECK: disallowed: bad instruction opcode: {{.*}} extractelement
@@ -56,7 +56,7 @@ define void @vectors() {
ret void
}
-define void @aggregates() {
+define internal void @aggregates() {
; CHECK-NOT: disallowed
; Aggregate operations
@@ -69,7 +69,7 @@ define void @aggregates() {
ret void
}
-define void @memory() {
+define internal void @memory() {
; Memory operations
%a1 = alloca i8, i32 4
%ptr = inttoptr i32 0 to i32*
@@ -84,7 +84,7 @@ define void @memory() {
ret void
}
-define void @conversion() {
+define internal void @conversion() {
; Conversion operations
%a1 = trunc i32 undef to i8
%a2 = zext i8 undef to i32
@@ -98,7 +98,7 @@ define void @conversion() {
ret void
}
-define void @other() {
+define internal void @other() {
entry:
%a1 = icmp eq i32 undef, undef
%a2 = fcmp oeq float undef, undef
@@ -113,14 +113,14 @@ bar:
ret void
}
-define void @throwing_func() {
+define internal void @throwing_func() {
ret void
}
-define void @personality_func() {
+define internal void @personality_func() {
ret void
}
-define void @invoke_func() {
+define internal void @invoke_func() {
invoke void @throwing_func() to label %ok unwind label %onerror
; CHECK-NOT: disallowed
; CHECK: disallowed: bad instruction opcode: invoke
@@ -135,7 +135,7 @@ onerror:
; CHECK: disallowed: bad instruction opcode: resume
}
-define i32 @va_arg(i32 %va_list_as_int) {
+define internal i32 @va_arg(i32 %va_list_as_int) {
%va_list = inttoptr i32 %va_list_as_int to i8*
%val = va_arg i8* %va_list, i32
ret i32 %val
@@ -143,16 +143,16 @@ define i32 @va_arg(i32 %va_list_as_int) {
; CHECK-NOT: disallowed
; CHECK: disallowed: bad instruction opcode: {{.*}} va_arg
-@global_var = global [4 x i8] zeroinitializer
+@global_var = internal global [4 x i8] zeroinitializer
-define void @constantexpr() {
+define internal void @constantexpr() {
ptrtoint i8* getelementptr ([4 x i8]* @global_var, i32 1, i32 0) to i32
ret void
}
; CHECK-NOT: disallowed
; CHECK: disallowed: operand not InherentPtr: %1 = ptrtoint i8* getelementptr
-define void @inline_asm() {
+define internal void @inline_asm() {
call void asm "foo", ""()
ret void
}
diff --git a/test/NaCl/PNaClABI/types.ll b/test/NaCl/PNaClABI/types.ll
index 2a331324dc..6b8335504e 100644
--- a/test/NaCl/PNaClABI/types.ll
+++ b/test/NaCl/PNaClABI/types.ll
@@ -3,21 +3,21 @@
; CHECK: Function badReturn has disallowed type: half* ()
-define half* @badReturn() {
+define internal half* @badReturn() {
unreachable
}
; CHECK: Function badArgType1 has disallowed type: void (half, i32)
-define void @badArgType1(half %a, i32 %b) {
+define internal void @badArgType1(half %a, i32 %b) {
ret void
}
; CHECK: Function badArgType2 has disallowed type: void (i32, half)
-define void @badArgType2(i32 %a, half %b) {
+define internal void @badArgType2(i32 %a, half %b) {
ret void
}
-define void @func() {
+define internal void @func() {
entry:
br label %block
block:
@@ -97,7 +97,7 @@ block:
%struct.s1 = type { half, float}
%struct.s2 = type { i32, i32}
-define void @func2() {
+define internal void @func2() {
entry:
br label %block
block:
@@ -121,7 +121,7 @@ block:
%struct.linked = type { i32, %struct.linked * }
-define void @func3() {
+define internal void @func3() {
entry:
br label %block
block: