diff options
author | Daniel Dunbar <daniel@zuster.org> | 2009-05-21 04:36:41 +0000 |
---|---|---|
committer | Daniel Dunbar <daniel@zuster.org> | 2009-05-21 04:36:41 +0000 |
commit | 6f290d8f9e9d7faac295cb51fc96884a18f4ded4 (patch) | |
tree | 46e7d426abc0c9f06ac472ac6f7f9e661b5d78cb /test | |
parent | a55960edd4dcd7535526de8d2277642522aa0209 (diff) | |
download | klee-6f290d8f9e9d7faac295cb51fc96884a18f4ded4.tar.gz |
Initial KLEE checkin.
- Lots more tweaks, documentation, and web page content is needed, but this should compile & work on OS X & Linux. git-svn-id: https://llvm.org/svn/llvm-project/klee/trunk@72205 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'test')
136 files changed, 4928 insertions, 0 deletions
diff --git a/test/CXX/ArrayNew.cpp b/test/CXX/ArrayNew.cpp new file mode 100644 index 00000000..e6a41ddf --- /dev/null +++ b/test/CXX/ArrayNew.cpp @@ -0,0 +1,38 @@ +// RUN: %llvmgxx %s --emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --no-output --exit-on-error --no-externals %t1.bc + +#include <cassert> + +static int decon = 0; + +class Test { + int x; + +public: + Test() {} + Test(int _x) : x(_x) { } + ~Test() { decon += x; } + + int getX() { return x; } + void setX(int _x) { x = _x; } +}; + +int main(int argc) { + Test *rt = new Test[4]; + int i; + + for (i=0; i<4; i++) + rt[i].setX(i+1); + + int sum = 0; + for (i=0; i<4; i++) + sum += rt[i].getX(); + + assert(sum==10); + + delete[] rt; + + assert(decon==10); + + return 0; +} diff --git a/test/CXX/New.cpp b/test/CXX/New.cpp new file mode 100644 index 00000000..148dfed6 --- /dev/null +++ b/test/CXX/New.cpp @@ -0,0 +1,29 @@ +// RUN: %llvmgxx %s --emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --no-output --exit-on-error --no-externals %t1.bc + +#include <cassert> + +class Test { + int x; + +public: + Test(int _x) : x(_x) { + } + ~Test() { + } + + int getX() { return x; } +}; + +// This doesn't do what I want because +// it is being changed to alloca, but +// it is also failing. +int main(int argc) { + Test *rt = new Test(2); + + assert(rt->getX()==2); + + delete rt; + + return 0; +} diff --git a/test/CXX/SimpleVirtual.cpp b/test/CXX/SimpleVirtual.cpp new file mode 100644 index 00000000..9dc2a0ac --- /dev/null +++ b/test/CXX/SimpleVirtual.cpp @@ -0,0 +1,38 @@ +// RUN: %llvmgxx %s --emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --no-output --exit-on-error --no-externals %t1.bc + +#include <cassert> + +static int decon = 0; + +class Thing { +public: + Thing() {} + virtual ~Thing() { decon += getX(); } + + virtual int getX() { return 1; }; +}; + +class Thing2 : public Thing { +public: + virtual int getX() { return 2; }; +}; + +Thing *getThing(bool which) { + return which ? new Thing() : new Thing2(); +} + +int main(int argc) { + Thing *one = getThing(false); + Thing *two = getThing(true); + + int x = one->getX() + two->getX(); + assert(x==3); + + delete two; + delete one; + + assert(decon==2); + + return 0; +} diff --git a/test/CXX/StaticConstructor.cpp b/test/CXX/StaticConstructor.cpp new file mode 100644 index 00000000..d4992ffe --- /dev/null +++ b/test/CXX/StaticConstructor.cpp @@ -0,0 +1,25 @@ +// RUN: %llvmgxx %s --emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --libc=klee --no-output --exit-on-error %t1.bc + +#include <cassert> + +// to make sure globals are initialized +int aGlobal = 21; + +class Test { + int x; + +public: + Test() : x(aGlobal + 1) {} + ~Test() {} + + int getX() { return x; } +}; + +Test t; + +int main() { + assert(t.getX()==22); + + return 0; +} diff --git a/test/CXX/StaticDestructor.cpp b/test/CXX/StaticDestructor.cpp new file mode 100644 index 00000000..7a765a8f --- /dev/null +++ b/test/CXX/StaticDestructor.cpp @@ -0,0 +1,24 @@ +// don't optimize this, llvm likes to turn the *p into unreachable + +// RUN: %llvmgxx %s --emit-llvm -g -O0 -c -o %t1.bc +// RUN: %klee --libc=klee --no-output %t1.bc 2> %t1.log +// RUN: grep ":16: memory error" %t1.log + +#include <cassert> + +class Test { + int *p; + +public: + Test() : p(0) {} + ~Test() { + assert(!p); + assert(*p == 10); // crash here + } +}; + +Test t; + +int main() { + return 0; +} diff --git a/test/CXX/Trivial.cpp b/test/CXX/Trivial.cpp new file mode 100644 index 00000000..b50e82b2 --- /dev/null +++ b/test/CXX/Trivial.cpp @@ -0,0 +1,22 @@ +// RUN: %llvmgxx %s --emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --no-output --exit-on-error %t1.bc + +#include <cassert> + +class Test { + int x; + +public: + Test(int _x) : x(_x) {} + ~Test() {} + + int getX() { return x; } +}; + +int main() { + Test rt(2); + + assert(rt.getX()==2); + + return 0; +} diff --git a/test/CXX/dg.exp b/test/CXX/dg.exp new file mode 100644 index 00000000..879685ca --- /dev/null +++ b/test/CXX/dg.exp @@ -0,0 +1,3 @@ +load_lib llvm.exp + +RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Concrete/BitwiseOps.ll b/test/Concrete/BitwiseOps.ll new file mode 100644 index 00000000..cf5e7e6b --- /dev/null +++ b/test/Concrete/BitwiseOps.ll @@ -0,0 +1,15 @@ +declare void @print_i32(i32) + +define i32 @main() { + %a = or i32 12345678, 87654321 + %b = and i32 %a, 87654321 + %check = xor i32 %b, 87654321 + %test = icmp eq i32 %check, 0 + br i1 %test, label %exitTrue, label %exitFalse +exitTrue: + call void @print_i32(i32 1) + ret i32 0 +exitFalse: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/BoolReadWrite.ll b/test/Concrete/BoolReadWrite.ll new file mode 100644 index 00000000..f37359f8 --- /dev/null +++ b/test/Concrete/BoolReadWrite.ll @@ -0,0 +1,13 @@ +declare void @print_i1(i1) + +define i32 @main() { + %mem = alloca i1 + store i1 1, i1* %mem + %v = load i1* %mem + br i1 %v, label %ok, label %exit +ok: + call void @print_i1(i1 %v) + br label %exit +exit: + ret i32 0 +} diff --git a/test/Concrete/Casts.ll b/test/Concrete/Casts.ll new file mode 100755 index 00000000..1329a127 --- /dev/null +++ b/test/Concrete/Casts.ll @@ -0,0 +1,28 @@ +declare void @print_i32(i32) + +define i32 @main() { +entry: + %a = add i32 315904, 128 + %b = trunc i32 %a to i8 + %c0 = icmp eq i8 %b, 128 + %d = zext i8 %b to i32 + %c1 = icmp eq i32 %d, 128 + %e = sext i8 %b to i32 + %c2 = icmp eq i32 %e, -128 + %c0i = zext i1 %c0 to i32 + %c1i = zext i1 %c1 to i32 + %c2i = zext i1 %c2 to i32 + %c0is = shl i32 %c0i, 0 + %c1is = shl i32 %c1i, 1 + %c2is = shl i32 %c2i, 2 + %tmp = add i32 %c0is, %c1is + %res = add i32 %tmp, %c2is + %p = icmp eq i32 %res, 7 + br i1 %p, label %exitTrue, label %exitFalse +exitTrue: + call void @print_i32(i32 1) + ret i32 0 +exitFalse: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/CmpEq.ll b/test/Concrete/CmpEq.ll new file mode 100644 index 00000000..a8c2fe7a --- /dev/null +++ b/test/Concrete/CmpEq.ll @@ -0,0 +1,14 @@ +declare void @print_i32(i32) + +define i32 @main() { + %a = add i8 0, 1 + %b = add i8 %a, -1 + %c = icmp eq i8 %b, 0 + br i1 %c, label %exitTrue, label %exitFalse +exitTrue: + call void @print_i32(i32 1) + ret i32 0 +exitFalse: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/ConcreteTest.py b/test/Concrete/ConcreteTest.py new file mode 100755 index 00000000..758d0caa --- /dev/null +++ b/test/Concrete/ConcreteTest.py @@ -0,0 +1,99 @@ +#!/usr/bin/python + +import os +import sys +import popen2 + +class TestError(Exception): + pass + +kLLIPath = '../../llvm/Debug/bin/lli' +kKleePath = '../../Debug/bin/klee' + +def getFiles(): + for name in os.listdir('.'): + if (name[0]!='.' and name[0]!='_' and + (name.endswith('.ll') or name.endswith('.c'))): + yield name + +def readFile(f): + s = "" + while 1: + data = f.read() + if not data: + break + s += data + return s + +def testFile(name, printOutput=False): + baseName,ext = os.path.splitext(name) + exeFile = 'Output/linked_%s.bc'%baseName + if printOutput: + redirectStderr = '' + else: + redirectStderr = '2> /dev/null' + + if os.system('make %s > /dev/null %s'%(exeFile,redirectStderr)): + raise TestError('make failed') + + if printOutput: + print '-- running lli --' + lli = popen2.Popen3('%s -force-interpreter=true %s %s'%(kLLIPath,exeFile,redirectStderr)) + lliOut = readFile(lli.fromchild) + if lli.wait(): + raise TestError('lli execution failed') + + if printOutput: + print lliOut + + if printOutput: + print '-- running klee --' + klee = popen2.Popen3('%s --no-output %s %s'%(kKleePath,exeFile,redirectStderr)) + kleeOut = readFile(klee.fromchild) + if klee.wait(): + raise TestError('klee execution failed') + if printOutput: + print kleeOut + + if lliOut!=kleeOut: + raise TestError('outputs differ') + +def testOneFile(f, printOutput=False, log=None): + try: + testFile(f, printOutput) + code = ['pass','xpass'][f.startswith('broken')] + extra = '' + except TestError,e: + code = ['fail','xfail'][f.startswith('broken')] + extra = str(e) + + print '%s: %s -- %s'%(code,f,extra) + if log: + print >>log,'%s: %s -- %s'%(code,f,extra) + +def test(): + if not os.path.exists('Output'): + os.mkdir('Output') + log = open("Output/test.log","w") + files = list(getFiles()) + files.sort(key = lambda n: n.lower()) + for f in files: + testOneFile(f, log=log) + log.close() + +if __name__=='__main__': + args = sys.argv + args.pop(0) + + runAll = not args + + while args: + arg = args.pop(0) + if arg=='--run': + testFile(args.pop(0), printOutput=True) + else: + raise ValueError,'invalid argument: %s'%arg + + if runAll: + test() + diff --git a/test/Concrete/ConstantExpr.ll b/test/Concrete/ConstantExpr.ll new file mode 100644 index 00000000..2bc33a1e --- /dev/null +++ b/test/Concrete/ConstantExpr.ll @@ -0,0 +1,166 @@ +@gInt = global i32 10 +@gIntWithConstant = global i32 sub(i32 ptrtoint(i32* @gInt to i32), + i32 ptrtoint(i32* @gInt to i32)) + +define void @"test_int_to_ptr"() +begin + %t1 = add i8 ptrtoint(i8* inttoptr(i32 100 to i8*) to i8), 0 + %t2 = add i32 ptrtoint(i32* inttoptr(i8 100 to i32*) to i32), 0 + %t3 = add i32 ptrtoint(i32* inttoptr(i64 100 to i32*) to i32), 0 + %t4 = add i64 ptrtoint(i8* inttoptr(i32 100 to i8*) to i64), 0 + + call void @print_i8(i8 %t1) + call void @print_i32(i32 %t2) + call void @print_i32(i32 %t3) + call void @print_i64(i64 %t4) + + ret void +end + +define void @"test_constant_ops"() +begin + %t1 = add i8 trunc(i64 add(i64 ptrtoint(i32* @gInt to i64), i64 -10) to i8), 10 + %t2 = sub i64 sext(i32 ptrtoint(i32* @gInt to i32) to i64), ptrtoint(i32* @gInt to i64) + %t3 = sub i64 zext(i32 ptrtoint(i32* @gInt to i32) to i64), ptrtoint(i32* @gInt to i64) + + %t4 = icmp eq i8 trunc(i64 ptrtoint(i32* @gInt to i64) to i8), %t1 + %t5 = zext i1 %t4 to i8 + + call void @print_i8(i8 %t5) + call void @print_i64(i64 %t2) + call void @print_i64(i64 %t3) + + ret void +end + +define void @"test_logical_ops"() +begin + %t1 = add i32 -10, and(i32 ptrtoint(i32* @gInt to i32), i32 xor(i32 ptrtoint(i32* @gInt to i32), i32 -1)) + %t2 = add i32 -10, or(i32 ptrtoint(i32* @gInt to i32), i32 xor(i32 ptrtoint(i32* @gInt to i32), i32 -1)) + %t3 = add i32 -10, xor(i32 xor(i32 ptrtoint(i32* @gInt to i32), i32 1024), i32 ptrtoint(i32* @gInt to i32)) + + call void @print_i32(i32 %t1) + call void @print_i32(i32 %t2) + call void @print_i32(i32 %t3) + + %t4 = shl i32 lshr(i32 ptrtoint(i32* @gInt to i32), i32 8), 8 + %t5 = shl i32 ashr(i32 ptrtoint(i32* @gInt to i32), i32 8), 8 + %t6 = lshr i32 shl(i32 ptrtoint(i32* @gInt to i32), i32 8), 8 + + %t7 = icmp eq i32 %t4, %t5 + %t8 = icmp ne i32 %t4, %t6 + + %t9 = zext i1 %t7 to i8 + %t10 = zext i1 %t8 to i8 + + call void @print_i8(i8 %t9) + call void @print_i8(i8 %t10) + + ret void +end + +%test.struct.type = type { i32, i32 } +@test_struct = global %test.struct.type { i32 0, i32 10 } + +define void @"test_misc"() +begin + ; probability that @gInt == 100 is very very low + %t1 = add i32 select(i1 icmp eq (i32* @gInt, i32* inttoptr(i32 100 to i32*)), i32 10, i32 0), 0 + call void @print_i32(i32 %t1) + + %t2 = load i32* getelementptr(%test.struct.type* @test_struct, i32 0, i32 1) + call void @print_i32(i32 %t2) + + ret void +end + +define void @"test_simple_arith"() +begin + %t1 = add i32 add(i32 ptrtoint(i32* @gInt to i32), i32 0), 0 + %t2 = add i32 sub(i32 0, i32 ptrtoint(i32* @gInt to i32)), %t1 + %t3 = mul i32 mul(i32 ptrtoint(i32* @gInt to i32), i32 10), %t2 + + call void @print_i32(i32 %t3) + + ret void +end + +define void @"test_div_and_mod"() +begin + %t1 = add i32 udiv(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 + %t2 = add i32 urem(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 + %t3 = add i32 sdiv(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 + %t4 = add i32 srem(i32 ptrtoint(i32* @gInt to i32), i32 13), 0 + + %p = ptrtoint i32* @gInt to i32 + + %i1 = udiv i32 %p, 13 + %i2 = urem i32 %p, 13 + %i3 = sdiv i32 %p, 13 + %i4 = srem i32 %p, 13 + + %x1 = sub i32 %t1, %i1 + %x2 = sub i32 %t2, %i2 + %x3 = sub i32 %t3, %i3 + %x4 = sub i32 %t4, %i4 + + call void @print_i32(i32 %x1) + call void @print_i32(i32 %x2) + call void @print_i32(i32 %x3) + call void @print_i32(i32 %x4) + + ret void +end + +define void @test_cmp() +begin + %t1 = add i8 zext(i1 icmp ult (i32 ptrtoint(i32* @gInt to i32), i32 0) to i8), 1 + %t2 = add i8 zext(i1 icmp ule (i32 ptrtoint(i32* @gInt to i32), i32 0) to i8), 1 + %t3 = add i8 zext(i1 icmp uge (i32 ptrtoint(i32* @gInt to i32), i32 0) to i8), 1 + %t4 = add i8 zext(i1 icmp ugt (i32 ptrtoint(i32* @gInt to i32), i32 0) to i8), 1 + %t5 = add i8 zext(i1 icmp slt (i32 ptrtoint(i32* @gInt to i32), i32 0) to i8), 1 + %t6 = add i8 zext(i1 icmp sle (i32 ptrtoint(i32* @gInt to i32), i32 0) to i8), 1 + %t7 = add i8 zext(i1 icmp sge (i32 ptrtoint(i32* @gInt to i32), i32 0) to i8), 1 + %t8 = add i8 zext(i1 icmp sgt (i32 ptrtoint(i32* @gInt to i32), i32 0) to i8), 1 + %t9 = add i8 zext(i1 icmp eq (i32 ptrtoint(i32* @gInt to i32), i32 10) to i8), 1 + %t10 = add i8 zext(i1 icmp ne (i32 ptrtoint(i32* @gInt to i32), i32 10) to i8), 1 + + call void @print_i1(i8 %t1) + call void @print_i1(i8 %t2) + call void @print_i1(i8 %t3) + call void @print_i1(i8 %t4) + call void @print_i1(i8 %t5) + call void @print_i1(i8 %t6) + call void @print_i1(i8 %t7) + call void @print_i1(i8 %t8) + call void @print_i1(i8 %t9) + call void @print_i1(i8 %t10) + + ret void +end + +define i32 @main() +begin + call void @test_simple_arith() + + call void @test_div_and_mod() + + call void @test_cmp() + + call void @test_int_to_ptr() + + call void @test_constant_ops() + + call void @test_logical_ops() + + call void @test_misc() + + ret i32 0 +end + +; defined in print_int.c +declare void @print_i1(i8) +declare void @print_i8(i8) +declare void @print_i16(i16) +declare void @print_i32(i32) +declare void @print_i64(i64) diff --git a/test/Concrete/FloatingPointOps.ll b/test/Concrete/FloatingPointOps.ll new file mode 100644 index 00000000..7f23dcef --- /dev/null +++ b/test/Concrete/FloatingPointOps.ll @@ -0,0 +1,685 @@ +%struct.stdout = type { i32, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, i8*, %struct._IO_marker*, %struct.stdout*, i32, i32, i32, i16, i8, [1 x i8], i8*, i64, i8*, i8*, i8*, i8*, i32, i32, [40 x i8] } +%struct._IO_marker = type { %struct._IO_marker*, %struct.stdout*, i32 } +@stdout = external global %struct.stdout* + +; casting error messages +@.strTrunc = internal constant [15 x i8] c"FPTrunc broken\00" +@.strExt = internal constant [13 x i8] c"FPExt broken\00" +@.strFPToUIFlt = internal constant [20 x i8] c"FPToUI float broken\00" +@.strFPToUIDbl = internal constant [21 x i8] c"FPToUI double broken\00" +@.strFPToSIFlt = internal constant [20 x i8] c"FPToSI float broken\00" +@.strFPToSIDbl = internal constant [21 x i8] c"FPToSI double broken\00" +@.strUIToFPFlt = internal constant [20 x i8] c"UIToFP float broken\00" +@.strUIToFPDbl = internal constant [21 x i8] c"UIToFP double broken\00" +@.strSIToFPFlt = internal constant [20 x i8] c"SIToFP float broken\00" +@.strSIToFPDbl = internal constant [21 x i8] c"SIToFP double broken\00" + +; mathematical operator error messages +@.strDivFlt = internal constant [18 x i8] c"FDiv float broken\00" +@.strDivDbl = internal constant [19 x i8] c"FDiv double broken\00" +@.strRemFlt = internal constant [18 x i8] c"FRem float broken\00" +@.strRemDbl = internal constant [19 x i8] c"FRem double broken\00" +@.strAddInt = internal constant [16 x i8] c"Add ints broken\00" +@.strAddFlt = internal constant [18 x i8] c"Add floats broken\00" +@.strAddDbl = internal constant [19 x i8] c"Add doubles broken\00" +@.strSubInt = internal constant [16 x i8] c"Sub ints broken\00" +@.strSubFlt = internal constant [18 x i8] c"Sub floats broken\00" +@.strSubDbl = internal constant [19 x i8] c"Sub doubles broken\00" +@.strMulInt = internal constant [16 x i8] c"Mul ints broken\00" +@.strMulFlt = internal constant [18 x i8] c"Mul floats broken\00" +@.strMulDbl = internal constant [19 x i8] c"Mul doubles broken\00" + +; fcmp error messages +@.strCmpTrFlt = internal constant [19 x i8] c"floats TRUE broken\00" ; fcmp::generic broken msgs +@.strCmpFaFlt = internal constant [20 x i8] c"floats FALSE broken\00" +@.strCmpTrDbl = internal constant [19 x i8] c"double TRUE broken\00" +@.strCmpFaDbl = internal constant [20 x i8] c"double FALSE broken\00" +@.strCmpEqFlt = internal constant [17 x i8] c"floats == broken\00" ; fcmp::ordered broken msgs +@.strCmpGeFlt = internal constant [17 x i8] c"floats >= broken\00" +@.strCmpGtFlt = internal constant [17 x i8] c"floats > broken\00" +@.strCmpLeFlt = internal constant [17 x i8] c"floats <= broken\00" +@.strCmpLtFlt = internal constant [17 x i8] c"floats < broken\00" +@.strCmpNeFlt = internal constant [17 x i8] c"floats != broken\00" +@.strCmpOrdFlt = internal constant [18 x i8] c"floats ORD broken\00" +@.strCmpEqDbl = internal constant [18 x i8] c"doubles == broken\00" +@.strCmpGeDbl = internal constant [18 x i8] c"doubles >= broken\00" +@.strCmpGtDbl = internal constant [18 x i8] c"doubles > broken\00" +@.strCmpLeDbl = internal constant [18 x i8] c"doubles <= broken\00" +@.strCmpLtDbl = internal constant [18 x i8] c"doubles < broken\00" +@.strCmpNeDbl = internal constant [18 x i8] c"doubles != broken\00" +@.strCmpOrdDbl = internal constant [19 x i8] c"doubles ORD broken\00" +@.strCmpEqFltU = internal constant [17 x i8] c"U:floats==broken\00" ; fcmp::unordered broken msgs +@.strCmpGeFltU = internal constant [17 x i8] c"U:floats>=broken\00" +@.strCmpGtFltU = internal constant [17 x i8] c"U:floats> broken\00" +@.strCmpLeFltU = internal constant [17 x i8] c"U:floats<=broken\00" +@.strCmpLtFltU = internal constant [17 x i8] c"U:floats< broken\00" +@.strCmpNeFltU = internal constant [17 x i8] c"U:floats!=broken\00" +@.strCmpUnoFlt = internal constant [20 x i8] c"U:floats UNO broken\00" +@.strCmpEqDblU = internal constant [18 x i8] c"U:doubles==broken\00" +@.strCmpGeDblU = internal constant [18 x i8] c"U:doubles>=broken\00" +@.strCmpGtDblU = internal constant [18 x i8] c"U:doubles> broken\00" +@.strCmpLeDblU = internal constant [18 x i8] c"U:doubles<=broken\00" +@.strCmpLtDblU = internal constant [18 x i8] c"U:doubles< broken\00" +@.strCmpNeDblU = internal constant [18 x i8] c"U:doubles!=broken\00" +@.strCmpUnoDbl = internal constant [21 x i8] c"U:doubles UNO broken\00" + +@.strWorks = internal constant [20 x i8] c"Everything works!\0D\0A\00" +@.strNL = internal constant [3 x i8] c"\0D\0A\00" + +declare i32 @fprintf(%struct.stdout*, i8*, ...) +declare void @exit(i32) +declare void @llvm.memcpy.i32(i8*, i8*, i32, i32) + +; if isOk is false, then print errMsg to stdout and exit(1) +define void @failCheck(i1 %isOk, i8* %errMsg) { +entry: + %fail = icmp eq i1 %isOk, 0 + br i1 %fail, label %failed, label %return + +failed: + ; print the error msg + %err_stream = load %struct.stdout** @stdout + %ret = call i32 (%struct.stdout*, i8*, ...)* @fprintf( %struct.stdout* %err_stream, i8* %errMsg ) + + ; add a newline to the ostream + %nl = getelementptr [3 x i8]* @.strNL, i32 0, i32 0 + %ret2 = call i32 (%struct.stdout*, i8*, ...)* @fprintf( %struct.stdout* %err_stream, i8* %nl ) + + ; exit with return value 1 to denote that an error occurred + call void @exit( i32 1 ) + unreachable + +return: + ret void +} + +; test FPTrunc which casts doubles to floats +define void @testFPTrunc() { +entry: + %d_addr = alloca double, align 8 + store double 8.000000e+00, double* %d_addr + %d = load double* %d_addr + %f = fptrunc double %d to float + %matches = fcmp oeq float %f, 8.000000e+00 + %err_msg = getelementptr [15 x i8]* @.strTrunc, i32 0, i32 0 + call void @failCheck( i1 %matches, i8* %err_msg ) + ret void +} + +; test FPExt which casts floats to doubles +define void @testFPExt() { +entry: + %f_addr = alloca float, align 4 + store float 8.000000e+00, float* %f_addr + %f = load float* %f_addr + %d = fpext float %f to double + %matches = fcmp oeq double %d, 8.000000e+00 + %err_msg = getelementptr [13 x i8]* @.strExt, i32 0, i32 0 + call void @failCheck( i1 %matches, i8* %err_msg ) + ret void +} + +; test casting fp to an unsigned int +define void @testFPToUI() { +entry: + %f_addr = alloca float, align 4 + %d_addr = alloca double, align 8 + + ; test float to UI + store float 0x4020333340000000, float* %f_addr; %f = 8.1 + %f = load float* %f_addr + %uf = fptoui float %f to i32 + %matchesf = icmp eq i32 %uf, 8 + %err_msgf = getelementptr [20 x i8]* @.strFPToUIFlt, i32 0, i32 0 + call void @failCheck( i1 %matchesf, i8* %err_msgf ) + + ; test double to UI + store double 8.100000e+00, double* %d_addr + %d = load double* %d_addr + %ud = fptoui double %d to i32 + %matchesd = icmp eq i32 %ud, 8 + %err_msgd = getelementptr [21 x i8]* @.strFPToUIDbl, i32 0, i32 0 + call void @failCheck( i1 %matchesd, i8* %err_msgd ) + + ret void +} + +; test casting fp to a signed int +define void @testFPToSI() { +entry: + %f_addr = alloca float, align 4 + %d_addr = alloca double, align 8 + + ; test float 8.1 to signed int + store float 0x4020333340000000, float* %f_addr + %f = load float* %f_addr + %sf = fptosi float %f to i32 + %matchesf = icmp eq i32 %sf, 8 + %err_msgf = getelementptr [20 x i8]* @.strFPToSIFlt, i32 0, i32 0 + call void @failCheck( i1 %matchesf, i8* %err_msgf ) + + ; test double -8.1 to signed int + store double -8.100000e+00, double* %d_addr + %d = load double* %d_addr + %sd = fptosi double %d to i32 + %matchesd = icmp eq i32 %sd, -8 + %err_msgd = getelementptr [21 x i8]* @.strFPToSIDbl, i32 0, i32 0 + call void @failCheck( i1 %matchesd, i8* %err_msgd ) + + ret void +} + +; test casting unsigned int to fp +define void @testUIToFP() { +entry: + ; unsigned int to float + %f = uitofp i32 7 to float + %matchesf = fcmp oeq float %f, 7.000000e+00 + %err_msgf = getelementptr [20 x i8]* @.strUIToFPFlt, i32 0, i32 0 + call void @failCheck( i1 %matchesf, i8* %err_msgf ) + + ; unsigned int to double + %d = uitofp i32 7 to double + %matchesd = fcmp oeq double %d, 7.000000e+00 + %err_msgd = getelementptr [21 x i8]* @.strUIToFPDbl, i32 0, i32 0 + call void @failCheck( i1 %matchesd, i8* %err_msgd ) + + ret void +} + +; test casting signed int to fp +define void @testSIToFP() { +entry: + ; signed int to float + %f = sitofp i32 -7 to float + %matchesf = fcmp oeq float %f, -7.000000e+00 + %err_msgf = getelementptr [20 x i8]* @.strSIToFPFlt, i32 0, i32 0 + call void @failCheck( i1 %matchesf, i8* %err_msgf ) + + ; signed int to double + %d = sitofp i32 -7 to double + %matchesd = fcmp oeq double %d, -7.000000e+00 + %err_msgd = getelementptr [21 x i8]* @.strSIToFPDbl, i32 0, i32 0 + call void @failCheck( i1 %matchesd, i8* %err_msgd ) + + ret void +} + +; testing fp division +define void @testFDiv() { +entry: + %fN_addr = alloca float, align 4 + %fD_addr = alloca float, align 4 + %dN_addr = alloca double, align 8 + %dD_addr = alloca double, align 8 + + ; float division + store float 2.200000e+01, float* %fN_addr + store float 4.000000e+00, float* %fD_addr + %fN = load float* %fN_addr + %fD = load float* %fD_addr + %f = fdiv float %fN, %fD + %matchesf = fcmp oeq float %f, 5.500000e+00 + %err_msgf = getelementptr [18 x i8]* @.strDivFlt, i32 0, i32 0 + call void @failCheck( i1 %matchesf, i8* %err_msgf ) + + ; double division + store double 2.200000e+01, double* %dN_addr + store double -4.000000e+00, double* %dD_addr + %dN = load double* %dN_addr + %dD = load double* %dD_addr + %d = fdiv double %dN, %dD + %matchesd = fcmp oeq double %d, -5.500000e+00 + %err_msgd = getelementptr [19 x i8]* @.strDivDbl, i32 0, i32 0 + call void @failCheck( i1 %matchesd, i8* %err_msgd ) + + ret void +} + +; testing fp modulo +define void @testFRem() { +entry: + %fN_addr = alloca float, align 4 + %fD_addr = alloca float, align 4 + %dN_addr = alloca double, align 8 + %dD_addr = alloca double, align 8 + + ; float modoulo + store float 2.200000e+01, float* %fN_addr + store float 4.000000e+00, float* %fD_addr + %fN = load float* %fN_addr + %fD = load float* %fD_addr + %f = frem float %fN, %fD + %matchesf = fcmp oeq float %f, 2.000000e+00 + %err_msgf = getelementptr [18 x i8]* @.strRemFlt, i32 0, i32 0 + call void @failCheck( i1 %matchesf, i8* %err_msgf ) + + ; double modulo + store double -2.200000e+01, double* %dN_addr + store double 4.000000e+00, double* %dD_addr + %dN = load double* %dN_addr + %dD = load double* %dD_addr + %d = frem double %dN, %dD + %matchesd = fcmp oeq double %d, -2.000000e+00 + %err_msgd = getelementptr [19 x i8]* @.strRemDbl, i32 0, i32 0 + call void @failCheck( i1 %matchesd, i8* %err_msgd ) + + ret void +} + +; test addition (fp and int since add is polymorphic) +define void @testAdd() { +entry: + %f1_addr = alloca float, align 4 + %f2_addr = alloca float, align 4 + %d1_addr = alloca double, align 8 + %d2_addr = alloca double, align 8 + + ; test integer addition (3 + 4) + %sumi = add i32 3, 4 + %matchesi = icmp eq i32 %sumi, 7 + %err_msgi = getelementptr [16 x i8]* @.strAddInt, i32 0, i32 0 + call void @failCheck( i1 %matchesi, i8* %err_msgi ) + + ; test float addition (3.5 + 4.2) + store float 3.500000e+00, float* %f1_addr + store float 0x4010CCCCC0000000, float* %f2_addr + %f1 = load float* %f1_addr + %f2 = load float* %f2_addr + %sumf = add float %f1, %f2 + %matchesf = fcmp oeq float %sumf, 0x401ECCCCC0000000 + %err_msgf = getelementptr [18 x i8]* @.strAddFlt, i32 0, i32 0 + call void @failCheck( i1 %matchesf, i8* %err_msgf ) + + ; test double addition (3.5 + -4.2) + store double 3.500000e+00, double* %d1_addr + store double -4.200000e+00, double* %d2_addr + %d1 = load double* %d1_addr + %d2 = load double* %d2_addr + %sumd = add double %d1, %d2 + %matchesd = fcmp oeq double %sumd, 0xBFE6666666666668 + %err_msgd = getelementptr [19 x i8]* @.strAddDbl, i32 0, i32 0 + call void @failCheck( i1 %matchesd, i8* %err_msgd ) + + ret void +} + +; test subtraction (fp and int since sub is polymorphic) +define void @testSub() { +entry: + %f1_addr = alloca float, align 4 + %f2_addr = alloca float, align 4 + %d1_addr = alloca double, align 8 + %d2_addr = alloca double, align 8 + + ; test integer subtraction (3 - 4) + %subi = sub i32 3, 4 + %matchesi = icmp eq i32 %subi, -1 + %err_msgi = getelementptr [16 x i8]* @.strSubInt, i32 0, i32 0 + call void @failCheck( i1 %matchesi, i8* %err_msgi ) + + ; test float subtraction (3.5 - 4.2) + store float 3.500000e+00, float* %f1_addr + store float 0x4010CCCCC0000000, float* %f2_addr + %f1 = load float* %f1_addr + %f2 = load float* %f2_addr + %subf = sub float %f1, %f2 + %matchesf = fcmp oeq float %subf, 0xBFE6666600000000 + %err_msgf = getelementptr [18 x i8]* @.strSubFlt, i32 0, i32 0 + call void @failCheck( i1 %matchesf, i8* %err_msgf ) + + ; test double subtraction (3.5 - -4.2) + store double 3.500000e+00, double* %d1_addr + store double -4.200000e+00, double* %d2_addr + %d1 = load double* %d1_addr + %d2 = load double* %d2_addr + %subd = sub double %d1, %d2 + %matchesd = fcmp oeq double %subd, 7.700000e+00 + %err_msgd = getelementptr [19 x i8]* @.strSubDbl, i32 0, i32 0 + call void @failCheck( i1 %matchesd, i8* %err_msgd ) + + ret void +} + +; test multiplication (fp and int since mul is polymorphic) +define void @testMul() { +entry: + %f1_addr = alloca float, align 4 + %f2_addr = alloca float, align 4 + %d1_addr = alloca double, align 8 + %d2_addr = alloca double, align 8 + + ; test integer multiplication (3 * 4) + %muli = mul i32 3, 4 + %matchesi = icmp eq i32 %muli, 12 + %err_msgi = getelementptr [16 x i8]* @.strMulInt, i32 0, i32 0 + call void @failCheck( i1 %matchesi, i8* %err_msgi ) + + ; test float multiplication (3.5 * 4.2) + store float 3.500000e+00, float* %f1_addr + store float 0x4010CCCCC0000000, float* %f2_addr + %f1 = load float* %f1_addr + %f2 = load float* %f2_addr + %mulf = mul float %f1, %f2 + %matchesf = fcmp oeq float %mulf, 0x402D666640000000 + %err_msgf = getelementptr [18 x i8]* @.strMulFlt, i32 0, i32 0 + call void @failCheck( i1 %matchesf, i8* %err_msgf ) + + ; test double multiplication (3.5 * -4.2) + store double 3.500000e+00, double* %d1_addr + store double -4.200000e+00, double* %d2_addr + %d1 = load double* %d1_addr + %d2 = load double* %d2_addr + %muld = mul double %d1, %d2 + %matchesd = fcmp oeq double %muld, 0xC02D666666666667 + %err_msgd = getelementptr [19 x i8]* @.strMulDbl, i32 0, i32 0 + call void @failCheck( i1 %matchesd, i8* %err_msgd ) + + ret void +} + +; test float comparisons (ordered) +define void @testFCmpFOrdered(float %f1, float %f2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %ord) { +entry: + ; test fcmp::true -- should always return true + %cmp_t = fcmp true float %f1, %f2 + %cmp_t_ok = icmp eq i1 %cmp_t, 1 + %cmp_t_em = getelementptr [19 x i8]* @.strCmpTrFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_t_ok, i8* %cmp_t_em ) + + ; test fcmp::false -- should always return false + %cmp_f = fcmp false float %f1, %f2 + %cmp_f_ok = icmp eq i1 %cmp_f, 0 + %cmp_f_em = getelementptr [20 x i8]* @.strCmpFaFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_f_ok, i8* %cmp_f_em ) + + ; test fcmp::ord -- should return true if neither operand is NaN + %cmp_o = fcmp ord float %f1, %f2 + %cmp_o_ok = icmp eq i1 %cmp_o, %ord + %cmp_o_em = getelementptr [18 x i8]* @.strCmpOrdFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_o_ok, i8* %cmp_o_em ) + + ; test fcmp::oeq -- should return true if neither operand is a NaN and they are equal + %cmp_eq = fcmp oeq float %f1, %f2 + %cmp_eq_ok = icmp eq i1 %cmp_eq, %eq + %cmp_eq_em = getelementptr [17 x i8]* @.strCmpEqFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_eq_ok, i8* %cmp_eq_em ) + + ; test fcmp::oge -- should return true if neither operand is a NaN and the first is greater or equal + %cmp_ge = fcmp oge float %f1, %f2 + %cmp_ge_ok = icmp eq i1 %cmp_ge, %ge + %cmp_ge_em = getelementptr [17 x i8]* @.strCmpGeFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_ge_ok, i8* %cmp_ge_em ) + + ; test fcmp::ogt -- should return true if neither operand is a NaN and the first is greater + %cmp_gt = fcmp ogt float %f1, %f2 + %cmp_gt_ok = icmp eq i1 %cmp_gt, %gt + %cmp_gt_em = getelementptr [17 x i8]* @.strCmpGtFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_gt_ok, i8* %cmp_gt_em ) + + ; test fcmp::ole -- should return true if neither operand is a NaN and the first is less or equal + %cmp_le = fcmp ole float %f1, %f2 + %cmp_le_ok = icmp eq i1 %cmp_le, %le + %cmp_le_em = getelementptr [17 x i8]* @.strCmpLeFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_le_ok, i8* %cmp_le_em ) + + ; test fcmp::olt -- should return true if neither operand is a NaN and the first is less + %cmp_lt = fcmp olt float %f1, %f2 + %cmp_lt_ok = icmp eq i1 %cmp_lt, %lt + %cmp_lt_em = getelementptr [17 x i8]* @.strCmpLtFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_lt_ok, i8* %cmp_lt_em ) + + ; test fcmp::one -- should return true if neither operand is a NaN and they are not equal + %cmp_ne = fcmp one float %f1, %f2 + %cmp_ne_ok = icmp eq i1 %cmp_ne, %ne + %cmp_ne_em = getelementptr [17 x i8]* @.strCmpNeFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_ne_ok, i8* %cmp_ne_em ) + + ret void +} + +; test double comparisons (ordered) +define void @testFCmpDOrdered(double %d1, double %d2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %ord) { +entry: + ; test fcmp::true -- should always return true + %cmp_t = fcmp true double %d1, %d2 + %cmp_t_ok = icmp eq i1 %cmp_t, 1 + %cmp_t_em = getelementptr [19 x i8]* @.strCmpTrDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_t_ok, i8* %cmp_t_em ) + + ; test fcmp::false -- should always return false + %cmp_f = fcmp false double %d1, %d2 + %cmp_f_ok = icmp eq i1 %cmp_f, 0 + %cmp_f_em = getelementptr [20 x i8]* @.strCmpFaDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_f_ok, i8* %cmp_f_em ) + + ; test fcmp::ord -- should return true if neither operand is NaN + %cmp_o = fcmp ord double %d1, %d2 + %cmp_o_ok = icmp eq i1 %cmp_o, %ord + %cmp_o_em = getelementptr [19 x i8]* @.strCmpOrdDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_o_ok, i8* %cmp_o_em ) + + ; test fcmp::oeq -- should return true if neither operand is a NaN and they are equal + %cmp_eq = fcmp oeq double %d1, %d2 + %cmp_eq_ok = icmp eq i1 %cmp_eq, %eq + %cmp_eq_em = getelementptr [18 x i8]* @.strCmpEqDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_eq_ok, i8* %cmp_eq_em ) + + ; test fcmp::oge -- should return true if neither operand is a NaN and the first is greater or equal + %cmp_ge = fcmp oge double %d1, %d2 + %cmp_ge_ok = icmp eq i1 %cmp_ge, %ge + %cmp_ge_em = getelementptr [18 x i8]* @.strCmpGeDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_ge_ok, i8* %cmp_ge_em ) + + ; test fcmp::ogt -- should return true if neither operand is a NaN and the first is greater + %cmp_gt = fcmp ogt double %d1, %d2 + %cmp_gt_ok = icmp eq i1 %cmp_gt, %gt + %cmp_gt_em = getelementptr [18 x i8]* @.strCmpGtDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_gt_ok, i8* %cmp_gt_em ) + + ; test fcmp::ole -- should return true if neither operand is a NaN and the first is less or equal + %cmp_le = fcmp ole double %d1, %d2 + %cmp_le_ok = icmp eq i1 %cmp_le, %le + %cmp_le_em = getelementptr [18 x i8]* @.strCmpLeDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_le_ok, i8* %cmp_le_em ) + + ; test fcmp::olt -- should return true if neither operand is a NaN and the first is less + %cmp_lt = fcmp olt double %d1, %d2 + %cmp_lt_ok = icmp eq i1 %cmp_lt, %lt + %cmp_lt_em = getelementptr [18 x i8]* @.strCmpLtDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_lt_ok, i8* %cmp_lt_em ) + + ; test fcmp::one -- should return true if neither operand is a NaN and they are not equal + %cmp_ne = fcmp one double %d1, %d2 + %cmp_ne_ok = icmp eq i1 %cmp_ne, %ne + %cmp_ne_em = getelementptr [18 x i8]* @.strCmpNeDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_ne_ok, i8* %cmp_ne_em ) + + ret void +} + +; test floating point comparisons (ordered) +define void @testFCmpBothOrdered(double %d1, double %d2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %ord) { +entry: + call void @testFCmpDOrdered( double %d1, double %d2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %ord ) + + %f1 = fptrunc double %d1 to float + %f2 = fptrunc double %d2 to float + call void @testFCmpFOrdered( float %f1, float %f2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %ord ) + + ret void +} + +; test float comparisons (unordered) +define void @testFCmpFUnordered(float %f1, float %f2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %uno) { +entry: + ; test fcmp::uno -- should return true if either operand is NaN + %cmp_o = fcmp uno float %f1, %f2 + %cmp_o_ok = icmp eq i1 %cmp_o, %uno + %cmp_o_em = getelementptr [20 x i8]* @.strCmpUnoFlt, i32 0, i32 0 + call void @failCheck( i1 %cmp_o_ok, i8* %cmp_o_em ) + + ; test fcmp::oeq -- should return true if either operand is a NaN and they are equal + %cmp_eq = fcmp ueq float %f1, %f2 + %cmp_eq_ok = icmp eq i1 %cmp_eq, %eq + %cmp_eq_em = getelementptr [17 x i8]* @.strCmpEqFltU, i32 0, i32 0 + call void @failCheck( i1 %cmp_eq_ok, i8* %cmp_eq_em ) + + ; test fcmp::oge -- should return true if either operand is a NaN and the first is greater or equal + %cmp_ge = fcmp uge float %f1, %f2 + %cmp_ge_ok = icmp eq i1 %cmp_ge, %ge + %cmp_ge_em = getelementptr [17 x i8]* @.strCmpGeFltU, i32 0, i32 0 + call void @failCheck( i1 %cmp_ge_ok, i8* %cmp_ge_em ) + + ; test fcmp::ogt -- should return true if either operand is a NaN and the first is greater + %cmp_gt = fcmp ugt float %f1, %f2 + %cmp_gt_ok = icmp eq i1 %cmp_gt, %gt + %cmp_gt_em = getelementptr [17 x i8]* @.strCmpGtFltU, i32 0, i32 0 + call void @failCheck( i1 %cmp_gt_ok, i8* %cmp_gt_em ) + + ; test fcmp::ole -- should return true if either operand is a NaN and the first is less or equal + %cmp_le = fcmp ule float %f1, %f2 + %cmp_le_ok = icmp eq i1 %cmp_le, %le + %cmp_le_em = getelementptr [17 x i8]* @.strCmpLeFltU, i32 0, i32 0 + call void @failCheck( i1 %cmp_le_ok, i8* %cmp_le_em ) + + ; test fcmp::olt -- should return true if either operand is a NaN and the first is less + %cmp_lt = fcmp ult float %f1, %f2 + %cmp_lt_ok = icmp eq i1 %cmp_lt, %lt + %cmp_lt_em = getelementptr [17 x i8]* @.strCmpLtFltU, i32 0, i32 0 + call void @failCheck( i1 %cmp_lt_ok, i8* %cmp_lt_em ) + + ; test fcmp::one -- should return true if either operand is a NaN and they are not equal + %cmp_ne = fcmp une float %f1, %f2 + %cmp_ne_ok = icmp eq i1 %cmp_ne, %ne + %cmp_ne_em = getelementptr [17 x i8]* @.strCmpNeFltU, i32 0, i32 0 + call void @failCheck( i1 %cmp_ne_ok, i8* %cmp_ne_em ) + + ret void +} + +; test double comparisons (unordered) +define void @testFCmpDUnordered(double %d1, double %d2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %uno) { +entry: + ; test fcmp::uno -- should return true if either operand is NaN + %cmp_o = fcmp uno double %d1, %d2 + %cmp_o_ok = icmp eq i1 %cmp_o, %uno + %cmp_o_em = getelementptr [21 x i8]* @.strCmpUnoDbl, i32 0, i32 0 + call void @failCheck( i1 %cmp_o_ok, i8* %cmp_o_em ) + + ; test fcmp::ueq -- should return true if either operand is a NaN and they are equal + %cmp_eq = fcmp ueq double %d1, %d2 + %cmp_eq_ok = icmp eq i1 %cmp_eq, %eq + %cmp_eq_em = getelementptr [18 x i8]* @.strCmpEqDblU, i32 0, i32 0 + call void @failCheck( i1 %cmp_eq_ok, i8* %cmp_eq_em ) + + ; test fcmp::uge -- should return true if either operand is a NaN and the first is greater or equal + %cmp_ge = fcmp uge double %d1, %d2 + %cmp_ge_ok = icmp eq i1 %cmp_ge, %ge + %cmp_ge_em = getelementptr [18 x i8]* @.strCmpGeDblU, i32 0, i32 0 + call void @failCheck( i1 %cmp_ge_ok, i8* %cmp_ge_em ) + + ; test fcmp::ugt -- should return true if either operand is a NaN and the first is greater + %cmp_gt = fcmp ugt double %d1, %d2 + %cmp_gt_ok = icmp eq i1 %cmp_gt, %gt + %cmp_gt_em = getelementptr [18 x i8]* @.strCmpGtDblU, i32 0, i32 0 + call void @failCheck( i1 %cmp_gt_ok, i8* %cmp_gt_em ) + + ; test fcmp::ule -- should return true if either operand is a NaN and the first is less or equal + %cmp_le = fcmp ule double %d1, %d2 + %cmp_le_ok = icmp eq i1 %cmp_le, %le + %cmp_le_em = getelementptr [18 x i8]* @.strCmpLeDblU, i32 0, i32 0 + call void @failCheck( i1 %cmp_le_ok, i8* %cmp_le_em ) + + ; test fcmp::ult -- should return true if either operand is a NaN and the first is less + %cmp_lt = fcmp ult double %d1, %d2 + %cmp_lt_ok = icmp eq i1 %cmp_lt, %lt + %cmp_lt_em = getelementptr [18 x i8]* @.strCmpLtDblU, i32 0, i32 0 + call void @failCheck( i1 %cmp_lt_ok, i8* %cmp_lt_em ) + + ; test fcmp::une -- should return true if either operand is a NaN and they are not equal + %cmp_ne = fcmp une double %d1, %d2 + %cmp_ne_ok = icmp eq i1 %cmp_ne, %ne + %cmp_ne_em = getelementptr [18 x i8]* @.strCmpNeDblU, i32 0, i32 0 + call void @failCheck( i1 %cmp_ne_ok, i8* %cmp_ne_em ) + + ret void +} + +; test floating point comparisons (unordered) +define void @testFCmpBothUnordered(double %d1, double %d2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %uno) { +entry: + call void @testFCmpDUnordered( double %d1, double %d2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %uno ) + + %f1 = fptrunc double %d1 to float + %f2 = fptrunc double %d2 to float + call void @testFCmpFUnordered( float %f1, float %f2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %uno ) + + ret void +} + +; test floating point comparisons (ordered and unordered) +define void @testFCmpBoth(double %d1, double %d2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %ord, i1 %uno) { +entry: + call void @testFCmpBothOrdered( double %d1, double %d2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %ord ) + call void @testFCmpBothUnordered( double %d1, double %d2, i1 %eq, i1 %ge, i1 %gt, i1 %le, i1 %lt, i1 %ne, i1 %uno ) + + ret void +} + +; test floating point comparisons (ordered and unordered) with a variety of real numbers and NaNs as operands +define void @testFCmp() { +entry: + %x = alloca i64, align 8 + %nan = alloca double, align 8 + + ; test FCmp on some real number inputs + call void @testFCmpBoth( double 0.000000e+00, double 0.000000e+00, i1 1, i1 1, i1 0, i1 1, i1 0, i1 0, i1 1, i1 0 ) + call void @testFCmpBoth( double 0.000000e+00, double 1.000000e+00, i1 0, i1 0, i1 0, i1 1, i1 1, i1 1, i1 1, i1 0 ) + call void @testFCmpBoth( double 1.000000e+00, double 0.000000e+00, i1 0, i1 1, i1 1, i1 0, i1 0, i1 1, i1 1, i1 0 ) + + ; build NaN + store i64 -1, i64* %x + %nan_as_i8 = bitcast double* %nan to i8* + %x_as_i8 = bitcast i64* %x to i8* + call void @llvm.memcpy.i32( i8* %nan_as_i8, i8* %x_as_i8, i32 8, i32 8 ) + + ; load two copies of our NaN + %nan1 = load double* %nan + %nan2 = load double* %nan + + ; Warning: NaN comparisons with normal operators is BROKEN in LLVM JIT v2.0. Fixed in v2.1. + ; NaNs do different things depending on ordered vs unordered +; call void @testFCmpBothOrdered( double %nan1, double 0.000000e+00, i1 0, i1 0, i1 0, i1 0, i1 0, i1 0, i1 0 ) +; call void @testFCmpBothOrdered( double %nan1, double %nan2, i1 0, i1 0, i1 0, i1 0, i1 0, i1 0, i1 0 ) +; call void @testFCmpBothUnordered( double %nan1, double 0.000000e+00, i1 1, i1 1, i1 1, i1 1, i1 1, i1 1, i1 1 ) +; call void @testFCmpBothUnordered( double %nan1, double %nan2, i1 1, i1 1, i1 1, i1 1, i1 1, i1 1, i1 1 ) + + ret void +} + +; tes all floating point instructions +define i32 @main() { +entry: + call void @testFPTrunc( ) + call void @testFPExt( ) + call void @testFPToUI( ) + call void @testFPToSI( ) + call void @testUIToFP( ) + call void @testSIToFP( ) + + call void @testFDiv( ) + call void @testFRem( ) + call void @testAdd( ) + call void @testSub( ) + call void @testMul( ) + + call void @testFCmp( ) + + ; everything worked -- print a message saying so + %works_msg = getelementptr [20 x i8]* @.strWorks, i32 0, i32 0 + %err_stream = load %struct.stdout** @stdout + %ret = call i32 (%struct.stdout*, i8*, ...)* @fprintf( %struct.stdout* %err_stream, i8* %works_msg ) + + ret i32 0 +} diff --git a/test/Concrete/GlobalInitializers.ll b/test/Concrete/GlobalInitializers.ll new file mode 100755 index 00000000..b4d95de6 --- /dev/null +++ b/test/Concrete/GlobalInitializers.ll @@ -0,0 +1,47 @@ +; (cd .. && make) && ../llvm/Release/bin/llvm-as test.ll -o=- | ../Debug/bin/klee + +declare void @print_i32(i32) + +%simple = type { i8, i16, i32, i64 } +@gInt = global i32 2 +@gInts = global [2 x i32] [ i32 3, i32 5 ] +@gStruct = global %simple { i8 7, i16 11, i32 13, i64 17 } +@gZero = global %simple zeroinitializer + +define i32 @main() { +entry: + %addr0 = getelementptr i32* @gInt, i32 0 + %addr1 = getelementptr [2 x i32]* @gInts, i32 0, i32 0 + %addr2 = getelementptr [2 x i32]* @gInts, i32 0, i32 1 + %addr3 = getelementptr %simple* @gStruct, i32 0, i32 0 + %addr4 = getelementptr %simple* @gStruct, i32 0, i32 1 + %addr5 = getelementptr %simple* @gStruct, i32 0, i32 2 + %addr6 = getelementptr %simple* @gStruct, i32 0, i32 3 + %addr7 = getelementptr %simple* @gZero, i32 0, i32 2 + %contents0 = load i32* %addr0 + %contents1 = load i32* %addr1 + %contents2 = load i32* %addr2 + %contents3tmp = load i8* %addr3 + %contents3 = zext i8 %contents3tmp to i32 + %contents4tmp = load i16* %addr4 + %contents4 = zext i16 %contents4tmp to i32 + %contents5 = load i32* %addr5 + %contents6tmp = load i64* %addr6 + %contents6 = trunc i64 %contents6tmp to i32 + %contents7 = load i32* %addr7 + %tmp0 = mul i32 %contents0, %contents1 + %tmp1 = mul i32 %tmp0, %contents2 + %tmp2 = mul i32 %tmp1, %contents3 + %tmp3 = mul i32 %tmp2, %contents4 + %tmp4 = mul i32 %tmp3, %contents5 + %tmp5 = mul i32 %tmp4, %contents6 + %tmp6 = add i32 %tmp5, %contents7 + %p = icmp eq i32 %tmp5, 510510 + br i1 %p, label %exitTrue, label %exitFalse +exitTrue: + call void @print_i32(i32 1) + ret i32 0 +exitFalse: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/GlobalVariable.ll b/test/Concrete/GlobalVariable.ll new file mode 100644 index 00000000..d15df064 --- /dev/null +++ b/test/Concrete/GlobalVariable.ll @@ -0,0 +1,9 @@ +declare void @print_i32(i32) + +@anInt = global i32 1 +@aRef = global i32* @anInt + +define i32 @main() { + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/ICmp.ll b/test/Concrete/ICmp.ll new file mode 100644 index 00000000..e2a1ef24 --- /dev/null +++ b/test/Concrete/ICmp.ll @@ -0,0 +1,245 @@ +declare void @print_i32(i32) + +define i1 @checkSlt() { + %c0 = icmp slt i8 -1, 1 ; 1 + %c1 = icmp slt i8 0, 1 ; 1 + %c2 = icmp slt i8 1, 1 ; 0 + %c3 = icmp slt i8 1, -1 ; 0 + %c4 = icmp slt i8 1, 0 ; 0 + %c5 = icmp slt i8 1, 1 ; 0 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %a3 = select i1 %c3, i8 8, i8 0 + %a4 = select i1 %c4, i8 16, i8 0 + %a5 = select i1 %c5, i8 32, i8 0 + %sum0 = add i8 %a0, %a1 + %sum1 = add i8 %sum0, %a2 + %sum2 = add i8 %sum1, %a3 + %sum3 = add i8 %sum2, %a4 + %sum = add i8 %sum3, %a5 + %test = icmp eq i8 %sum, 3 ; 0bin000011 + ret i1 %test +} + +define i1 @checkSle() { + %c0 = icmp sle i8 -1, 1 ; 1 + %c1 = icmp sle i8 0, 1 ; 1 + %c2 = icmp sle i8 1, 1 ; 1 + %c3 = icmp sle i8 1, -1 ; 0 + %c4 = icmp sle i8 1, 0 ; 0 + %c5 = icmp sle i8 1, 1 ; 1 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %a3 = select i1 %c3, i8 8, i8 0 + %a4 = select i1 %c4, i8 16, i8 0 + %a5 = select i1 %c5, i8 32, i8 0 + %sum0 = add i8 %a0, %a1 + %sum1 = add i8 %sum0, %a2 + %sum2 = add i8 %sum1, %a3 + %sum3 = add i8 %sum2, %a4 + %sum = add i8 %sum3, %a5 + %test = icmp eq i8 %sum, 39 ; 0bin100111 + ret i1 %test +} + +define i1 @checkSgt() { + %c0 = icmp sgt i8 -1, 1 ; 0 + %c1 = icmp sgt i8 0, 1 ; 0 + %c2 = icmp sgt i8 1, 1 ; 0 + %c3 = icmp sgt i8 1, -1 ; 1 + %c4 = icmp sgt i8 1, 0 ; 1 + %c5 = icmp sgt i8 1, 1 ; 0 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %a3 = select i1 %c3, i8 8, i8 0 + %a4 = select i1 %c4, i8 16, i8 0 + %a5 = select i1 %c5, i8 32, i8 0 + %sum0 = add i8 %a0, %a1 + %sum1 = add i8 %sum0, %a2 + %sum2 = add i8 %sum1, %a3 + %sum3 = add i8 %sum2, %a4 + %sum = add i8 %sum3, %a5 + %test = icmp eq i8 %sum, 24 ; 0bin011000 + ret i1 %test +} + +define i1 @checkSge() { + %c0 = icmp sge i8 -1, 1 ; 0 + %c1 = icmp sge i8 0, 1 ; 0 + %c2 = icmp sge i8 1, 1 ; 1 + %c3 = icmp sge i8 1, -1 ; 1 + %c4 = icmp sge i8 1, 0 ; 1 + %c5 = icmp sge i8 1, 1 ; 1 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %a3 = select i1 %c3, i8 8, i8 0 + %a4 = select i1 %c4, i8 16, i8 0 + %a5 = select i1 %c5, i8 32, i8 0 + %sum0 = add i8 %a0, %a1 + %sum1 = add i8 %sum0, %a2 + %sum2 = add i8 %sum1, %a3 + %sum3 = add i8 %sum2, %a4 + %sum = add i8 %sum3, %a5 + %test = icmp eq i8 %sum, 60 ; 0bin111100 + ret i1 %test +} + +define i1 @checkUlt() { + %c0 = icmp ult i8 -1, 1 ; 0 + %c1 = icmp ult i8 0, 1 ; 1 + %c2 = icmp ult i8 1, 1 ; 0 + %c3 = icmp ult i8 1, -1 ; 1 + %c4 = icmp ult i8 1, 0 ; 0 + %c5 = icmp ult i8 1, 1 ; 0 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %a3 = select i1 %c3, i8 8, i8 0 + %a4 = select i1 %c4, i8 16, i8 0 + %a5 = select i1 %c5, i8 32, i8 0 + %sum0 = add i8 %a0, %a1 + %sum1 = add i8 %sum0, %a2 + %sum2 = add i8 %sum1, %a3 + %sum3 = add i8 %sum2, %a4 + %sum = add i8 %sum3, %a5 + %test = icmp eq i8 %sum, 10 ; 0bin001010 + ret i1 %test +} + +define i1 @checkUle() { + %c0 = icmp ule i8 -1, 1 ; 0 + %c1 = icmp ule i8 0, 1 ; 1 + %c2 = icmp ule i8 1, 1 ; 1 + %c3 = icmp ule i8 1, -1 ; 1 + %c4 = icmp ule i8 1, 0 ; 0 + %c5 = icmp ule i8 1, 1 ; 1 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %a3 = select i1 %c3, i8 8, i8 0 + %a4 = select i1 %c4, i8 16, i8 0 + %a5 = select i1 %c5, i8 32, i8 0 + %sum0 = add i8 %a0, %a1 + %sum1 = add i8 %sum0, %a2 + %sum2 = add i8 %sum1, %a3 + %sum3 = add i8 %sum2, %a4 + %sum = add i8 %sum3, %a5 + %test = icmp eq i8 %sum, 46 ; 0bin101110 + ret i1 %test +} + +define i1 @checkUgt() { + %c0 = icmp ugt i8 -1, 1 ; 1 + %c1 = icmp ugt i8 0, 1 ; 0 + %c2 = icmp ugt i8 1, 1 ; 0 + %c3 = icmp ugt i8 1, -1 ; 0 + %c4 = icmp ugt i8 1, 0 ; 1 + %c5 = icmp ugt i8 1, 1 ; 0 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %a3 = select i1 %c3, i8 8, i8 0 + %a4 = select i1 %c4, i8 16, i8 0 + %a5 = select i1 %c5, i8 32, i8 0 + %sum0 = add i8 %a0, %a1 + %sum1 = add i8 %sum0, %a2 + %sum2 = add i8 %sum1, %a3 + %sum3 = add i8 %sum2, %a4 + %sum = add i8 %sum3, %a5 + %test = icmp eq i8 %sum, 17 ; 0bin010001 + ret i1 %test +} + +define i1 @checkUge() { + %c0 = icmp uge i8 -1, 1 ; 1 + %c1 = icmp uge i8 0, 1 ; 0 + %c2 = icmp uge i8 1, 1 ; 1 + %c3 = icmp uge i8 1, -1 ; 0 + %c4 = icmp uge i8 1, 0 ; 1 + %c5 = icmp uge i8 1, 1 ; 1 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %a3 = select i1 %c3, i8 8, i8 0 + %a4 = select i1 %c4, i8 16, i8 0 + %a5 = select i1 %c5, i8 32, i8 0 + %sum0 = add i8 %a0, %a1 + %sum1 = add i8 %sum0, %a2 + %sum2 = add i8 %sum1, %a3 + %sum3 = add i8 %sum2, %a4 + %sum = add i8 %sum3, %a5 + %test = icmp eq i8 %sum, 53 ; 0bin110101 + ret i1 %test +} + +define i1 @checkEq() { + %c0 = icmp eq i8 -1, 1 ; 0 + %c1 = icmp eq i8 1, 1 ; 1 + %c2 = icmp eq i8 1, -1 ; 0 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %sum0 = add i8 %a0, %a1 + %sum = add i8 %sum0, %a2 + %test = icmp eq i8 %sum, 2 + ret i1 %test +} + +define i1 @checkNe() { + %c0 = icmp ne i8 -1, 1 ; 1 + %c1 = icmp ne i8 1, 1 ; 0 + %c2 = icmp ne i8 1, -1 ; 1 + %a0 = select i1 %c0, i8 1, i8 0 + %a1 = select i1 %c1, i8 2, i8 0 + %a2 = select i1 %c2, i8 4, i8 0 + %sum0 = add i8 %a0, %a1 + %sum = add i8 %sum0, %a2 + %test = icmp eq i8 %sum, 5 + ret i1 %test +} + +define i32 @main() { + %c0 = call i1 @checkSlt () + %c1 = call i1 @checkSle () + %c2 = call i1 @checkSgt () + %c3 = call i1 @checkSge () + %c4 = call i1 @checkUlt () + %c5 = call i1 @checkUle () + %c6 = call i1 @checkUgt () + %c7 = call i1 @checkUge () + %c8 = call i1 @checkEq () + %c9 = call i1 @checkNe () + %a0 = select i1 %c0, i16 1, i16 0 + %a1 = select i1 %c1, i16 2, i16 0 + %a2 = select i1 %c2, i16 4, i16 0 + %a3 = select i1 %c3, i16 8, i16 0 + %a4 = select i1 %c4, i16 16, i16 0 + %a5 = select i1 %c5, i16 32, i16 0 + %a6 = select i1 %c6, i16 64, i16 0 + %a7 = select i1 %c7, i16 128, i16 0 + %a8 = select i1 %c8, i16 256, i16 0 + %a9 = select i1 %c9, i16 512, i16 0 + %sum0 = add i16 %a0, %a1 + %sum1 = add i16 %sum0, %a2 + %sum2 = add i16 %sum1, %a3 + %sum3 = add i16 %sum2, %a4 + %sum4 = add i16 %sum3, %a5 + %sum5 = add i16 %sum4, %a6 + %sum6 = add i16 %sum5, %a7 + %sum7 = add i16 %sum6, %a8 + %sum8 = add i16 %sum7, %a9 + %t = shl i16 63, 10 + %sum = add i16 %sum8, %t + %test = icmp eq i16 %sum, -1 + br i1 %test, label %exitTrue, label %exitFalse +exitTrue: + call void @print_i32(i32 1) + ret i32 0 +exitFalse: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/InvokeAndReturn.ll b/test/Concrete/InvokeAndReturn.ll new file mode 100644 index 00000000..f73c242a --- /dev/null +++ b/test/Concrete/InvokeAndReturn.ll @@ -0,0 +1,18 @@ +declare void @print_i32(i32) + +define i8 @sum(i8 %a, i8 %b) { + %c = add i8 %a, %b + ret i8 %c +} + +define i32 @main() { + invoke i8 @sum(i8 1, i8 2) + to label %continue + unwind label %error +continue: + call void @print_i32(i32 1) + ret i32 0 +error: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/InvokeAndUnwindOnce.ll b/test/Concrete/InvokeAndUnwindOnce.ll new file mode 100644 index 00000000..2834ec82 --- /dev/null +++ b/test/Concrete/InvokeAndUnwindOnce.ll @@ -0,0 +1,18 @@ +declare void @print_i32(i32) + +define i8 @sum(i8 %a, i8 %b) { + %c = add i8 %a, %b + unwind +} + +define i32 @main() { + invoke i8 @sum(i8 1, i8 2) + to label %continue + unwind label %error +continue: + call void @print_i32(i32 1) + ret i32 0 +error: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/InvokeAndUnwindTwice.ll b/test/Concrete/InvokeAndUnwindTwice.ll new file mode 100644 index 00000000..81760b86 --- /dev/null +++ b/test/Concrete/InvokeAndUnwindTwice.ll @@ -0,0 +1,22 @@ +declare void @print_i32(i32) + +define i8 @myadd(i8 %a, i8 %b) { + unwind +} + +define i8 @sum(i8 %a, i8 %b) { + %c = call i8 @myadd(i8 %a, i8 %b) + ret i8 %c +} + +define i32 @main() { + invoke i8 @sum(i8 1, i8 2) + to label %continue + unwind label %error +continue: + call void @print_i32(i32 1) + ret i32 0 +error: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/Makefile b/test/Concrete/Makefile new file mode 100644 index 00000000..4acfadad --- /dev/null +++ b/test/Concrete/Makefile @@ -0,0 +1,55 @@ +LEVEL = ../.. + +# hard-coding bad. will get fixed. +LCCFLAGS += -O0 -Wall +LCXXFLAGS += -O0 -Wall +LLCFLAGS = + +test: + ./ConcreteTest.py + +clean:: + -rm -rf Output klee-last klee-out* test.log + -rm -rf *.bc + +# We do not want to make .d files for tests! +DISABLE_AUTO_DEPENDENCIES=1 + +include ${LEVEL}/Makefile.common + +# Compile from X.c to Output/X.ll +Output/%.ll: %.c $(LCC1) Output/.dir $(INCLUDES) + $(LLVMGCCWITHPATH) --emit-llvm $(CPPFLAGS) $(LCCFLAGS) -S $< -o $@ + +# Compile from X.cpp to Output/X.ll +Output/%.ll: %.cpp $(LCC1XX) Output/.dir $(INCLUDES) + $(LLVMGXXWITHPATH) --emit-llvm $(CPPFLAGS) $(LCXXFLAGS) -S $< -o $@ + +# Compile from X.cc to Output/X.ll +Output/%.ll: %.cc $(LCC1XX) Output/.dir $(INCLUDES) + $(LLVMGXXWITHPATH) --emit-llvm $(CPPFLAGS) $(LCXXFLAGS) -S $< -o $@ + +# LLVM Assemble from Output/X.ll to Output/X.bc. Output/X.ll must have come +# from GCC output, so use GCCAS. +# +Output/%.bc: Output/%.ll $(LLVMAS) + $(LLVMAS) -f $< -o $@ + +# LLVM Assemble from X.ll to Output/X.bc. Because we are coming directly from +# LLVM source, use the non-transforming assembler. +# +Output/%.bc: %.ll $(LLVMAS) Output/.dir + $(LLVMAS) -f $< -o $@ + +Output/linked_%.bc: Output/%.bc Output/_testingUtils.bc + $(LLVMLD) -disable-opt -link-as-library Output/_testingUtils.bc $< -o $@ + +.PRECIOUS: Output/.dir + +## Cancel built-in implicit rules that override above rules +%: %.s + +%: %.c + +%.o: %.c + diff --git a/test/Concrete/OneCall.ll b/test/Concrete/OneCall.ll new file mode 100644 index 00000000..d8b94b37 --- /dev/null +++ b/test/Concrete/OneCall.ll @@ -0,0 +1,12 @@ +declare void @print_i32(i32) + +define i32 @sum(i32 %a, i32 %b) { + %c = sub i32 %a, %b + ret i32 %c +} + +define i32 @main() { + %a = call i32 @sum(i32 54, i32 2) + call void @print_i32(i32 %a) + ret i32 0 +} diff --git a/test/Concrete/OverlappingPhiNodes.ll b/test/Concrete/OverlappingPhiNodes.ll new file mode 100644 index 00000000..d3dc76ab --- /dev/null +++ b/test/Concrete/OverlappingPhiNodes.ll @@ -0,0 +1,15 @@ +declare void @print_i32(i32) + +define i32 @main() { +entry: + br label %test +test: + %a = phi i32 [10, %entry], [%b, %test] + %b = phi i32 [20, %entry], [%a, %test] + %c = phi i32 [0, %entry], [1, %test] + %d = icmp eq i32 %c, 1 + br i1 %d, label %exit, label %test +exit: + call void @print_i32(i32 %b) + ret i32 0 +} diff --git a/test/Concrete/Select.ll b/test/Concrete/Select.ll new file mode 100644 index 00000000..29b81e3e --- /dev/null +++ b/test/Concrete/Select.ll @@ -0,0 +1,15 @@ +declare void @print_i32(i32) + +define i32 @main() { + %ten = select i1 true, i32 10, i32 0 + %five = select i1 false, i32 0, i32 5 + %check = add i32 %ten, %five + %test = icmp eq i32 %check, 15 + br i1 %test, label %exitTrue, label %exitFalse +exitTrue: + call void @print_i32(i32 1) + ret i32 0 +exitFalse: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/Shifts.ll b/test/Concrete/Shifts.ll new file mode 100644 index 00000000..2430f879 --- /dev/null +++ b/test/Concrete/Shifts.ll @@ -0,0 +1,21 @@ +declare void @print_i32(i32) + +define i32 @main() { + %amt = add i8 2, 5 + %a = shl i8 1, 5 + %b = lshr i8 %a, 5 + %c = shl i8 %b, %amt + %d = lshr i8 %c, %amt + %e = shl i8 %d, 7 + %f = ashr i8 %e, 7 + %g = shl i8 %f, %amt + %h = ashr i8 %g, %amt + %test = icmp eq i8 %h, -1 + br i1 %test, label %exitTrue, label %exitFalse +exitTrue: + call void @print_i32(i32 1) + ret i32 0 +exitFalse: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/SimpleStoreAndLoad.ll b/test/Concrete/SimpleStoreAndLoad.ll new file mode 100644 index 00000000..0201ba15 --- /dev/null +++ b/test/Concrete/SimpleStoreAndLoad.ll @@ -0,0 +1,17 @@ +declare void @print_i32(i32) + +define i32 @main() { +entry: + %a = alloca i32, i32 4 + %tmp1 = getelementptr i32* %a, i32 0 + store i32 0, i32* %tmp1 + %tmp2 = load i32* %tmp1 + %tmp3 = icmp eq i32 %tmp2, 0 + br i1 %tmp3, label %exitTrue, label %exitFalse +exitTrue: + call void @print_i32(i32 1) + ret i32 0 +exitFalse: + call void @print_i32(i32 0) + ret i32 0 +} diff --git a/test/Concrete/UnconditionalBranch.ll b/test/Concrete/UnconditionalBranch.ll new file mode 100644 index 00000000..81e2f931 --- /dev/null +++ b/test/Concrete/UnconditionalBranch.ll @@ -0,0 +1,10 @@ +declare void @print_i32(i32) + +define i32 @main() { +entry: + %a = add i32 0, 1 + br label %exit +exit: + call void @print_i32(i32 %a) + ret i32 0 +} diff --git a/test/Concrete/UnconditionalBranchWithSimplePhi.ll b/test/Concrete/UnconditionalBranchWithSimplePhi.ll new file mode 100644 index 00000000..551ddf5d --- /dev/null +++ b/test/Concrete/UnconditionalBranchWithSimplePhi.ll @@ -0,0 +1,14 @@ +declare void @print_i32(i32) + +define i32 @main() { +entry: + %a = add i32 0, 1 + br label %exit +unused: + %b = add i32 1, 2 + br label %exit +exit: + %c = phi i32 [%a, %entry], [%b, %unused] + call void @print_i32(i32 %c) + ret i32 0 +} diff --git a/test/Concrete/UnorderedPhiNodes.ll b/test/Concrete/UnorderedPhiNodes.ll new file mode 100644 index 00000000..3ecd5083 --- /dev/null +++ b/test/Concrete/UnorderedPhiNodes.ll @@ -0,0 +1,15 @@ +declare void @print_i32(i32) + +define i32 @main() { +entry: + br label %test +test: + %a = phi i32 [10, %entry], [%b, %test] + %b = phi i32 [%a, %test], [20, %entry] + %c = phi i32 [0, %entry], [1, %test] + %d = icmp eq i32 %c, 1 + br i1 %d, label %exit, label %test +exit: + call void @print_i32(i32 %b) + ret i32 0 +} diff --git a/test/Concrete/_testingUtils.c b/test/Concrete/_testingUtils.c new file mode 100644 index 00000000..02d0529e --- /dev/null +++ b/test/Concrete/_testingUtils.c @@ -0,0 +1,32 @@ +int putchar(int x); + +void print_int(unsigned long long val); + +#define TYPED_PRINT(_name_type, _arg_type) \ + void print_ ## _name_type(_arg_type val) { print_int(val); } + +TYPED_PRINT(i1, unsigned char) +TYPED_PRINT(i8, unsigned char) +TYPED_PRINT(i16, unsigned short) +TYPED_PRINT(i32, unsigned int) +TYPED_PRINT(i64, unsigned long long) + +void print_int(unsigned long long val) { + int cur = 1; + + // effectively do a log (can't call log because it returns floats) + // do the nasty divide to prevent overflow + while (cur <= val / 10) + cur *= 10; + + while (cur) { + int digit = val / cur; + + putchar(digit + '0'); + + val = val % cur; + cur /= 10; + } + + putchar('\n'); +} diff --git a/test/Concrete/ackermann.c b/test/Concrete/ackermann.c new file mode 100644 index 00000000..0f21a3ab --- /dev/null +++ b/test/Concrete/ackermann.c @@ -0,0 +1,16 @@ +// llvm-gcc -O2 --emit-llvm -c ackermann.c && ../../Debug/bin/klee ackermann.o 2 2 + +#include <stdio.h> + +int ackermann(int m, int n) { + if (m == 0) + return n+1; + else + return ackermann(m-1, (n==0) ? 1 : ackermann(m, n-1)); + } + +int main() { + printf("ackerman(%d, %d) = %d\n", 2, 2, ackermann(2, 2)); + + return 0; +} diff --git a/test/Concrete/arith_test.ll b/test/Concrete/arith_test.ll new file mode 100644 index 00000000..5624462b --- /dev/null +++ b/test/Concrete/arith_test.ll @@ -0,0 +1,76 @@ +define void @"test_simple_arith"(i16 %i0, i16 %j0) +begin + %t1 = add i16 %i0, %j0 + %t2 = sub i16 %i0, %j0 + %t3 = mul i16 %t1, %t2 + + call void @print_i16(i16 %t3) + + ret void +end + +define void @"test_div_and_mod"(i16 %op1, i16 %op2) +begin + %t1 = udiv i16 %op1, %op2 + %t2 = urem i16 %op1, %op2 + %t3 = sdiv i16 %op1, %op2 + %t4 = srem i16 %op1, %op2 + + call void @print_i16(i16 %t1) + call void @print_i16(i16 %t2) + call void @print_i16(i16 %t3) + call void @print_i16(i16 %t4) + + ret void +end + +define void @test_cmp(i16 %op1, i16 %op2) +begin + %t1 = icmp ule i16 %op1, %op2 + %t2 = icmp ult i16 %op1, %op2 + %t3 = icmp uge i16 %op1, %op2 + %t4 = icmp ugt i16 %op1, %op2 + %t6 = icmp slt i16 %op1, %op2 + %t5 = icmp sle i16 %op1, %op2 + %t7 = icmp sge i16 %op1, %op2 + %t8 = icmp sgt i16 %op1, %op2 + %t9 = icmp eq i16 %op1, %op2 + %t10 = icmp ne i16 %op1, %op2 + + call void @print_i1(i1 %t1) + call void @print_i1(i1 %t2) + call void @print_i1(i1 %t3) + call void @print_i1(i1 %t4) + call void @print_i1(i1 %t5) + call void @print_i1(i1 %t6) + call void @print_i1(i1 %t7) + call void @print_i1(i1 %t8) + call void @print_i1(i1 %t9) + call void @print_i1(i1 %t10) + + ret void +end + +define i32 @main() +begin + call void @test_simple_arith(i16 111, i16 100) + + call void @test_div_and_mod(i16 63331, i16 3123) + call void @test_div_and_mod(i16 1000, i16 55444) + call void @test_div_and_mod(i16 49012, i16 55444) + call void @test_div_and_mod(i16 1000, i16 25) + + call void @test_cmp(i16 63331, i16 3123) + call void @test_cmp(i16 1000, i16 55444) + call void @test_cmp(i16 49012, i16 55444) + call void @test_cmp(i16 1000, i16 25) + + ret i32 0 +end + +; defined in print_int.c +declare void @print_i1(i1) +declare void @print_i8(i8) +declare void @print_i16(i16) +declare void @print_i32(i32) +declare void @print_i64(i64) diff --git a/test/Coverage/ReadArgs.c b/test/Coverage/ReadArgs.c new file mode 100644 index 00000000..7ebf056e --- /dev/null +++ b/test/Coverage/ReadArgs.c @@ -0,0 +1,9 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: rm -rf xxx +// RUN: echo " --output-dir=xxx " > %t1.args +// RUN: %klee --read-args %t1.args %t1.bc +// RUN: test -d xxx + +int main() { + return 0; +} diff --git a/test/Coverage/ReplayOutDir.c b/test/Coverage/ReplayOutDir.c new file mode 100644 index 00000000..3ca6fb80 --- /dev/null +++ b/test/Coverage/ReplayOutDir.c @@ -0,0 +1,11 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: rm -rf %t1.out %t1.replay +// RUN: %klee --output-dir=%t1.out %t1.bc +// RUN: %klee --output-dir=%t1.replay --replay-out-dir=%t1.out %t1.bc + +int main() { + int i; + klee_make_symbolic(&i, sizeof i); + klee_print_range("i", i); + return 0; +} diff --git a/test/Coverage/dg.exp b/test/Coverage/dg.exp new file mode 100644 index 00000000..879685ca --- /dev/null +++ b/test/Coverage/dg.exp @@ -0,0 +1,3 @@ +load_lib llvm.exp + +RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Dogfood/ImmutableSet.cpp b/test/Dogfood/ImmutableSet.cpp new file mode 100644 index 00000000..7b816de4 --- /dev/null +++ b/test/Dogfood/ImmutableSet.cpp @@ -0,0 +1,134 @@ +// RUN: llvm-g++ -I../../../include -g -DMAX_ELEMENTS=4 -fno-exceptions --emit-llvm -c -o %t1.bc %s +// RUN: %klee --libc=klee --max-forks=200 --no-output --exit-on-error --optimize --disable-inlining --use-non-uniform-random-search --use-cex-cache %t1.bc + +#include "klee/klee.h" +#include "klee/Internal/ADT/ImmutableSet.h" + +using namespace klee; + +typedef ImmutableSet<unsigned> T; + +bool iff(bool a, bool b) { + return !!a == !!b; +} + +template<typename InputIterator, typename T> +bool contains(InputIterator begin, InputIterator end, T item) { + for (; begin!=end; ++begin) + if (*begin == item) + return true; + return false; +} + +bool equal(T &a, T &b) { + T::iterator aIt=a.begin(), ae=a.end(), bIt=b.begin(), be=b.end(); + for (; aIt!=ae && bIt!=be; ++aIt, ++bIt) + if (*aIt != *bIt) + return false; + if (aIt!=ae) return false; + if (bIt!=be) return false; + return true; +} + +template<typename InputIterator, typename T> +void remove(InputIterator begin, InputIterator end, T item) { + InputIterator out = begin; + for (; begin!=end; ++begin) { + if (*begin!=item) { + if (out!=begin) + *out = *begin; + ++out; + } + } +} + +void check_set(T &set, unsigned num, unsigned *values) { + assert(set.size() == num); + + // must contain only values + unsigned item = klee_range(0, 256, "range"); + assert(iff(contains(values, values+num, item), + set.count(item))); + + // each value must be findable, must be its own lower bound, and + // must be one behind its upper bound + for (unsigned i=0; i<num; i++) { + unsigned item = values[i]; + assert(set.count(item)); + T::iterator it = set.find(item); + T::iterator lb = set.lower_bound(item); + T::iterator ub = set.upper_bound(item); + assert(it != set.end()); // must exit + assert(*it == item); // must be itself + assert(lb == it); // must be own lower bound + assert(--ub == it); // must be one behind upper + } + + // for items not in the set... + unsigned item2 = klee_range(0, 256, "range"); + if (!set.count(item2)) { + assert(set.find(item2) == set.end()); + + T::iterator lb = set.lower_bound(item2); + for (T::iterator it=set.begin(); it!=lb; ++it) + assert(*it < item2); + for (T::iterator it=lb, ie=set.end(); it!=ie; ++it) + assert(*it >= item2); + + T::iterator ub = set.upper_bound(item2); + for (T::iterator it=set.begin(); it!=ub; ++it) + assert(*it <= item2); + for (T::iterator it=ub, ie=set.end(); it!=ie; ++it) + assert(*it > item2); + } +} + +#ifndef MAX_ELEMENTS +#define MAX_ELEMENTS 4 +#endif + +void test() { + unsigned num=0, values[MAX_ELEMENTS]; + T set; + + assert(MAX_ELEMENTS >= 0); + for (unsigned i=0; i<klee_range(0,MAX_ELEMENTS+1, "range"); i++) { + unsigned item = klee_range(0, 256, "range"); + if (contains(values, values+num, item)) + klee_silent_exit(0); + + set = set.insert(item); + values[num++] = item; + } + + check_set(set, num, values); + + unsigned item = klee_range(0, 256, "range"); + if (contains(values, values+num, item)) { // in tree + // insertion is invariant + T set2 = set.insert(item); + assert(equal(set2, set)); + + // check remove + T set3 = set.remove(item); + assert(!equal(set3, set)); // mostly just for coverage + assert(set3.size() + 1 == set.size()); + assert(!set3.count(item)); + } else { // not in tree + // removal is invariant + T set2 = set.remove(item); + assert(equal(set2, set)); + + // check insert + T set3 = set.insert(item); + assert(!equal(set3, set)); // mostly just for coverage + assert(set3.size() == set.size() + 1); + assert(set3.count(item)); + } +} + +int main(int argc, char **argv) { + test(); + assert(T::getAllocated() == 0); + return 0; +} diff --git a/test/Dogfood/dg.exp b/test/Dogfood/dg.exp new file mode 100644 index 00000000..879685ca --- /dev/null +++ b/test/Dogfood/dg.exp @@ -0,0 +1,3 @@ +load_lib llvm.exp + +RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Expr/dg.exp b/test/Expr/dg.exp new file mode 100644 index 00000000..879685ca --- /dev/null +++ b/test/Expr/dg.exp @@ -0,0 +1,3 @@ +load_lib llvm.exp + +RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Feature/Alias.c b/test/Feature/Alias.c new file mode 100644 index 00000000..9300e2c7 --- /dev/null +++ b/test/Feature/Alias.c @@ -0,0 +1,25 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc + +// Darwin does not have strong aliases. +// XFAIL: darwin + +#include <assert.h> + +// alias for global +int b = 52; +extern int a __attribute__((alias("b"))); + +// alias for function +int __foo() { return 52; } +extern int foo() __attribute__((alias("__foo"))); + +int *c = &a; + +int main() { + assert(a == 52); + assert(foo() == 52); + assert(*c == 52); + + return 0; +} diff --git a/test/Feature/AliasFunction.c b/test/Feature/AliasFunction.c new file mode 100644 index 00000000..e7acfc19 --- /dev/null +++ b/test/Feature/AliasFunction.c @@ -0,0 +1,33 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc > %t1.log +// RUN: grep -c foo %t1.log | grep 5 +// RUN: grep -c bar %t1.log | grep 3 + +#include <stdio.h> +#include <stdlib.h> + +void foo() { printf(" foo()\n"); } +void bar() { printf(" bar()\n"); } + +int main() { + int x; + klee_make_symbolic_name(&x, sizeof(x), "x"); + + // no aliases + foo(); + + if (x > 10) + { + // foo -> bar + klee_alias_function("foo", "bar"); + + if (x > 20) + foo(); + } + + foo(); + + // undo + klee_alias_function("foo", "foo"); + foo(); +} diff --git a/test/Feature/AliasFunctionExit.c b/test/Feature/AliasFunctionExit.c new file mode 100644 index 00000000..fcaf7e6c --- /dev/null +++ b/test/Feature/AliasFunctionExit.c @@ -0,0 +1,30 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc > %t1.log +// RUN: grep -c START %t1.log | grep 1 +// RUN: grep -c END %t1.log | grep 2 + +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> + +void start(int x) { + printf("START\n"); + if (x == 53) + exit(1); +} + +void end(int status) { + klee_alias_function("exit", "exit"); + printf("END: status = %d\n", status); + exit(status); +} + + +int main() { + int x; + klee_make_symbolic_name(&x, sizeof(x), "x"); + + klee_alias_function("exit", "end"); + start(x); + end(0); +} diff --git a/test/Feature/AsmAddresses.c b/test/Feature/AsmAddresses.c new file mode 100644 index 00000000..a58fc059 --- /dev/null +++ b/test/Feature/AsmAddresses.c @@ -0,0 +1,22 @@ +// RUN: %llvmgcc -g -c -o %t.bc %s +// RUN: %klee --exit-on-error --use-asm-addresses %t.bc +// RUN: %llvmgcc -DOVERLAP -g -c -o %t.bc %s +// RUN: not %klee --exit-on-error --use-asm-addresses %t.bc + +#include <assert.h> + + +volatile unsigned char x0 __asm ("0x0021"); +volatile unsigned char whee __asm ("0x0WHEE"); + +#ifdef OVERLAP +volatile unsigned int y0 __asm ("0x0030"); +volatile unsigned int y1 __asm ("0x0032"); +#endif + +int main() { + assert(&x0 == (void*) 0x0021); + assert(&whee != (void*) 0x0); + + return 0; +} diff --git a/test/Feature/ByteSwap.c b/test/Feature/ByteSwap.c new file mode 100644 index 00000000..f85ac3b1 --- /dev/null +++ b/test/Feature/ByteSwap.c @@ -0,0 +1,16 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --libc=klee --exit-on-error %t1.bc + +#include <arpa/inet.h> +#include <assert.h> + +int main() { + + uint32_t n = 0; + klee_make_symbolic(&n, sizeof(n)); + + uint32_t h = ntohl(n); + assert(htonl(h) == n); + + return 0; +} diff --git a/test/Feature/CallToUndefinedExternal.cpp b/test/Feature/CallToUndefinedExternal.cpp new file mode 100644 index 00000000..2f11f29d --- /dev/null +++ b/test/Feature/CallToUndefinedExternal.cpp @@ -0,0 +1,11 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: test -f klee-last/test000001.external.err + +extern "C" void poof(void); + +int main() { + poof(); + + return 0; +} diff --git a/test/Feature/CheckForImpliedValue.c.failing b/test/Feature/CheckForImpliedValue.c.failing new file mode 100644 index 00000000..7a088354 --- /dev/null +++ b/test/Feature/CheckForImpliedValue.c.failing @@ -0,0 +1,23 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: rm -f %t1.log +// RUN: %klee --log-file %t1.log --debug-check-for-implied-values %t1.bc +// RUN: grep "= 0 (ok)" %t1.log +// RUN: grep "= 2 (missed)" %t1.log + +#define swap(x) (((x)>>16) | (((x)&0xFFFF)<<16)) +int main() { + unsigned x, y; + + klee_make_symbolic(&x, sizeof x); + klee_make_symbolic(&y, sizeof y); + + if (!x) { // should give x = 0 hit by ivc + printf("ok\n"); + } else { + if (swap(y) == 0x00020000) { // should give y = 2 missed by ivc + printf("ok\n"); + } + } + + return 0; +} diff --git a/test/Feature/CheckMemoryAccess.c b/test/Feature/CheckMemoryAccess.c new file mode 100644 index 00000000..dd6e8745 --- /dev/null +++ b/test/Feature/CheckMemoryAccess.c @@ -0,0 +1,26 @@ +// RUN: %llvmgcc -g -c %s -o %t.bc +// RUN: %klee %t.bc > %t.log +// RUN: grep -q "good" %t.log +// RUN: not grep -q "bad" %t.log + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +int main() { + char buf[4]; + + klee_check_memory_access(&buf, 1); + printf("good\n"); + if (klee_range(0, 2, "range1")) { + klee_check_memory_access(0, 1); + printf("null pointer deref: bad\n"); + } + + if (klee_range(0, 2, "range2")) { + klee_check_memory_access(buf, 5); + printf("oversize access: bad\n"); + } + + return 0; +} diff --git a/test/Feature/CopyOnWrite.c b/test/Feature/CopyOnWrite.c new file mode 100644 index 00000000..ee3ea15e --- /dev/null +++ b/test/Feature/CopyOnWrite.c @@ -0,0 +1,26 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee --use-random-search --exit-on-error %t1.bc + +#include <assert.h> + +#define N 5 + +unsigned branches = 0; + +void explode(int *ap, int i, int *result) { + if (i<N) { + (*result)++; + if (ap[i]) // just cause a fork + branches++; + return explode(ap, i+1, result); + } +} + +int main() { + int result = 0; + int a[N]; + klee_make_symbolic(a, sizeof a); + explode(a,0,&result); + assert(result==N); + return 0; +} diff --git a/test/Feature/DanglingConcreteReadExpr.c b/test/Feature/DanglingConcreteReadExpr.c new file mode 100644 index 00000000..1bf44c3f --- /dev/null +++ b/test/Feature/DanglingConcreteReadExpr.c @@ -0,0 +1,22 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: grep "total queries = 2" klee-last/info + +#include <assert.h> + +int main() { + unsigned char x, y; + + klee_make_symbolic(&x, sizeof x); + + y = x; + + // should be exactly two queries (prove x is/is not 10) + // eventually should be 0 when we have fast solver + if (x==10) { + assert(y==10); + } + + klee_silent_exit(0); + return 0; +} diff --git a/test/Feature/DefineFixedObject.c b/test/Feature/DefineFixedObject.c new file mode 100644 index 00000000..36822434 --- /dev/null +++ b/test/Feature/DefineFixedObject.c @@ -0,0 +1,17 @@ +// RUN: %llvmgcc -c -o %t1.bc %s +// RUN: %klee --exit-on-error %t1.bc + +#include <stdio.h> + +#define ADDRESS ((int*) 0x0080) + +int main() { + klee_define_fixed_object(ADDRESS, 4); + + int *p = ADDRESS; + + *p = 10; + printf("*p: %d\n", *p); + + return 0; +} diff --git a/test/Feature/DoubleFree.c b/test/Feature/DoubleFree.c new file mode 100644 index 00000000..3727ef2b --- /dev/null +++ b/test/Feature/DoubleFree.c @@ -0,0 +1,10 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: test -f klee-last/test000001.ptr.err + +int main() { + int *x = malloc(4); + free(x); + free(x); + return 0; +} diff --git a/test/Feature/DumpStatesOnHalt.c b/test/Feature/DumpStatesOnHalt.c new file mode 100644 index 00000000..7e9cf46a --- /dev/null +++ b/test/Feature/DumpStatesOnHalt.c @@ -0,0 +1,8 @@ +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --stop-after-n-instructions=1 --dump-states-on-halt=true %t1.bc +// RUN: test -f klee-last/test000001.bout + +int main() { + int x = 10; + return x; +} diff --git a/test/Feature/Envp.c b/test/Feature/Envp.c new file mode 100644 index 00000000..f1f62a72 --- /dev/null +++ b/test/Feature/Envp.c @@ -0,0 +1,18 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc + +#include <assert.h> + +int main(int argc, char **argv, char **envp) { + unsigned i; + assert(argv[argc] == 0); + printf("argc: %d, argv: %p, envp: %p\n", argc, argv, envp); + printf("--environ--\n"); + int haspwd = 0; + for (i=0; envp[i]; i++) { + printf("%d: %s\n", i, envp[i]); + haspwd |= strncmp(envp[i], "PWD=", 4)==0; + } + assert(haspwd); + return 0; +} diff --git a/test/Feature/ExprLogging.c b/test/Feature/ExprLogging.c new file mode 100644 index 00000000..2abf0070 --- /dev/null +++ b/test/Feature/ExprLogging.c @@ -0,0 +1,43 @@ +// RUN: %llvmgcc %s -emit-llvm -g -O0 -c -o %t1.bc +// RUN: %klee --use-query-pc-log --write-pcs --write-cvcs %t1.bc 2> %t2.log +// RUN: %kleaver -print-ast klee-last/test000001.pc + +// FIXME: Ideally we would verify a roundtrip that we parsed the pc +// file and can dump it back out as the same file. + +#include <assert.h> + +int constantArr[16 ] = { + 1 << 0, 1 << 1, 1 << 2, 1 << 3, + 1 << 4, 1 << 5, 1 << 6, 1 << 7, + 1 << 8, 1 << 9, 1 << 10, 1 << 11, + 1 << 12, 1 << 13, 1 << 14, 1 << 15 +}; + + +int main() { + char buf[4]; + klee_make_symbolic(buf, sizeof buf); + + buf[1] = 'a'; + + constantArr[klee_range(0, 16, "idx.0")] = buf[0]; + + // Use this to trigger an interior update list usage. + int y = constantArr[klee_range(0, 16, "idx.1")]; + + constantArr[klee_range(0, 16, "idx.2")] = buf[3]; + + buf[klee_range(0, 4, "idx.3")] = 0; + klee_assume(buf[0] == 'h'); + + int x = *((int*) buf); + klee_assume(x > 2); + klee_assume(x == constantArr[12]); + + klee_assume(y != (1 << 5)); + + assert(0); + + return 0; +} diff --git a/test/Feature/ExternalWeakLinkage.c b/test/Feature/ExternalWeakLinkage.c new file mode 100644 index 00000000..c2008136 --- /dev/null +++ b/test/Feature/ExternalWeakLinkage.c @@ -0,0 +1,11 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc + +#include <assert.h> + +void __attribute__((weak)) IAmSoWeak(int); + +int main() { + assert(IAmSoWeak==0); + return 0; +} diff --git a/test/Feature/FunctionPointer.c b/test/Feature/FunctionPointer.c new file mode 100644 index 00000000..e1ae1e37 --- /dev/null +++ b/test/Feature/FunctionPointer.c @@ -0,0 +1,36 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee --no-output --exit-on-error %t1.bc + +#include <stdio.h> + +void foo(const char *msg) { printf("foo: %s\n", msg); } +void baz(const char *msg) { printf("baz: %s\n", msg); } + +void (*xx)(const char *) = foo; + +void bar(void (*fp)(const char *)) { fp("called via bar"); } + +int main(int argc, char **argv) { + void (*fp)(const char *) = foo; + + printf("going to call through fp\n"); + fp("called via fp"); + + printf("calling via pass through\n"); + bar(foo); + + fp = baz; + fp("called via fp"); + + xx("called via xx"); + +#if 0 + klee_make_symbolic(&fp, sizeof fp); + if(fp == baz) { + printf("fp = %p, baz = %p\n", fp, baz); + fp("calling via symbolic!"); + } +#endif + + return 0; +} diff --git a/test/Feature/GetValue.c b/test/Feature/GetValue.c new file mode 100644 index 00000000..391b68e3 --- /dev/null +++ b/test/Feature/GetValue.c @@ -0,0 +1,17 @@ +// RUN: %llvmgcc -c -o %t1.bc %s +// RUN: %klee --exit-on-error %t1.bc + +#include <stdio.h> +#include <assert.h> + +int main() { + int x = klee_int("x"); + klee_assume(x > 10); + klee_assume(x < 20); + + assert(!klee_is_symbolic(klee_get_value(x))); + assert(klee_get_value(x) > 10); + assert(klee_get_value(x) < 20); + + return 0; +} diff --git a/test/Feature/ImpliedValue.c.failing b/test/Feature/ImpliedValue.c.failing new file mode 100644 index 00000000..2f169970 --- /dev/null +++ b/test/Feature/ImpliedValue.c.failing @@ -0,0 +1,147 @@ +// RUN: rm -f %t4.out %t4.err %t4.log +// RUN: %llvmgcc %s -emit-llvm -O2 -c -o %t1.bc +// RUN: llvm-as -f ../_utils._ll -o %t2.bc +// RUN: llvm-ld -disable-opt -link-as-library %t1.bc %t2.bc -o %t3.bc +// RUN: %klee --log-file %t4.log --debug-check-for-implied-values %t3.bc > %t4.out 2> %t4.err +// RUN: ls klee-last | not grep .err +// RUN: not grep "(missed)" %t4.log + +#include <assert.h> + +#include "utils.h" + +int main() { + unsigned char which; + volatile unsigned char a,b,c,d,e,f,g,h; + + klee_make_symbolic(&which, sizeof which); + klee_make_symbolic(&a, sizeof a); + klee_make_symbolic(&b, sizeof b); + klee_make_symbolic(&c, sizeof c); + klee_make_symbolic(&d, sizeof d); + klee_make_symbolic(&e, sizeof e); + klee_make_symbolic(&f, sizeof f); + klee_make_symbolic(&g, sizeof g); + klee_make_symbolic(&h, sizeof h); + + switch (which) { +// RUN: grep "simple read(2) = value case" %t4.out + case 0: + if (a == 2) { + assert(!klee_is_symbolic(a)); + printf("simple read(%d) = value case\n", a); + } + break; + +// RUN: grep "select(0) has distinct constant result case (false)" %t4.out + case 1: + if (util_make_select(a, 12, 14) == 14) { + assert(!klee_is_symbolic(a)); + printf("select(%d) has distinct constant result case (false)\n", a); + } + break; + +// RUN: grep "select(0) has distinct constant result case (true)" %t4.out + case 2: + if (util_make_select(!a, 12, 14) == 12) { + assert(!klee_is_symbolic(a)); + printf("select(%d) has distinct constant result case (true)\n", a); + } + break; + +// RUN: grep "concat2(0xBE,0xEF) = value case" %t4.out + case 3: + if (util_make_concat2(a,b) == 0xBEEF) { + assert(!klee_is_symbolic(a)); + assert(!klee_is_symbolic(b)); + printf("concat2(0x%X,0x%X) = value case\n", + a, b); + } + break; + +// RUN: grep "concat4(0xDE,0xAD,0xBE,0xEF) = value case" %t4.out + case 4: + if (util_make_concat4(a,b,c,d) == 0xDEADBEEF) { + assert(!klee_is_symbolic(a)); + assert(!klee_is_symbolic(b)); + assert(!klee_is_symbolic(c)); + assert(!klee_is_symbolic(d)); + printf("concat4(0x%X,0x%X,0x%X,0x%X) = value case\n", + a, b, c, d); + } + break; + +// RUN: grep "concat8(0xDE,0xAD,0xBE,0xEF,0xAB,0xCD,0xAB,0xCD) = value case" %t4.out + case 5: + if (util_make_concat8(a,b,c,d,e,f,g,h) == 0xDEADBEEFABCDABCDLL) { + assert(!klee_is_symbolic(a)); + assert(!klee_is_symbolic(b)); + assert(!klee_is_symbolic(c)); + assert(!klee_is_symbolic(d)); + assert(!klee_is_symbolic(e)); + assert(!klee_is_symbolic(f)); + assert(!klee_is_symbolic(g)); + assert(!klee_is_symbolic(h)); + printf("concat8(0x%X,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X,0x%X) = value case\n", + a, b, c, d, e, f, g, h); + } + break; + +// RUN: grep "and(0,0) = true case" %t4.out + case 6: + if (util_make_and_i1(!a, !b)) { + assert(!klee_is_symbolic(a)); + assert(!klee_is_symbolic(b)); + printf("and(%d,%d) = true case\n", a, b); + } + break; + +// RUN: grep "or(0,0) = false case" %t4.out + case 7: + if (!util_make_or_i1(a, b)) { + assert(!klee_is_symbolic(a)); + assert(!klee_is_symbolic(b)); + printf("or(%d,%d) = false case\n", a, b); + } + break; + + // we use concat to prevent folding, will need to fix if that gets + // partial evaluated +// RUN: grep "add constant case: 0xDE" %t4.out + case 8: + if (util_make_concat2(a+0xCD,0xCD) == 0xABCD) { + assert(!klee_is_symbolic(a)); + printf("add constant case: 0x%X\n", a); + } + break; + +// RUN: grep "sub constant case: 0x60" %t4.out + case 9: + if (util_make_concat2(0x0B-a,0xCD) == 0xABCD) { + assert(!klee_is_symbolic(a)); + printf("sub constant case: 0x%X\n", a); + } + break; + +// RUN: grep "xor constant case: 0xA0" %t4.out + case 10: + if (util_make_concat2(0x0B ^ a,0xCD) == 0xABCD) { + assert(!klee_is_symbolic(a)); + printf("xor constant case: 0x%X\n", a); + } + break; + +// RUN: grep "sext constant case: 244" %t4.out + case 11: + if (! util_make_or_i1(((short) (signed char) a) + 12,b)) { + assert(!klee_is_symbolic(a)); + printf("sext constant case: %d\n", a); + } + break; + + default: + break; + } + + return 0; +} diff --git a/test/Feature/InAndOutOfBounds.c b/test/Feature/InAndOutOfBounds.c new file mode 100644 index 00000000..18e5d2b2 --- /dev/null +++ b/test/Feature/InAndOutOfBounds.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: test -f klee-last/test000001.ptr.err -o -f klee-last/test000002.ptr.err +// RUN: test ! -f klee-last/test000001.ptr.err -o ! -f klee-last/test000002.ptr.err +// RUN: test ! -f klee-last/test000003.bout + +unsigned klee_urange(unsigned start, unsigned end) { + unsigned x; + klee_make_symbolic(&x, sizeof x); + if (x-start>=end-start) klee_silent_exit(0); + return x; +} + +int main() { + int *x = malloc(4); + x[klee_urange(0,2)] = 1; + free(x); + return 0; +} diff --git a/test/Feature/IndirectCallToBuiltin.c b/test/Feature/IndirectCallToBuiltin.c new file mode 100644 index 00000000..591a5601 --- /dev/null +++ b/test/Feature/IndirectCallToBuiltin.c @@ -0,0 +1,15 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee %t1.bc + +#include <stdlib.h> +#include <stdio.h> + +int main() { + void *(*allocator)(size_t) = malloc; + int *mem = allocator(10); + + printf("mem: %p\n", mem); + printf("mem[0]: %d\n", mem[0]); + + return 0; +} diff --git a/test/Feature/IndirectCallToExternal.c b/test/Feature/IndirectCallToExternal.c new file mode 100644 index 00000000..4603213b --- /dev/null +++ b/test/Feature/IndirectCallToExternal.c @@ -0,0 +1,15 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee %t1.bc + +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include <assert.h> + +int main() { + int (*scmp)(char*,char*) = strcmp; + + assert(scmp("hello","hi") < 0); + + return 0; +} diff --git a/test/Feature/InvalidBitfieldAccess.c.failing b/test/Feature/InvalidBitfieldAccess.c.failing new file mode 100644 index 00000000..ae8bfe5e --- /dev/null +++ b/test/Feature/InvalidBitfieldAccess.c.failing @@ -0,0 +1,28 @@ +// RUN: %llvmgcc -c -o %t1.bc %s +// RUN: %klee --exit-on-error %t1.bc + +// This is a bug in llvm-gcc4.0 but seems to be fixed in llvm-gcc4.2, +// its included here mostly as a reminder. + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> + +struct foo { + unsigned int a : 5; + unsigned int b : 10; + unsigned int c : 1; +} __attribute__((packed)); + +int main() { + struct foo *a = malloc(sizeof *a); + + a->b = 12; // problem here is that llvm-gcc emits a 4 byte access + // which is out of bounds. + + int x = a->b; + + assert(x == 12); + + return 0; +} diff --git a/test/Feature/IsSymbolic.c b/test/Feature/IsSymbolic.c new file mode 100644 index 00000000..4a86368a --- /dev/null +++ b/test/Feature/IsSymbolic.c @@ -0,0 +1,16 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc + +#include <assert.h> + +int main() { + int x, y, z = 0; + klee_make_symbolic(&x, sizeof x); + klee_make_symbolic(&y, sizeof y); + if (x) { + assert(klee_is_symbolic(y)); + } else { + assert(!klee_is_symbolic(z)); + } + return 0; +} diff --git a/test/Feature/KleeReportError.c b/test/Feature/KleeReportError.c new file mode 100644 index 00000000..dda72fd0 --- /dev/null +++ b/test/Feature/KleeReportError.c @@ -0,0 +1,23 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc +// RUN: %klee --emit-all-errors %t2.bc > %t3.log +// RUN: ls klee-last/ | grep .my.err | wc -l | grep 2 +#include <stdio.h> +#include <assert.h> + +int main(int argc, char** argv) { + int x, y, *p = 0; + + klee_make_symbolic(&x, sizeof x); + klee_make_symbolic(&y, sizeof y); + + if (x) + fprintf(stderr, "x\n"); + else fprintf(stderr, "!x\n"); + + if (y) { + fprintf(stderr, "My error\n"); + klee_report_error(__FILE__, __LINE__, "My error", "my.err"); + } + + return 0; +} diff --git a/test/Feature/LongDoubleSupport.c b/test/Feature/LongDoubleSupport.c new file mode 100644 index 00000000..b4631832 --- /dev/null +++ b/test/Feature/LongDoubleSupport.c @@ -0,0 +1,20 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc > %t2.out + +#include <stdio.h> +#include <float.h> + +// FIXME: This doesn't really work at all, it just doesn't +// crash. Until we have wide constant support, that is all we care +// about; the only reason this comes up is in initialization of +// constants, we don't actually end up seeing much code which uses long +// double. +int main() { + long double a = LDBL_MAX; + long double b = -1; + long double c = a + b; + printf("a = %Lg\n", a); + printf("b = %Lg\n", b); + printf("c = %Lg\n", c); + return 0; +} diff --git a/test/Feature/LowerSwitch.c b/test/Feature/LowerSwitch.c new file mode 100644 index 00000000..c4d9644a --- /dev/null +++ b/test/Feature/LowerSwitch.c @@ -0,0 +1,30 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t.bc +// RUN: %klee --exit-on-error --allow-external-sym-calls --switch-type=internal %t.bc +// RUN: not test -f klee-last/test000010.bout +// RUN: %klee --exit-on-error --allow-external-sym-calls --switch-type=simple %t.bc +// RUN: test -f klee-last/test000010.bout + +#include <stdio.h> + +int main(int argc, char **argv) { + int c = klee_range(0, 256, "range"); + + switch(c) { + case 0: printf("0\n"); break; + case 10: printf("10\n"); break; + case 16: printf("16\n"); break; + case 17: printf("17\n"); break; + case 18: printf("18\n"); break; + case 19: printf("19\n"); break; +#define C(x) case x: case x+1: case x+2: case x+3 +#define C2(x) C(x): C(x+4): C(x+8): C(x+12) +#define C3(x) C2(x): C2(x+16): C2(x+32): C2(x+48) + C3(128): + printf("bignums: %d\n", c); break; + default: + printf("default\n"); + break; + } + + return 0; +} diff --git a/test/Feature/MakeConcreteSymbolic.c b/test/Feature/MakeConcreteSymbolic.c new file mode 100644 index 00000000..29b43a04 --- /dev/null +++ b/test/Feature/MakeConcreteSymbolic.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc +// RUN: grep "done: total queries = 0" klee-last/info +// RUN: %klee --make-concrete-symbolic=1 --exit-on-error %t1.bc +// RUN: grep "done: total queries = 2" klee-last/info + + +#include <assert.h> + +#define N 2 +int main() { + int i; + char a; + + a = 10; + assert(a == 10); + + return 0; +} diff --git a/test/Feature/MakeSymbolicName.c b/test/Feature/MakeSymbolicName.c new file mode 100644 index 00000000..c1f11424 --- /dev/null +++ b/test/Feature/MakeSymbolicName.c @@ -0,0 +1,17 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee --use-random-search --exit-on-error %t1.bc + +#include <assert.h> + +int main() { + int a[4] = {1, 2, 3, 4}; + unsigned i; + + klee_make_symbolic_name(&i, sizeof(i), "index"); + if (i > 3) + klee_silent_exit(0); + + assert(a[i] << 1 != 5); + if (a[i] << 1 == 6) + assert(i == 2); +} diff --git a/test/Feature/MemoryLimit.c b/test/Feature/MemoryLimit.c new file mode 100644 index 00000000..3b1bacaf --- /dev/null +++ b/test/Feature/MemoryLimit.c @@ -0,0 +1,37 @@ +// RUN: %llvmgcc -DLITTLE_ALLOC -g -c %s -o %t.little.bc +// RUN: %llvmgcc -g -c %s -o %t.big.bc +// RUN: %klee --max-memory=20 %t.little.bc > %t.little.log +// RUN: %klee --max-memory=20 %t.big.bc > %t.big.log +// RUN: not grep -q "DONE" %t.little.log +// RUN: not grep -q "DONE" %t.big.log + +#include <stdlib.h> + +int main() { + int i, j, x=0; + +#ifdef LITTLE_ALLOC + printf("IN LITTLE ALLOC\n"); + + // 200 MBs total (in 32 byte chunks) + for (i=0; i<100; i++) { + for (j=0; j<(1<<16); j++) + malloc(1<<5); + } +#else + printf("IN BIG ALLOC\n"); + + // 200 MBs total + for (i=0; i<100; i++) { + malloc(1<<21); + + // Ensure we hit the periodic check + for (j=0; j<10000; j++) + x++; + } +#endif + + printf("DONE!\n"); + + return x; +} diff --git a/test/Feature/MultipleFreeResolution.c b/test/Feature/MultipleFreeResolution.c new file mode 100644 index 00000000..872d6856 --- /dev/null +++ b/test/Feature/MultipleFreeResolution.c @@ -0,0 +1,39 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --emit-all-errors %t1.bc +// RUN: ls klee-last/ | grep .out | wc -l | grep 4 +// RUN: ls klee-last/ | grep .err | wc -l | grep 3 + +#include <stdlib.h> +#include <stdio.h> + +unsigned klee_urange(unsigned start, unsigned end) { + unsigned x; + klee_make_symbolic(&x, sizeof x); + if (x-start>=end-start) klee_silent_exit(0); + return x; +} + +int *make_int(int i) { + int *x = malloc(sizeof(*x)); + *x = i; + return x; +} + +int main() { + int *buf[4]; + int i,s; + + for (i=0; i<3; i++) + buf[i] = make_int(i); + buf[3] = 0; + + s = klee_urange(0,4); + + free(buf[s]); + + for (i=0; i<3; i++) { + printf("*buf[%d] = %d\n", i, *buf[i]); + } + + return 0; +} diff --git a/test/Feature/MultipleReadResolution.c b/test/Feature/MultipleReadResolution.c new file mode 100644 index 00000000..9297cf8d --- /dev/null +++ b/test/Feature/MultipleReadResolution.c @@ -0,0 +1,43 @@ +// RUN: echo "x" > %t1.res +// RUN: echo "x" >> %t1.res +// RUN: echo "x" >> %t1.res +// RUN: echo "x" >> %t1.res +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc > %t1.log +// RUN: diff %t1.res %t1.log + +#include <stdio.h> + +unsigned klee_urange(unsigned start, unsigned end) { + unsigned x; + klee_make_symbolic(&x, sizeof x); + if (x-start>=end-start) klee_silent_exit(0); + return x; +} + +int *make_int(int i) { + int *x = malloc(sizeof(*x)); + *x = i; + return x; +} + +int main() { + int *buf[4]; + int i,s,t; + + for (i=0; i<4; i++) + buf[i] = make_int((i+1)*2); + + s = klee_urange(0,4); + + int x = *buf[s]; + + if (x == 4) + if (s!=1) + abort(); + + printf("x\n"); + fflush(stdout); + + return 0; +} diff --git a/test/Feature/MultipleReallocResolution.c b/test/Feature/MultipleReallocResolution.c new file mode 100644 index 00000000..b1a14ace --- /dev/null +++ b/test/Feature/MultipleReallocResolution.c @@ -0,0 +1,63 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: ls klee-last/ | grep .err | wc -l | grep 2 +// RUN: ls klee-last/ | grep .ptr.err | wc -l | grep 2 + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +unsigned klee_urange(unsigned start, unsigned end) { + unsigned x; + klee_make_symbolic(&x, sizeof x); + if (x-start>=end-start) klee_silent_exit(0); + return x; +} + +int *make_int(int i, int N) { + int *x = malloc(sizeof(*x) * N); + *x = i; + return x; +} + +int main() { + int *buf[4]; + + buf[0] = malloc(sizeof(int)*4); + buf[1] = malloc(sizeof(int)); + buf[2] = 0; // gets malloc'd + buf[3] = (int*) 0xdeadbeef; // boom + + buf[0][0] = 10; + buf[0][1] = 42; + buf[1][0] = 20; + + int i = klee_urange(0,4); + int new_size = 2 * sizeof(int) * klee_urange(0,2); // 0 or 8 + + // whee, party time, needs to: + // Fork if size == 0, in which case all buffers get free'd and + // we will crash in prints below. + // Fork if buf[s] == 0, in which case the buffer gets malloc'd (for s==2) + // Fork on other buffers (s in [0,1]) and do realloc + // for s==0 this is shrinking + // for s==1 this is growing + buf[i] = realloc(buf[i], new_size); + + if (new_size == 0) { + assert(!buf[2]); // free(0) is a no-op + if (i==0) assert(!buf[0] && buf[1]); + if (i==1) assert(buf[0] && !buf[1]); + assert(i != 3); // we should have crashed on free of invalid + } else { + assert(new_size == sizeof(int)*2); + assert(buf[0][0] == 10); + assert(buf[0][1] == 42); // make sure copied + assert(buf[1][0] == 20); + if (i==1) { int x = buf[1][1]; } // should be safe + if (i==2) { int x = buf[2][0]; } // should be safe + assert(i != 3); // we should have crashed on realloc of invalid + } + + return 0; +} diff --git a/test/Feature/MultipleWriteResolution.c b/test/Feature/MultipleWriteResolution.c new file mode 100644 index 00000000..f07b9710 --- /dev/null +++ b/test/Feature/MultipleWriteResolution.c @@ -0,0 +1,43 @@ +// RUN: echo "x" > %t1.res +// RUN: echo "x" >> %t1.res +// RUN: echo "x" >> %t1.res +// RUN: echo "x" >> %t1.res +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc > %t1.log +// RUN: diff %t1.res %t1.log + +#include <stdio.h> + +unsigned klee_urange(unsigned start, unsigned end) { + unsigned x; + klee_make_symbolic(&x, sizeof x); + if (x-start>=end-start) klee_silent_exit(0); + return x; +} + +int *make_int(int i) { + int *x = malloc(sizeof(*x)); + *x = i; + return x; +} + +int main() { + int *buf[4]; + int i,s,t; + + for (i=0; i<4; i++) + buf[i] = make_int((i+1)*2); + + s = klee_urange(0,4); + + *buf[s] = 5; + + if ((*buf[0] + *buf[1] + *buf[2] + *buf[3]) == 17) + if (s!=3) + abort(); + + printf("x\n"); + fflush(stdout); + + return 0; +} diff --git a/test/Feature/NamedSeedMatching.c b/test/Feature/NamedSeedMatching.c new file mode 100644 index 00000000..6d52e7a4 --- /dev/null +++ b/test/Feature/NamedSeedMatching.c @@ -0,0 +1,41 @@ +// RUN: %llvmgcc -c -g %s -o %t.bc +// RUN: rm -rf %t.out +// RUN: %klee --output-dir=%t.out %t.bc "initial" +// RUN: test -f %t.out/test000001.bout +// RUN: not test -f %t.out/test000002.bout +// RUN: %klee --only-replay-seeds --named-seed-matching --seed-out %t.out/test000001.bout %t.bc > %t.log +// RUN: grep -q "a==3" %t.log +// RUN: grep -q "b==4" %t.log +// RUN: grep -q "c==5" %t.log +// RUN: grep -q "x==6" %t.log + +#include <string.h> +#include <stdio.h> + +int main(int argc, char **argv) { + int a, b, c, x; + + if (argc==2 && strcmp(argv[1], "initial") == 0) { + klee_make_symbolic_name(&a, sizeof a, "a"); + klee_make_symbolic_name(&b, sizeof b, "b"); + klee_make_symbolic_name(&c, sizeof c, "c"); + klee_make_symbolic_name(&x, sizeof x, "a"); + + klee_assume(a == 3); + klee_assume(b == 4); + klee_assume(c == 5); + klee_assume(x == 6); + } else { + klee_make_symbolic_name(&a, sizeof a, "a"); + klee_make_symbolic_name(&c, sizeof c, "c"); + klee_make_symbolic_name(&b, sizeof b, "b"); + klee_make_symbolic_name(&x, sizeof x, "a"); + } + + if (a==3) printf("a==3\n"); + if (b==4) printf("b==4\n"); + if (c==5) printf("c==5\n"); + if (x==6) printf("x==6\n"); + + return 0; +} diff --git a/test/Feature/OneFreeError.c b/test/Feature/OneFreeError.c new file mode 100644 index 00000000..8eb13298 --- /dev/null +++ b/test/Feature/OneFreeError.c @@ -0,0 +1,10 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: test -f klee-last/test000001.ptr.err + +int main() { + int *x = malloc(4); + free(x); + x[0] = 1; + return 0; +} diff --git a/test/Feature/OneOutOfBounds.c b/test/Feature/OneOutOfBounds.c new file mode 100644 index 00000000..11a9eecb --- /dev/null +++ b/test/Feature/OneOutOfBounds.c @@ -0,0 +1,10 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: test -f klee-last/test000001.ptr.err + +int main() { + int *x = malloc(4); + x[1] = 1; + free(x); + return 0; +} diff --git a/test/Feature/Optimize.c b/test/Feature/Optimize.c new file mode 100644 index 00000000..3c9159c7 --- /dev/null +++ b/test/Feature/Optimize.c @@ -0,0 +1,22 @@ +// RUN: %llvmgcc %s --emit-llvm -O0 -c -o %t2.bc +// RUN: rm -f %t2.log +// RUN: %klee --stop-after-n-instructions=100 --optimize %t2.bc > %t3.log +// RUN: echo "good" > %t3.good +// RUN: diff %t3.log %t3.good + +// should complete by 100 instructions if opt is on + +int main() { + int i, res = 0; + + for (i=1; i<=1000; i++) + res += i; + + if (res == (1000*1001)/2) { + printf("good\n"); + } else { + printf("bad\n"); + } + + return 0; +} diff --git a/test/Feature/OverlappedError.c b/test/Feature/OverlappedError.c new file mode 100644 index 00000000..3c79380c --- /dev/null +++ b/test/Feature/OverlappedError.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -g -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: ls klee-last/ | grep .out | wc -l | grep 4 +// RUN: ls klee-last/ | grep .ptr.err | wc -l | grep 2 + +#include <stdlib.h> + +int main() { + if (klee_range(0,2, "range")) { + char *x = malloc(8); + *((int*) &x[klee_range(0,6, "range")]) = 1; + free(x); + } else { + char *x = malloc(8); + *((int*) &x[klee_range(-1,5, "range")]) = 1; + free(x); + } + return 0; +} diff --git a/test/Feature/PreferCex.c b/test/Feature/PreferCex.c new file mode 100644 index 00000000..d73b6076 --- /dev/null +++ b/test/Feature/PreferCex.c @@ -0,0 +1,18 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc +// RUN: klee-bout-tool klee-last/test000001.bout | grep -F 'Hi\x00\x00' + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +int main() { + char buf[4]; + + klee_make_symbolic(buf, sizeof buf); + klee_prefer_cex(buf, buf[0]=='H'); + klee_prefer_cex(buf, buf[1]=='i'); + klee_prefer_cex(buf, buf[2]=='\0'); + + return 0; +} diff --git a/test/Feature/RaiseAsm.c b/test/Feature/RaiseAsm.c new file mode 100644 index 00000000..5b8acab4 --- /dev/null +++ b/test/Feature/RaiseAsm.c @@ -0,0 +1,39 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc + +#include <assert.h> + +typedef unsigned short uint16; +typedef unsigned int uint32; + +uint16 byteswap_uint16(uint16 x) { + return (x << 8) | (x >> 8); +} +uint32 byteswap_uint32(uint32 x) { + return ((byteswap_uint16(x) << 16) | + (byteswap_uint16(x >> 16))); +} + +uint16 byteswap_uint16_asm(uint16 x) { + uint16 res; + __asm__("rorw $8, %w0" : "=r" (res) : "0" (x) : "cc"); + return res; +} + +uint32 byteswap_uint32_asm(uint32 x) { + uint32 res; + __asm__("rorw $8, %w0;" + "rorl $16, %0;" + "rorw $8, %w0" : "=r" (res) : "0" (x) : "cc"); + return res; +} + +int main() { + uint16 ui16 = klee_int("ui16"); + uint32 ui32 = klee_int("ui32"); + + assert(ui16 == byteswap_uint16(byteswap_uint16_asm(ui16))); + assert(ui32 == byteswap_uint32(byteswap_uint32_asm(ui32))); + + return 0; +} diff --git a/test/Feature/ReallocFailure.c b/test/Feature/ReallocFailure.c new file mode 100644 index 00000000..e5105c33 --- /dev/null +++ b/test/Feature/ReallocFailure.c @@ -0,0 +1,18 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc + +#include <assert.h> +#include <stdlib.h> +#include <stdio.h> + +int main() { + int *p = malloc(sizeof(int)*2); + assert(p); + p[1] = 52; + + int *p2 = realloc(p, 1<<30); + assert(p2 == 0); + assert(p[1] == 52); + + return 0; +} diff --git a/test/Feature/ReplayPath.c b/test/Feature/ReplayPath.c new file mode 100644 index 00000000..3f01fa80 --- /dev/null +++ b/test/Feature/ReplayPath.c @@ -0,0 +1,27 @@ +// RUN: echo "1" > %t1.path +// RUN: echo "0" >> %t1.path +// RUN: echo "1" >> %t1.path +// RUN: echo "0" >> %t1.path +// RUN: echo "1" >> %t1.path +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc +// RUN: %klee --replay-path %t1.path %t2.bc > %t3.log +// RUN: echo "res: 110" > %t3.good +// RUN: diff %t3.log %t3.good + +int main() { + int res = 1; + int x; + + klee_make_symbolic(&x, sizeof x); + + if (x&1) res *= 2; + if (x&2) res *= 3; + if (x&4) res *= 5; + + // get forced branch coverage + if (x&2) res *= 7; + if (!(x&2)) res *= 11; + printf("res: %d\n", res); + + return 0; +} diff --git a/test/Feature/Searchers.c b/test/Feature/Searchers.c new file mode 100644 index 00000000..95ebddf2 --- /dev/null +++ b/test/Feature/Searchers.c @@ -0,0 +1,52 @@ +// RUN: %llvmgcc %s --emit-llvm -O0 -c -o %t2.bc +// RUN: %klee %t2.bc +// RUN: %klee --use-random-search %t2.bc +// RUN: %klee --use-non-uniform-random-search %t2.bc +// RUN: %klee --use-non-uniform-random-search --weight-type=query-cost %t2.bc +// RUN: %klee --use-batching-search %t2.bc +// RUN: %klee --use-batching-search --use-random-search %t2.bc +// RUN: %klee --use-batching-search --use-non-uniform-random-search %t2.bc +// RUN: %klee --use-batching-search --use-non-uniform-random-search --weight-type=query-cost %t2.bc +// RUN: %klee --use-merge --debug-log-merge --debug-log-state-merge %t2.bc +// RUN: %klee --use-merge --use-batching-search %t2.bc +// RUN: %klee --use-merge --use-batching-search --use-random-search %t2.bc +// RUN: %klee --use-merge --use-batching-search --use-non-uniform-random-search %t2.bc +// RUN: %klee --use-merge --use-batching-search --use-non-uniform-random-search --weight-type=query-cost %t2.bc +// RUN: %klee --use-iterative-deepening-time-search --use-batching-search %t2.bc +// RUN: %klee --use-iterative-deepening-time-search --use-batching-search --use-random-search %t2.bc +// RUN: %klee --use-iterative-deepening-time-search --use-batching-search --use-non-uniform-random-search %t2.bc +// RUN: %klee --use-iterative-deepening-time-search --use-batching-search --use-non-uniform-random-search --weight-type=query-cost %t2.bc + + +/* this test is basically just for coverage and doesn't really do any + correctness check (aside from testing that the various combinations + don't crash) */ + +int validate(char *buf, int N) { + + int i; + + for (i=0; i<N; i++) { + if (buf[i]==0) { + klee_merge(); + return 0; + } + } + + klee_merge(); + return 1; +} + +#ifndef SYMBOLIC_SIZE +#define SYMBOLIC_SIZE 15 +#endif +int main(int argc, char **argv) { + int N = SYMBOLIC_SIZE; + unsigned char *buf = malloc(N); + int i; + + klee_make_symbolic(buf, N); + if (validate(buf, N)) + return buf[0]; + return 0; +} diff --git a/test/Feature/SetForking.c b/test/Feature/SetForking.c new file mode 100644 index 00000000..8620110d --- /dev/null +++ b/test/Feature/SetForking.c @@ -0,0 +1,28 @@ +// RUN: %llvmgcc -g -c %s -o %t.bc +// RUN: %klee %t.bc > %t.log +// RUN: sort %t.log | uniq -c > %t.uniq.log +// RUN: grep "1 A" %t.uniq.log +// RUN: grep "1 B" %t.uniq.log +// RUN: grep "1 C" %t.uniq.log + +#include <stdio.h> + +int main() { + klee_set_forking(0); + + if (klee_range(0, 2, "range")) { + printf("A\n"); + } else { + printf("A\n"); + } + + klee_set_forking(1); + + if (klee_range(0, 2, "range")) { + printf("B\n"); + } else { + printf("C\n"); + } + + return 0; +} diff --git a/test/Feature/Vararg.c b/test/Feature/Vararg.c new file mode 100644 index 00000000..f782c15e --- /dev/null +++ b/test/Feature/Vararg.c @@ -0,0 +1,82 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc > %t2.out +// RUN: grep "types: (52, 37, 2.00, (9,12,15))" %t2.out +// RUN: test -f klee-last/test000001.ptr.err + +#include <stdarg.h> +#include <assert.h> +#include <stdio.h> + +struct triple { + int first, second, third; +}; + +int test1(int x, ...) { + va_list ap; + va_start(ap, x); + int i32 = va_arg(ap, int); + long long i64 = va_arg(ap, long long); + double d = va_arg(ap, double); + struct triple p = va_arg(ap, struct triple); + printf("types: (%d, %lld, %.2f, (%d,%d,%d))\n", i32, i64, d, p.first, p.second, p.third); + va_end(ap); +} + +int sum(int N, ...) { + int i, res = 0; + va_list ap,ap2; + + va_start(ap, N); + for (i=0; i<N; i++) { + if (i==1) + va_copy(ap2, ap); + res += va_arg(ap, int); + } + for (i=0; i<N-1; i++) + res += va_arg(ap2, int); + va_end(ap); + + return res; +} + +// test using aps in an array (no multiple resolution +// testing, though) +int va_array(int N, ...) { + va_list aps[2]; + unsigned i; + unsigned sum1 = 0, sum2 = 0; + + for (i=0; i<2; i++) + va_start(aps[i], N); + + for (i=0; i<N; i++) { + unsigned cmd = va_arg(aps[0], int); + + if (cmd==0) { + sum1 += va_arg(aps[0],int); + } else if (cmd==1) { + sum2 += va_arg(aps[1],int); + } else if (cmd==2) { + va_copy(aps[1], aps[0]); + } + } + + for (i=0; i<2; i++) + va_end(aps[i]); + + return 3*sum1 + 5*sum2; +} + +int main() { + struct triple p = { 9, 12, 15 }; + test1(-1, 52, 37ll, 2.0, p); + + assert(sum(2, 3, 4) == 11); + assert(sum(0) == 0); + assert(va_array(5, 0, 5, 1, 1, 2, 1)==45); // 15 + 30 + + // should give memory error + test1(-1, 52, 37, 2.0, p); + + return 0; +} diff --git a/test/Feature/WithLibc.c b/test/Feature/WithLibc.c new file mode 100644 index 00000000..5e84eb4a --- /dev/null +++ b/test/Feature/WithLibc.c @@ -0,0 +1,22 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc +// RUN: %klee --libc=klee %t2.bc > %t3.log +// RUN: echo "good" > %t3.good +// RUN: diff %t3.log %t3.good + +int main() { + char buf[4]; + char *s = "foo"; + + klee_make_symbolic(buf, sizeof buf); + buf[3] = 0; + + if (strcmp(buf, s)==0) { + if (buf[0]=='f' && buf[1]=='o' && buf[2]=='o' && buf[3]==0) { + printf("good\n"); + } else { + printf("bad\n"); + } + } + + return 0; +} diff --git a/test/Feature/WriteCov.c b/test/Feature/WriteCov.c new file mode 100644 index 00000000..defc7e59 --- /dev/null +++ b/test/Feature/WriteCov.c @@ -0,0 +1,15 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t2.bc +// RUN: %klee --exit-on-error --write-cov %t2.bc +// RUN: grep WriteCov.c:10 klee-last/test000002.cov +// RUN: grep WriteCov.c:12 klee-last/test000001.cov + +#include <assert.h> + +int main() { + if (klee_range(0,2, "range")) { + assert(__LINE__ == 10); printf("__LINE__ = %d\n", __LINE__); + } else { + assert(__LINE__ == 12); printf("__LINE__ = %d\n", __LINE__); + } + return 0; +} diff --git a/test/Feature/_utils._ll b/test/Feature/_utils._ll new file mode 100644 index 00000000..32a73bb1 --- /dev/null +++ b/test/Feature/_utils._ll @@ -0,0 +1,71 @@ +define i32 @util_make_and_i1(i32 %a, i32 %b) { + %a_i1 = icmp ne i32 %a, 0 + %b_i1 = icmp ne i32 %b, 0 + %res_i1 = and i1 %a_i1, %b_i1 + %res = zext i1 %res_i1 to i32 + ret i32 %res +} + +define i32 @util_make_or_i1(i32 %a, i32 %b) { + %a_i1 = icmp ne i32 %a, 0 + %b_i1 = icmp ne i32 %b, 0 + %res_i1 = or i1 %a_i1, %b_i1 + %res = zext i1 %res_i1 to i32 + ret i32 %res +} + +define i16 @util_make_concat2(i8 %a, i8 %b) { + %tmp = alloca i16 + %tmp8 = bitcast i16* %tmp to i8* + %p0 = getelementptr i8* %tmp8, i32 0 + %p1 = getelementptr i8* %tmp8, i32 1 + store i8 %b, i8* %p0 + store i8 %a, i8* %p1 + %concat = load i16* %tmp + ret i16 %concat +} + +define i32 @util_make_concat4(i8 %a, i8 %b, i8 %c, i8 %d) { + %tmp = alloca i32 + %tmp8 = bitcast i32* %tmp to i8* + %p0 = getelementptr i8* %tmp8, i32 0 + %p1 = getelementptr i8* %tmp8, i32 1 + %p2 = getelementptr i8* %tmp8, i32 2 + %p3 = getelementptr i8* %tmp8, i32 3 + store i8 %d, i8* %p0 + store i8 %c, i8* %p1 + store i8 %b, i8* %p2 + store i8 %a, i8* %p3 + %concat = load i32* %tmp + ret i32 %concat +} + +define i64 @util_make_concat8(i8 %a, i8 %b, i8 %c, i8 %d, + i8 %e, i8 %f, i8 %g, i8 %h) { + %tmp = alloca i64 + %tmp8 = bitcast i64* %tmp to i8* + %p0 = getelementptr i8* %tmp8, i32 0 + %p1 = getelementptr i8* %tmp8, i32 1 + %p2 = getelementptr i8* %tmp8, i32 2 + %p3 = getelementptr i8* %tmp8, i32 3 + %p4 = getelementptr i8* %tmp8, i32 4 + %p5 = getelementptr i8* %tmp8, i32 5 + %p6 = getelementptr i8* %tmp8, i32 6 + %p7 = getelementptr i8* %tmp8, i32 7 + store i8 %h, i8* %p0 + store i8 %g, i8* %p1 + store i8 %f, i8* %p2 + store i8 %e, i8* %p3 + store i8 %d, i8* %p4 + store i8 %c, i8* %p5 + store i8 %b, i8* %p6 + store i8 %a, i8* %p7 + %concat = load i64* %tmp + ret i64 %concat +} + +define i32 @util_make_select(i32 %cond, i32 %t, i32 %f) { + %cond_i1 = icmp ne i32 %cond, 0 + %res = select i1 %cond_i1, i32 %t, i32 %f + ret i32 %res +} \ No newline at end of file diff --git a/test/Feature/const_array_opt1.c b/test/Feature/const_array_opt1.c new file mode 100644 index 00000000..96c46fb9 --- /dev/null +++ b/test/Feature/const_array_opt1.c @@ -0,0 +1,37 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --const-array-opt --max-time=10 --only-output-states-covering-new %t.bc >%t.log +// grep -q "Finished successfully!\n" + +/* This is testing the const array optimization. On my 2.3GHz machine + this takes under 2 seconds w/ the optimization and almost 6 minutes + w/o. So we kill it in 10 sec and check if it has finished + successfully. */ + +#include <unistd.h> +#include <assert.h> +#include <stdio.h> + +int main() { +#define N 8192 +#define N_IDX 16 + unsigned char a[N]; + unsigned i, k[N_IDX]; + + for (i=0; i<N; i++) + a[i] = i % 256; + + klee_make_symbolic_name(k, sizeof(k), "k"); + + for (i=0; i<N_IDX; i++) { + if (k[i] >= N) + klee_silent_exit(0); + + if (a[k[i]] == i) + assert(k[i] % 256 == i); + else klee_silent_exit(0); + } + + printf("Finished successfully!\n"); + + return 0; +} diff --git a/test/Feature/dg.exp b/test/Feature/dg.exp new file mode 100644 index 00000000..879685ca --- /dev/null +++ b/test/Feature/dg.exp @@ -0,0 +1,3 @@ +load_lib llvm.exp + +RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] diff --git a/test/Feature/utils.h b/test/Feature/utils.h new file mode 100644 index 00000000..5423a0dc --- /dev/null +++ b/test/Feature/utils.h @@ -0,0 +1,16 @@ +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +uint32_t util_make_and_i1(uint32_t a, uint32_t b); +uint32_t util_make_or_i1(uint32_t a, uint32_t b); + +uint16_t util_make_concat2(uint8_t a, uint8_t b); +uint32_t util_make_concat4(uint8_t a, uint8_t b, + uint8_t c, uint8_t d); +uint64_t util_make_concat8(uint8_t a, uint8_t b, + uint8_t c, uint8_t d, + uint8_t e, uint8_t f, + uint8_t g, uint8_t h); +uint32_t util_make_select(uint32_t cond, uint32_t true, uint32_t false); diff --git a/test/Makefile b/test/Makefile new file mode 100644 index 00000000..0c42a6f6 --- /dev/null +++ b/test/Makefile @@ -0,0 +1,101 @@ +#===- test/Makefile ----------------------------------------*- Makefile -*--===# +# +# The LLVM Compiler Infrastructure +# +# This file was developed by the LLVM research group and is distributed under +# the University of Illinois Open Source License. See LICENSE.TXT for details. +# +#===------------------------------------------------------------------------===# + +LEVEL = .. +DIRS = + +# +# Make Dejagnu the default for testing +# +all:: check-local + +# Include other test rules +include Makefile.tests + +#===------------------------------------------------------------------------===# +# DejaGNU testing support +#===------------------------------------------------------------------------===# + +ifdef TESTSUITE +CLEANED_TESTSUITE := $(patsubst %/,%,$(TESTSUITE)) +CLEANED_TESTSUITE := $(patsubst test/%,%,$(CLEANED_TESTSUITE)) +RUNTESTFLAGS := --tool $(CLEANED_TESTSUITE) +endif + +ifneq ($(RUNTEST),) +check-local:: site.exp + ( ulimit -t 600 ; ulimit -d 512000 ; \ + PATH="$(ToolDir):$(LLVMToolDir):$(LLVM_SRC_ROOT)/test/Scripts:$(PATH)" \ + $(RUNTEST) $(RUNTESTFLAGS) ; \ + ! grep FAIL testrun.log ) +else +check-local:: site.exp + @echo "*** dejagnu not found. Make sure runtest is in your PATH, then reconfigure llvm." +endif + +ifdef TESTONE +CLEANED_TESTONE := $(patsubst %/,%,$(TESTONE)) +CLEANED_TESTONE := $(patsubst test/%,%,$(CLEANED_TESTONE)) +SUBDIR := $(shell dirname $(CLEANED_TESTONE)) +TESTPATH := $(PROJ_SRC_ROOT)/test/$(CLEANED_TESTONE) +check-one: site.exp $(TCLSH) + $(Verb)( echo "source $(PROJ_OBJ_ROOT)/test/site.exp" ; \ + echo "set subdir $(SUBDIR)" ; \ + echo "proc pass { msg } { puts \"PASS: \$$msg\" } "; \ + echo "proc fail { msg } { puts \"FAIL: \$$msg\" }" ; \ + echo "proc xfail { msg } { puts \"XFAIL: \$$msg\" }" ; \ + echo "proc xpass { msg } { puts \"XPASS: \$$msg\" }" ; \ + echo "source $(PROJ_SRC_ROOT)/test/lib/llvm.exp" ; \ + echo "RunLLVMTests $(TESTPATH)" ) | \ + ( ulimit -t 600 ; ulimit -d 512000 ; \ + PATH="$(ToolDir):$(LLVMToolDir):$(LLVM_SRC_ROOT)/test/Scripts:$(PATH)" \ + $(TCLSH) ) +endif + +clean:: + $(RM) -rf `find $(PROJ_OBJ_ROOT)/test -name Output -type d -print` + $(RM) -rf `find $(PROJ_OBJ_ROOT)/test -name 'ft-out*' -type d -print` + $(RM) -rf `find $(PROJ_OBJ_ROOT)/test -name 'ft-last' -print` + $(RM) -rf `find $(PROJ_OBJ_ROOT)/test -name 'klee-last'` + $(RM) -rf `find $(PROJ_OBJ_ROOT)/test -name 'klee-out*'` + $(RM) -rf `find $(PROJ_OBJ_ROOT)/test -name '*~'` + $(RM) -rf `find $(PROJ_OBJ_ROOT)/test -name test.log` + rm -f site.exp + +site.exp: Makefile $(LEVEL)/Makefile.config + @echo 'Making a new site.exp file...' + @echo '## these variables are automatically generated by make ##' >site.tmp + @echo '# Do not edit here. If you wish to override these values' >>site.tmp + @echo '# edit the last section' >>site.tmp + @echo 'set target_triplet "$(TARGET_TRIPLE)"' >> site.tmp + @echo 'set ENABLE_UCLIBC "$(ENABLE_UCLIBC)"' >> site.tmp + @echo 'set ENABLE_POSIX_RUNTIME "$(ENABLE_POSIX_RUNTIME)"' >> site.tmp + @echo 'set TEST_FEATURE_LIST "$(TEST_FEATURE_LIST)"' >> site.tmp + @echo 'set prcontext "$(TCLSH) $(LLVM_SRC_ROOT)/test/Scripts/prcontext.tcl"' >> site.tmp + @echo 'set llvmtoolsdir "$(ToolDir)"' >>site.tmp + @echo 'set llvmlibsdir "$(LibDir)"' >>site.tmp + @echo 'set srcroot "$(PROJ_SRC_ROOT)"' >>site.tmp + @echo 'set objroot "$(PROJ_OBJ_ROOT)"' >>site.tmp + @echo 'set srcdir "$(PROJ_SRC_ROOT)/test"' >>site.tmp + @echo 'set objdir "$(PROJ_OBJ_ROOT)/test"' >>site.tmp + @echo 'set gccpath "$(CC)"' >>site.tmp + @echo 'set gxxpath "$(CXX)"' >>site.tmp + @echo 'set compile_c "$(CC) $(CPP.Flags) $(C.Flags) $(CompileCommonOpts) -c "' >>site.tmp + @echo 'set compile_cxx "$(CXX) $(CPP.Flags) $(CXX.Flags) $(CompileCommonOpts) - c"' >> site.tmp + @echo 'set link "$(CXX) $(CPP.Flags) $(CXX.Flags) $(CompileCommonOpts) $(LD.Flags)"' >>site.tmp + @echo 'set llvmgcc "$(LLVMGCC)"' >> site.tmp + @echo 'set llvmgxx "$(LLVMGCC)"' >> site.tmp + @echo 'set llvmgccmajvers "$(LLVMGCC_MAJVERS)"' >> site.tmp + @echo 'set shlibext "$(SHLIBEXT)"' >> site.tmp + @echo '## All variables above are generated by configure. Do Not Edit ## ' >>site.tmp + @test ! -f site.exp || \ + sed '1,/^## All variables above are.*##/ d' site.exp >> site.tmp + @-rm -f site.bak + @test ! -f site.exp || mv site.exp site.bak + @mv site.tmp site.exp diff --git a/test/Makefile.tests b/test/Makefile.tests new file mode 100644 index 00000000..ad9f2eab --- /dev/null +++ b/test/Makefile.tests @@ -0,0 +1,80 @@ +##----------------------------------------------------------*- Makefile -*-===## +## +## Common rules for generating, linking, and compiling via LLVM. This is +## used to implement a robust testing framework for LLVM +## +##-------------------------------------------------------------------------===## + +# If the user specified a TEST= option on the command line, we do not want to do +# the default testing type. Instead, we change the default target to be the +# test:: target. +# +ifdef TEST +test:: +endif + +# We do not want to make .d files for tests! +DISABLE_AUTO_DEPENDENCIES=1 + +include ${LEVEL}/Makefile.common + +# Specify ENABLE_STATS on the command line to enable -stats and -time-passes +# output from gccas and gccld. +ifdef ENABLE_STATS +STATS = -stats -time-passes +endif + +.PHONY: clean default + +# These files, which might be intermediate results, should not be deleted by +# make +.PRECIOUS: Output/%.bc Output/%.ll +.PRECIOUS: Output/%.tbc Output/%.tll +.PRECIOUS: Output/.dir +.PRECIOUS: Output/%.llvm.bc +.PRECIOUS: Output/%.llvm + +LCCFLAGS += -O2 -Wall +LCXXFLAGS += -O2 -Wall +LLCFLAGS = +TESTRUNR = @echo Running test: $<; \ + PATH="$(LLVMTOOLCURRENT):$(LLVM_SRC_ROOT)/test/Scripts:$(PATH)" \ + $(LLVM_SRC_ROOT)/test/TestRunner.sh + +LLCLIBS := $(LLCLIBS) -lm + +clean:: + $(RM) -f a.out core + $(RM) -rf Output/ + +# Compile from X.c to Output/X.ll +Output/%.ll: %.c $(LCC1) Output/.dir $(INCLUDES) + -$(LLVMGCCWITHPATH) $(CPPFLAGS) $(LCCFLAGS) -S $< -o $@ + +# Compile from X.cpp to Output/X.ll +Output/%.ll: %.cpp $(LCC1XX) Output/.dir $(INCLUDES) + -$(LLVMGXXWITHPATH) $(CPPFLAGS) $(LCXXFLAGS) -S $< -o $@ + +# Compile from X.cc to Output/X.ll +Output/%.ll: %.cc $(LCC1XX) Output/.dir $(INCLUDES) + -$(LLVMGXXWITHPATH) $(CPPFLAGS) $(LCXXFLAGS) -S $< -o $@ + +# LLVM Assemble from Output/X.ll to Output/X.bc. Output/X.ll must have come +# from GCC output, so use GCCAS. +# +Output/%.bc: Output/%.ll $(LGCCAS) + -$(LGCCAS) $(STATS) $< -o $@ + +# LLVM Assemble from X.ll to Output/X.bc. Because we are coming directly from +# LLVM source, use the non-transforming assembler. +# +Output/%.bc: %.ll $(LLVMAS) Output/.dir + -$(LLVMAS) -f $< -o $@ + +## Cancel built-in implicit rules that override above rules +%: %.s + +%: %.c + +%.o: %.c + diff --git a/test/README b/test/README new file mode 100644 index 00000000..53d30ce2 --- /dev/null +++ b/test/README @@ -0,0 +1 @@ +about tests.... diff --git a/test/Runtime/POSIX/DirConsistency.c b/test/Runtime/POSIX/DirConsistency.c new file mode 100644 index 00000000..613655e9 --- /dev/null +++ b/test/Runtime/POSIX/DirConsistency.c @@ -0,0 +1,64 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --run-in=/tmp --use-random-search --init-env --libc=uclibc --posix-runtime --exit-on-error %t.bc --sym-files 1 1 > %t1.log +// RUN: %llvmgcc -D_FILE_OFFSET_BITS=64 %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --run-in=/tmp --use-random-search --init-env --libc=uclibc --posix-runtime --exit-on-error %t.bc --sym-files 1 1 > %t2.log +// RUN: sort %t1.log %t2.log | uniq -c > %t3.log +// RUN: grep -q "4 COUNT" %t3.log + +// For this test really to work as intended it needs to be run in a +// directory large enough to cause uclibc to do multiple getdents +// calls (otherwise uclibc will handle the seeks itself). We should +// create a bunch of files or something. +// +// It is even more important for this test because it requires the +// directory not to change while running, which might be a lot to +// demand of /tmp. + +#define _LARGEFILE64_SOURCE +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <sys/stat.h> +#include <errno.h> + +int main(int argc, char **argv) { + struct stat s; + int res = stat("A", &s); + int hasA = !(res!=0 && errno==ENOENT); + + //printf("sizeof(dirent) = %d\n", sizeof(struct dirent)); + //printf("sizeof(dirent64) = %d\n", sizeof(struct dirent64)); + + //printf("\"A\" exists: %d\n", hasA); + + DIR *d = opendir("."); + assert(d); + + int snum = 1; + if (klee_range(0,2,"range")) { + snum = 2; + printf("state%d\n", snum); + } + + int foundA = 0, count = 0; + struct dirent *de; + while ((de = readdir(d))) { + // printf("state%d: dirent: %s\n", snum, de->d_name); + if (strcmp(de->d_name, "A") == 0) + foundA = 1; + count++; + } + + closedir(d); + + //printf("found A: %d\n", foundA); + + // Ensure atomic write + char buf[64]; + sprintf(buf, "COUNT: %d\n", count); + fputs(buf, stdout); + assert(hasA == foundA); + + return 0; +} diff --git a/test/Runtime/POSIX/DirSeek.c b/test/Runtime/POSIX/DirSeek.c new file mode 100644 index 00000000..1735fdb8 --- /dev/null +++ b/test/Runtime/POSIX/DirSeek.c @@ -0,0 +1,57 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc +// RUN: %klee --run-in=/tmp --init-env --libc=uclibc --posix-runtime --exit-on-error %t2.bc --sym-files 2 2 +// RUN: %klee --run-in=/tmp --init-env --libc=uclibc --posix-runtime --exit-on-error %t2.bc --sym-files 1 2 +// RUN: %klee --run-in=/tmp --init-env --libc=uclibc --posix-runtime --exit-on-error %t2.bc --sym-files 0 2 + +// For this test really to work as intended it needs to be run in a +// directory large enough to cause uclibc to do multiple getdents +// calls (otherwise uclibc will handle the seeks itself). We should +// create a bunch of files or something. + +#include <assert.h> +#include <stdio.h> +#include <stdlib.h> +#include <dirent.h> +#include <sys/stat.h> +#include <errno.h> +#include <string.h> + +int main(int argc, char **argv) { + struct stat s; + + char first[256], second[256]; + DIR *d = opendir("."); + struct dirent *de = readdir(d); + assert(de); + strcpy(first, de->d_name); + off_t pos = telldir(d); + printf("pos: %d\n", telldir(d)); + de = readdir(d); + assert(de); + strcpy(second, de->d_name); + + // Go back to second and check + seekdir(d, pos); + de = readdir(d); + assert(de); + assert(strcmp(de->d_name, second) == 0); + + // Go to end, then back to 2nd + while (de) + de = readdir(d); + assert(!errno); + seekdir(d, pos); + assert(telldir(d) == pos); + de = readdir(d); + assert(de); + assert(strcmp(de->d_name, second) == 0); + + // Go to beginning and check + rewinddir(d); + de = readdir(d); + assert(de); + assert(strcmp(de->d_name, first) == 0); + closedir(d); + + return 0; +} diff --git a/test/Runtime/POSIX/FDNumbers.c b/test/Runtime/POSIX/FDNumbers.c new file mode 100644 index 00000000..e576f9bb --- /dev/null +++ b/test/Runtime/POSIX/FDNumbers.c @@ -0,0 +1,24 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc +// RUN: %klee --init-env --posix-runtime --exit-on-error %t2.bc --sym-files 1 10 + +#include <assert.h> +#include <fcntl.h> +#include <errno.h> + +int main(int argc, char **argv) { + int fd = open("A", O_TRUNC); + assert(fd == 3); + assert(!close(0)); + assert(!close(1)); + assert(close(0) == -1); + assert(close(1) == -1); + assert(open("A", O_TRUNC) == 0); + assert(dup(0) == 1); + assert(open("A", O_TRUNC) == 4); + assert(!close(1)); + assert(open("A", O_TRUNC) == 1); + assert(dup(0) != 1); + assert(dup2(0,1) == 1); + + return 0; +} diff --git a/test/Runtime/POSIX/FD_Fail.c b/test/Runtime/POSIX/FD_Fail.c new file mode 100644 index 00000000..cf1d4d5a --- /dev/null +++ b/test/Runtime/POSIX/FD_Fail.c @@ -0,0 +1,25 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --libc=uclibc --posix-runtime --init-env %t1.bc --sym-files 0 0 --max-fail 1 > %t.log +// RUN: grep -q "fread(): ok" %t.log +// RUN: grep -q "fread(): fail" %t.log +// RUN: grep -q "fclose(): ok" %t.log +// RUN: grep -q "fclose(): fail" %t.log + +#include <stdio.h> +#include <assert.h> + +int main(int argc, char** argv) { + char buf[1024]; + FILE* f = fopen("/etc/fstab", "r"); + assert(f); + + int r = fread(buf, 1, 100, f); + printf("fread(): %s\n", + r ? "ok" : "fail"); + + r = fclose(f); + printf("fclose(): %s\n", + r ? "ok" : "fail"); + + return 0; +} diff --git a/test/Runtime/POSIX/FD_Fail2.c b/test/Runtime/POSIX/FD_Fail2.c new file mode 100644 index 00000000..c9195f66 --- /dev/null +++ b/test/Runtime/POSIX/FD_Fail2.c @@ -0,0 +1,34 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --libc=uclibc --posix-runtime --init-env %t1.bc --sym-files 0 0 --max-fail 1 +// RUN: test -f klee-last/test000001.bout +// RUN: test -f klee-last/test000002.bout +// RUN: test -f klee-last/test000003.bout +// RUN: test -f klee-last/test000004.bout +// RUN: test -f klee-last/test000005.bout +// RUN: test -f klee-last/test000006.bout +// RUN: test -f klee-last/test000007.bout + +#include <stdio.h> +#include <assert.h> +#include <errno.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +int main(int argc, char** argv) { + char buf[1024]; + int fd = open("/etc/fstab", O_RDONLY); + assert(fd != -1); + + int r = read(fd, buf, 1, 100); + if (r != -1) + printf("read() succeeded\n"); + else printf("read() failed with errno %s\n", strerror(errno)); + + r = close(fd); + if (r != -1) + printf("close() succeeded\n"); + else printf("close() failed with errno %s\n", strerror(errno)); + + return 0; +} diff --git a/test/Runtime/POSIX/Fcntl.c b/test/Runtime/POSIX/Fcntl.c new file mode 100644 index 00000000..139fb1f3 --- /dev/null +++ b/test/Runtime/POSIX/Fcntl.c @@ -0,0 +1,17 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc +// RUN: %klee --init-env --posix-runtime --exit-on-error %t2.bc --sym-files 1 10 + +#include <assert.h> +#include <fcntl.h> + +int main(int argc, char **argv) { + int fd = open("A", O_RDWR|O_TRUNC); + if (fd == -1) + klee_silent_exit(0); + assert(fd == 3); + assert((fcntl(fd, F_GETFD) & FD_CLOEXEC) == 0); + assert(fcntl(fd, F_SETFD, FD_CLOEXEC, 1) == 0); + assert((fcntl(fd, F_GETFD) & FD_CLOEXEC) != 0); + + return 0; +} diff --git a/test/Runtime/POSIX/FilePerm.c b/test/Runtime/POSIX/FilePerm.c new file mode 100644 index 00000000..818d482f --- /dev/null +++ b/test/Runtime/POSIX/FilePerm.c @@ -0,0 +1,20 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --posix-runtime --init-env %t.bc --sym-files 1 10 --sym-stdout 2>%t.log +// RUN: test -f klee-last/test000001.bout +// RUN: test -f klee-last/test000002.bout +// RUN: test -f klee-last/test000003.bout + +#include <stdio.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + +int main(int argc, char** argv) { + int fd = open("A", O_RDWR); + if (fd != -1) + fprintf(stderr, "File 'A' opened successfully\n"); + else fprintf(stderr, "Cannot open file 'A'\n"); + + if (fd != -1) + close(fd); +} diff --git a/test/Runtime/POSIX/FreeArgv.c b/test/Runtime/POSIX/FreeArgv.c new file mode 100644 index 00000000..37909b80 --- /dev/null +++ b/test/Runtime/POSIX/FreeArgv.c @@ -0,0 +1,20 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --init-env --posix-runtime %t.bc --sym-args 1 1 1 +// RUN: test -f klee-last/test000001.free.err +// RUN: test -f klee-last/test000002.free.err +// RUN: test -f klee-last/test000003.free.err + +int main(int argc, char **argv) { + switch(klee_range(0, 3, "range")) { + case 0: + free(argv); + break; + case 1: + free(argv[0]); + break; + case 2: + free(argv[1]); + break; + } + return 0; +} diff --git a/test/Runtime/POSIX/Getenv.c b/test/Runtime/POSIX/Getenv.c new file mode 100644 index 00000000..7ec66788 --- /dev/null +++ b/test/Runtime/POSIX/Getenv.c @@ -0,0 +1,21 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc +// RUN: %klee --init-env --libc=klee --posix-runtime --exit-on-error %t2.bc --sym-files 1 10 + +#include <assert.h> + +int main(int argc, char **argv) { + char *g = getenv("PWD"); + if (g) { + printf("have PWD\n"); + } else { + printf("have no PWD\n"); + } + + g = getenv("HELLO"); + if (!g || strcmp(g, "nice")==0) { + printf("getenv(\"HELLO\") = %p\n", g); + if (g) assert(strcmp(getenv("HELLO"),"nice") == 0); + } + + return 0; +} diff --git a/test/Runtime/POSIX/Ioctl.c b/test/Runtime/POSIX/Ioctl.c new file mode 100644 index 00000000..0e7b2cad --- /dev/null +++ b/test/Runtime/POSIX/Ioctl.c @@ -0,0 +1,31 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --init-env --posix-runtime --exit-on-error %t.bc --sym-files 0 4 + +#include <assert.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <termios.h> +#include <asm/ioctls.h> +#include <errno.h> +#include <stdio.h> + +int main(int argc, char **argv) { + struct stat s; + struct termios ts; + + assert(fstat(0, &s) == 0); + + assert(ioctl(10, FIONREAD, &ts) == -1 && errno == EBADF); + + if (S_ISCHR(s.st_mode)) { + printf("is chr\n"); + assert(ioctl(0, TIOCGWINSZ, &ts) == 0); + } else { + printf("not chr\n"); + // I think TC* ioctls basically always fail on nonchr? + assert(ioctl(0, TIOCGWINSZ, &ts) == -1); + assert(errno == ENOTTY); + } + + return 0; +} diff --git a/test/Runtime/POSIX/Isatty.c b/test/Runtime/POSIX/Isatty.c new file mode 100644 index 00000000..6a78dc96 --- /dev/null +++ b/test/Runtime/POSIX/Isatty.c @@ -0,0 +1,33 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --libc=uclibc --posix-runtime --init-env %t.bc --sym-files 0 10 --sym-stdout 2>%t.log + +// RUN: test -f klee-last/test000001.bout +// RUN: test -f klee-last/test000002.bout +// RUN: test -f klee-last/test000003.bout +// RUN: test -f klee-last/test000004.bout + +// RUN: grep -q "stdin is a tty" %t.log +// RUN: grep -q "stdin is NOT a tty" %t.log +// RUN: grep -q "stdout is a tty" %t.log +// RUN: grep -q "stdout is NOT a tty" %t.log + +#include <unistd.h> +#include <stdio.h> +#include <assert.h> + +int main(int argc, char** argv) { + int fd0 = 0; // stdin + int fd1 = 1; // stdout + + int r = isatty(fd0); + if (r) + fprintf(stderr, "stdin is a tty\n"); + else fprintf(stderr, "stdin is NOT a tty\n"); + + r = isatty(fd1); + if (r) + fprintf(stderr, "stdout is a tty\n"); + else fprintf(stderr, "stdout is NOT a tty\n"); + + return 0; +} diff --git a/test/Runtime/POSIX/PrgName.c b/test/Runtime/POSIX/PrgName.c new file mode 100644 index 00000000..19a56889 --- /dev/null +++ b/test/Runtime/POSIX/PrgName.c @@ -0,0 +1,31 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t2.bc +// RUN: %klee --init-env --posix-runtime --exit-on-error %t2.bc --sym-arg 10 >%t.log +// RUN: test -f klee-last/test000001.bout +// RUN: test -f klee-last/test000002.bout +// RUN: grep -q "No" %t.log +// RUN: grep -qv "Yes" %t.log + + +/* Simple test for argv[0] */ + +#include <stdio.h> + +int f(int argc, char **argv) { + + if (argv[0][5] == '7') + printf("Yes\n"); + else printf("No\n"); + + printf("%c\n", argv[0][5]); + + if (argv[1][1] == 4) + printf("4\n"); + printf("not 4\n"); + + return 0; +} + + +int main(int argc, char **argv) { + f(argc, argv); +} diff --git a/test/Runtime/POSIX/Read1.c b/test/Runtime/POSIX/Read1.c new file mode 100644 index 00000000..3b24bfb9 --- /dev/null +++ b/test/Runtime/POSIX/Read1.c @@ -0,0 +1,34 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --exit-on-error --posix-runtime --init-env %t.bc --sym-files 1 8 >%t.log + +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> +#include <errno.h> +#include <assert.h> + +int main(int argc, char** argv) { + char buf[32]; + + // If count is zero, read() returns zero and has no other results. (man page) + int x = read(0, 0, 0); + assert(x == 0); + + int fd = open("A", O_RDONLY); + assert(fd != -1); + + // EFAULT buf is outside your accessible address space. (man page) + x = read(fd, 0, 1); + assert(x == -1 && errno == EFAULT); + + // EBADF fd is not a valid file descriptor (man page) + x = read(-1, buf, 1); + assert(x == -1 && errno == EBADF); + + fd = open("A", O_RDONLY); + assert(fd != -1); + x = read(fd, buf, 1); + assert(x == 1); +} + diff --git a/test/Runtime/POSIX/SELinux.c b/test/Runtime/POSIX/SELinux.c new file mode 100644 index 00000000..65dd1a7f --- /dev/null +++ b/test/Runtime/POSIX/SELinux.c @@ -0,0 +1,30 @@ +/* Very basic test, as right now SELinux support is extremely basic */ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --posix-runtime --exit-on-error %t1.bc --sym-arg 2 > %t.log +// XFAIL: no-selinux + +#include <selinux/selinux.h> +#include <stdio.h> +#include <assert.h> + +int main(int argc, char** argv) { + + security_context_t con; + + assert(argc == 2); + + int selinux = is_selinux_enabled(); + printf("selinux enabled = %d\n", selinux); + + if (setfscreatecon(argv[1]) < 0) + printf("Error: set\n"); + else printf("Success: set\n"); + + if (getfscreatecon(&con) < 0) + printf("Error: get\n"); + else printf("Success: get\n"); + + printf("create_con = %s\n", con); + + return 0; +} diff --git a/test/Runtime/POSIX/SeedAndFail.c b/test/Runtime/POSIX/SeedAndFail.c new file mode 100644 index 00000000..64cf79bd --- /dev/null +++ b/test/Runtime/POSIX/SeedAndFail.c @@ -0,0 +1,38 @@ +// RUN: %llvmgcc %s -emit-llvm -g -O0 -c -o %t.bc +// RUN: rm -rf tmp-123 +// RUN: %klee --libc=klee --output-dir=tmp-123 --posix-runtime --init-env %t.bc --sym-files 1 10 2>%t.log +// RUN: klee --seed-out-dir=tmp-123 --zero-seed-extension --libc=uclibc --posix-runtime --init-env %t.bc --sym-files 1 10 --max-fail 1 +// RUN: ls klee-last | grep -c assert | grep 4 + + + +#include <stdio.h> +#include <assert.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/stat.h> +#include <fcntl.h> + + +int main(int argc, char** argv) { + char buf[32]; + + int fd = open("A", O_RDWR | O_CREAT, S_IRWXU); + assert(fd != -1); + int nbytes = write(fd, "Hello", sizeof("Hello")); + assert(nbytes == sizeof("Hello")); + + off_t off = lseek(fd, 0, SEEK_SET); + assert(off != (off_t) -1); + + nbytes = read(fd, buf, sizeof("Hello")); + assert(nbytes == sizeof("Hello")); + + int r = close(fd); + assert(r == 0); + + r = memcmp(buf, "Hello", sizeof("Hello")); + assert(r == 0); + + return 0; +} diff --git a/test/Runtime/POSIX/Stdin.c b/test/Runtime/POSIX/Stdin.c new file mode 100644 index 00000000..065533a1 --- /dev/null +++ b/test/Runtime/POSIX/Stdin.c @@ -0,0 +1,56 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --init-env --libc=klee --posix-runtime --exit-on-error %t.bc --sym-files 0 4 > %t.log +// RUN: grep "mode:file" %t.log +// RUN: grep "mode:dir" %t.log +// RUN: grep "mode:chr" %t.log +// RUN: grep "mode:blk" %t.log +// RUN: grep "mode:fifo" %t.log +// RUN: grep "mode:lnk" %t.log +// RUN: grep "read:sym:yes" %t.log +// RUN: grep "read:sym:no" %t.log + +#include <stdio.h> +#include <fcntl.h> +#include <sys/stat.h> +#include <assert.h> + +int main(int argc, char **argv) { + struct stat stats; + assert(fstat(0, &stats) == 0); + + if (S_ISREG(stats.st_mode)) { + printf("mode:file\n"); + } else if (S_ISDIR(stats.st_mode)) { + printf("mode:dir\n"); + } else if (S_ISCHR(stats.st_mode)) { + printf("mode:chr\n"); + } else if (S_ISBLK(stats.st_mode)) { + printf("mode:blk\n"); + } else if (S_ISFIFO(stats.st_mode)) { + printf("mode:fifo\n"); + } else if (S_ISLNK(stats.st_mode)) { + printf("mode:lnk\n"); + } else if (S_ISSOCK(stats.st_mode)) { + printf("mode:sock\n"); + } else { + printf("unknown mode\n"); + } + + assert(stats.st_size==4); + + if (S_ISREG(stats.st_mode)) { + char buf[10]; + int n = read(0, buf, 5); + assert(n == 4); + + if (strcmp(buf, "HI!")) { + printf("read:sym:yes\n"); + } else { + printf("read:sym:no\n"); + } + } + + fflush(stdout); + + return 0; +} diff --git a/test/Runtime/POSIX/Write1.c b/test/Runtime/POSIX/Write1.c new file mode 100644 index 00000000..73902363 --- /dev/null +++ b/test/Runtime/POSIX/Write1.c @@ -0,0 +1,23 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --exit-on-error --libc=uclibc --posix-runtime --init-env %t.bc --sym-files 1 10 --sym-stdout 2>%t.log + +#include <stdio.h> +#include <assert.h> + +int main(int argc, char** argv) { + char buf[32]; + + FILE* f = fopen("A", "w"); + if (!f) + klee_silent_exit(0); + fwrite("Hello", sizeof("Hello"), 1, f); + fclose(f); + + f = fopen("A", "r"); + fread(buf, sizeof("Hello"), 1, f); + fclose(f); + + assert(memcmp(buf, "Hello", sizeof("Hello")) == 0); + + return 0; +} diff --git a/test/Runtime/POSIX/Write2.c b/test/Runtime/POSIX/Write2.c new file mode 100644 index 00000000..4865b479 --- /dev/null +++ b/test/Runtime/POSIX/Write2.c @@ -0,0 +1,21 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t.bc +// RUN: %klee --exit-on-error --libc=uclibc --posix-runtime --init-env %t.bc --sym-files 1 10 --sym-stdout 2>%t.log + +#include <stdio.h> +#include <assert.h> + +int main(int argc, char** argv) { + const char* msg = "This will eventually overflow stdout. "; + char buf[32]; + int i; + + FILE* f = stdout;//fopen("A", "w"); + if (!f) + klee_silent_exit(0); + + for (i = 0; i < 300; i++) + fwrite(msg, sizeof(msg), 1, f); + fclose(f); + + return 0; +} diff --git a/test/Runtime/POSIX/dg.exp b/test/Runtime/POSIX/dg.exp new file mode 100644 index 00000000..88406208 --- /dev/null +++ b/test/Runtime/POSIX/dg.exp @@ -0,0 +1,5 @@ +load_lib llvm.exp + +if { [klee_supports_posix_runtime] } { + RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] +} diff --git a/test/Runtime/Uclibc/2007-10-08-optimization-calls-wrong-libc-functions.c b/test/Runtime/Uclibc/2007-10-08-optimization-calls-wrong-libc-functions.c new file mode 100644 index 00000000..83e6a57a --- /dev/null +++ b/test/Runtime/Uclibc/2007-10-08-optimization-calls-wrong-libc-functions.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --exit-on-error --optimize --libc=uclibc %t1.bc + +#include <string.h> +#include <assert.h> + +int main() { + int a; + + klee_make_symbolic(&a, sizeof a); + + memset(&a, 0, sizeof a); + + if (a) { + assert(0); + } + + return 0; +} diff --git a/test/Runtime/Uclibc/2008-03-04-libc-atexit-uses-dso-handle.c b/test/Runtime/Uclibc/2008-03-04-libc-atexit-uses-dso-handle.c new file mode 100644 index 00000000..686bec19 --- /dev/null +++ b/test/Runtime/Uclibc/2008-03-04-libc-atexit-uses-dso-handle.c @@ -0,0 +1,12 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --exit-on-error --libc=uclibc %t1.bc + +// just make sure atexit works ok + +void boo() { +} + +int main() { + atexit(boo); + return 0; +} diff --git a/test/Runtime/Uclibc/Environ.c b/test/Runtime/Uclibc/Environ.c new file mode 100644 index 00000000..63892db5 --- /dev/null +++ b/test/Runtime/Uclibc/Environ.c @@ -0,0 +1,10 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee --libc=uclibc --exit-on-error %t1.bc + +#include <assert.h> + +int main() { + printf("HOME: %s\n", getenv("HOME")); + assert(getenv("HOME") != 0); + return 0; +} diff --git a/test/Runtime/Uclibc/dg.exp b/test/Runtime/Uclibc/dg.exp new file mode 100644 index 00000000..9c1663c3 --- /dev/null +++ b/test/Runtime/Uclibc/dg.exp @@ -0,0 +1,5 @@ +load_lib llvm.exp + +if { [klee_supports_uclibc] } { + RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] +} diff --git a/test/TestRunner.sh b/test/TestRunner.sh new file mode 100755 index 00000000..3e2cace4 --- /dev/null +++ b/test/TestRunner.sh @@ -0,0 +1,36 @@ +#!/bin/sh +# +# TestRunner.sh - This script is used to run the deja-gnu tests exactly like +# deja-gnu does, by executing the Tcl script specified in the test case's +# RUN: lines. This is made possible by a simple make target supported by the +# test/Makefile. All this script does is invoke that make target. +# +# Usage: +# TestRunner.sh {script_names} +# +# This script is typically used by cd'ing to a test directory and then +# running TestRunner.sh with a list of test file names you want to run. +# +TESTPATH=`pwd` +SUBDIR="" +if test `dirname $1` = "." ; then + while test `basename $TESTPATH` != "test" -a ! -z "$TESTPATH" ; do + tmp=`basename $TESTPATH` + SUBDIR="$tmp/$SUBDIR" + TESTPATH=`dirname $TESTPATH` + done +fi + +for TESTFILE in "$@" ; do + if test `dirname $TESTFILE` = . ; then + if test -d "$TESTPATH" ; then + cd $TESTPATH + make check-one TESTONE="$SUBDIR$TESTFILE" + cd $PWD + else + echo "Can't find klee/test directory in " `pwd` + fi + else + make check-one TESTONE=$TESTFILE + fi +done diff --git a/test/lib/llvm.exp b/test/lib/llvm.exp new file mode 100644 index 00000000..2857dd82 --- /dev/null +++ b/test/lib/llvm.exp @@ -0,0 +1,213 @@ +# This procedure executes one line of a test case's execution script. +proc execOneLine { test PRS outcome lineno line } { + set status 0 + set resultmsg "" + set retval [ catch { eval exec -keepnewline -- $line } errmsg ] + if { $retval != 0 } { + set code [lindex $::errorCode 0] + set lineno [expr $lineno + 1] + if { $PRS != ""} { + set PRS " for $PRS" + } + set errmsg " at line $lineno\nwhile running: $line\n$errmsg" + switch "$code" { + CHILDSTATUS { + set status [lindex $::errorCode 2] + if { $status != 0 } { + set resultmsg "$test$PRS\nFailed with exit($status)$errmsg" + } + } + CHILDKILLED { + set signal [lindex $::errorCode 2] + set resultmsg "$test$PRS\nFailed with signal($signal)$errmsg" + } + CHILDSUSP { + set signal [lindex $::errorCode 2] + set resultmsg "$test$PRS\nFailed with suspend($signal)$errmsg" + } + POSIX { + set posixNum [lindex $::errorCode 1] + set posixMsg [lindex $::errorCode 2] + set resultmsg "$test$PRS\nFailed with posix($posixNum,$posixMsg)$errmsg" + } + NONE { + } + default { + } + } + } + return $resultmsg +} + +# This procedure performs variable substitutions on the RUN: lines of a test +# cases. +proc substitute { line test tmpFile } { + global srcroot objroot srcdir objdir subdir target_triplet prcontext + global llvmgcc llvmgxx llvmgcc_version llvmgccmajvers + global gccpath gxxpath compile_c compile_cxx link shlibext llvmlibsdir + global llvmtoolsdir + set path [file join $srcdir $subdir] + + # Substitute all Tcl variables. + set new_line [subst $line ] + + #replace %prcontext with prcontext.tcl (Must replace before %p) + regsub -all {%prcontext} $new_line $prcontext new_line + #replace %llvmgcc with actual path to llvmgcc + regsub -all {%llvmgcc} $new_line "$llvmgcc -emit-llvm" new_line + #replace %llvmgxx with actual path to llvmg++ + regsub -all {%llvmgxx} $new_line "$llvmgxx -emit-llvm" new_line + #replace %compile_c with C compilation command + regsub -all {%compile_c} $new_line "$compile_c" new_line + #replace %compile_cxx with C++ compilation command + regsub -all {%compile_cxx} $new_line "$compile_cxx" new_line + #replace %link with C++ link command + regsub -all {%link} $new_line "$link" new_line + #replace %shlibext with shared library extension + regsub -all {%shlibext} $new_line "$shlibext" new_line + #replace %llvmlibsdir with configure library directory + regsub -all {%llvmlibsdir} $new_line "$llvmlibsdir" new_line + #replace %klee with klee binary + regsub -all {%klee} $new_line "klee" new_line + #replace %kleaver with kleaver binary + regsub -all {%kleaver} $new_line "kleaver" new_line + #replace %p with path to source, + regsub -all {%p} $new_line [file join $srcdir $subdir] new_line + #replace %s with filename + regsub -all {%s} $new_line $test new_line + #replace %t with temp filenames + regsub -all {%t} $new_line $tmpFile new_line + #replace %% with % + regsub -all {%%} $new_line % new_line + return $new_line +} + +# This procedure runs the set of tests for the test_source_files array. +proc RunLLVMTests { test_source_files } { + global srcroot objroot srcdir objdir subdir TEST_FEATURE_LIST target_triplet + set timeout 60 + + set path [file join $objdir $subdir] + + #Make Output Directory if it does not exist already + if { [file exists path] } { + cd $path + } else { + file mkdir $path + cd $path + } + + file mkdir Output + cd Output + + foreach test $test_source_files { + #Should figure out best way to set the timeout + #set timeout 40 + + set filename [file tail $test] + set outcome PASS + set tmpFile "$filename.tmp" + + #set hasRunline bool to check if testcase has a runline + set numLines 0 + + # Open the test file and start reading lines + set testFileId [ open $test r] + set runline "" + set PRNUMS "" + foreach line [split [read $testFileId] \n] { + + # if its the END. line then stop parsing (optimization for big files) + if {[regexp {END.[ *]$} $line match endofscript]} { + break + + # if the line is continued, concatenate and continue the loop + } elseif {[regexp {RUN: *(.+)(\\)$} $line match oneline suffix]} { + set runline "$runline$oneline " + + # if its a terminating RUN: line then do substitution on the whole line + # and then save the line. + } elseif {[regexp {RUN: *([^&]+)(&&)?} $line match oneline suffix]} { + set runline "$runline$oneline" + set runline [ substitute $runline $test $tmpFile ] + set lines($numLines) $runline + set numLines [expr $numLines + 1] + set runline "" + + # if its an PR line, save the problem report number + } elseif {[regexp {PR([0-9]+)} $line match prnum]} { + if {$PRNUMS == ""} { + set PRNUMS "PR$prnum" + } else { + set PRNUMS "$PRNUMS,$prnum" + } + # if its an XFAIL line, see if we should be XFAILing or not. + } elseif {[regexp {XFAIL:[ *](.+)} $line match features]} { + set features + + foreach feature [split $features ,] { + if { [regexp {\*} $feature match] } { + set outcome XFAIL + } elseif { [regexp $feature $target_triplet match] } { + set outcome XFAIL + } elseif { [regexp $feature $TEST_FEATURE_LIST match] } { + set outcome XFAIL + } + } + } + } + + # Done reading the script + close $testFileId + + + if { $numLines == 0 } { + fail "$test: \nDoes not have a RUN line\n" + } else { + set failed 0 + for { set i 0 } { $i < $numLines } { set i [ expr $i + 1 ] } { + regsub ^.*RUN:(.*) $lines($i) \1 theLine + set resultmsg [execOneLine $test $PRNUMS $outcome $i $theLine ] + if { $resultmsg != "" } { + if { $outcome == "XFAIL" } { + xfail "$resultmsg" + } else { + fail "$resultmsg" + } + set failed 1 + break + } + } + if { $failed } { + continue + } else { + if { $PRNUMS != "" } { + set PRNUMS " for $PRNUMS" + } + if { $outcome == "XFAIL" } { + xpass "$test$PRNUMS" + } else { + pass "$test$PRNUMS" + } + } + } + } +} + +# Check if klee was configured with POSIX runtime support. +proc klee_supports_posix_runtime { } { + global ENABLE_POSIX_RUNTIME + if { $ENABLE_POSIX_RUNTIME == "1" } { + return 1 + } + return 0 +} + +# Check if klee was configured with uclibc support. +proc klee_supports_uclibc { } { + global ENABLE_UCLIBC + if { $ENABLE_UCLIBC == "1" } { + return 1 + } + return 0 +} diff --git a/test/regression/2007-07-25-invalid-stp-array-binding-to-objectstate.c b/test/regression/2007-07-25-invalid-stp-array-binding-to-objectstate.c new file mode 100644 index 00000000..ad585ddd --- /dev/null +++ b/test/regression/2007-07-25-invalid-stp-array-binding-to-objectstate.c @@ -0,0 +1,20 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc + +#include <assert.h> + +int main(void) { + char c[2]; + + klee_make_symbolic(&c, sizeof(c)); + + if (c[0] > 10) { + int x; + + c[1] = 1; // copy object state + + assert(c[0] > 10); + } + + return 0; +} diff --git a/test/regression/2007-07-30-unflushed-byte.c b/test/regression/2007-07-30-unflushed-byte.c new file mode 100644 index 00000000..ba8a08a7 --- /dev/null +++ b/test/regression/2007-07-30-unflushed-byte.c @@ -0,0 +1,18 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc + +#include <assert.h> + +int main() { + char i, x[3]; + + klee_make_symbolic(&i, sizeof i); + + x[0] = i; + + // DEMAND FAILED:Memory.cpp:read8:199: <isByteFlushed(offset)> is false: "unflushed byte without cache value" + char y = x[1]; + + return 0; +} + diff --git a/test/regression/2007-08-01-bool-zext-in-call.ll b/test/regression/2007-08-01-bool-zext-in-call.ll new file mode 100644 index 00000000..3f3e26ab --- /dev/null +++ b/test/regression/2007-08-01-bool-zext-in-call.ll @@ -0,0 +1,22 @@ +; RUN: llvm-as -f %s -o - | %klee 2> %t1.log +; RUN: not test -f klee-last/test0001.abort.err + +declare void @klee_abort() + +define i32 @foo(i8 signext %val) { + %tmp = zext i8 %val to i32 + ret i32 %tmp +} + +define i32 @main() { + %res = call i32 bitcast (i32 (i8 signext)* @foo to i32 (i1)*)( i1 1 ) + %check = icmp ne i32 %res, 255 + br i1 %check, label %error, label %exit + +error: + call void @klee_abort() + unreachable + +exit: + ret i32 0 +} diff --git a/test/regression/2007-08-01-cache-unclear-on-overwrite-flushed.c b/test/regression/2007-08-01-cache-unclear-on-overwrite-flushed.c new file mode 100644 index 00000000..15f4e90e --- /dev/null +++ b/test/regression/2007-08-01-cache-unclear-on-overwrite-flushed.c @@ -0,0 +1,25 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc + +#include <assert.h> +#include <stdio.h> + +int main() { + unsigned char x; + + klee_make_symbolic(&x, sizeof x); + if (x >= 2) klee_silent_exit(0); + + char delete[2] = {0,1}; + + char tmp = delete[ x ]; + char tmp2 = delete[0]; + delete[ x ] = tmp2; + + if (x==1) { + assert(delete[1] == 0); + return 0; + } + + return 0; +} diff --git a/test/regression/2007-08-06-64bit-shift.c b/test/regression/2007-08-06-64bit-shift.c new file mode 100644 index 00000000..958e56c0 --- /dev/null +++ b/test/regression/2007-08-06-64bit-shift.c @@ -0,0 +1,20 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc + +#include <assert.h> + +int main() { + int d; + + klee_make_symbolic( &d, sizeof(d) ); + + int l = d - 1; + unsigned long long m = ((unsigned long long) l << 32) / d; + if (d==2) { + assert(m == 2147483648u); + } + + klee_silent_exit(0); + + return 0; +} diff --git a/test/regression/2007-08-06-access-after-free.c b/test/regression/2007-08-06-access-after-free.c new file mode 100644 index 00000000..a1812062 --- /dev/null +++ b/test/regression/2007-08-06-access-after-free.c @@ -0,0 +1,29 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc + +#include <assert.h> + +int main() { + int a; + unsigned char *p = malloc(4); + + klee_make_symbolic(&a, sizeof a); + klee_make_symbolic(p, sizeof p); + + p[0] |= 16; + + if (a) { + free(p); + + // this should give an error instead of + // pulling the state from the parent, where + // it is not free + assert(p[0] > 10); + + return 0; + } + + assert(p[0] > 10); + + return 0; +} diff --git a/test/regression/2007-08-08-free-zero.c b/test/regression/2007-08-08-free-zero.c new file mode 100644 index 00000000..964889a1 --- /dev/null +++ b/test/regression/2007-08-08-free-zero.c @@ -0,0 +1,8 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: ls klee-last | not grep *.err + +int main() { + free(0); + return 0; +} diff --git a/test/regression/2007-08-16-invalid-constant-value.c b/test/regression/2007-08-16-invalid-constant-value.c new file mode 100644 index 00000000..ecb3283f --- /dev/null +++ b/test/regression/2007-08-16-invalid-constant-value.c @@ -0,0 +1,31 @@ +// RUN: rm -f %t4.out %t4.err %t4.log +// RUN: %llvmgcc %s -emit-llvm -O2 -c -o %t1.bc +// RUN: llvm-as -f ../../Feature/_utils._ll -o %t2.bc +// RUN: llvm-ld -disable-opt %t1.bc %t2.bc -o %t3 +// RUN: %klee %t3.bc + +#include <assert.h> + +#include "../Feature/utils.h" + +int main() { + unsigned char a; + + klee_make_symbolic(&a, sizeof a); + + // demand was firing here because an invalid constant + // value was being created when implied value did not + // subtract using the proper type (so overflowed into + // invalid bits) + if (util_make_concat2(a+0xCD,0xCD) == 0xABCD) { + assert(!klee_is_symbolic(a)); + printf("add constant case: %d\n", a); + } + + if (util_make_concat2(0x0B-a,0xCD) == 0xABCD) { + assert(!klee_is_symbolic(a)); + printf("sub constant case: %d\n", a); + } + + return 0; +} diff --git a/test/regression/2007-08-16-valid-write-to-freed-object.c b/test/regression/2007-08-16-valid-write-to-freed-object.c new file mode 100644 index 00000000..472b7de8 --- /dev/null +++ b/test/regression/2007-08-16-valid-write-to-freed-object.c @@ -0,0 +1,24 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc + +unsigned sym() { + unsigned x; + klee_make_symbolic(&x, sizeof x); + return x; +} + +int main() { + unsigned x, y; + + // sym returns a symbolic object, but because it is + // alloca'd it is freed on sym()s return. thats fine, + // but the problem is that IVC is going to try to write + // into the object right here. + // + // to support this we need to have a facility for making + // state local copies of a freed object. + if (sym() == 0) + printf("ok\n"); + + return 0; +} diff --git a/test/regression/2007-10-11-free-of-alloca.c b/test/regression/2007-10-11-free-of-alloca.c new file mode 100644 index 00000000..71a16f6b --- /dev/null +++ b/test/regression/2007-10-11-free-of-alloca.c @@ -0,0 +1,9 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: test -f klee-last/test000001.free.err + +int main() { + int buf[4]; + free(buf); // this should give runtime error, not crash + return 0; +} diff --git a/test/regression/2007-10-11-illegal-access-after-free-and-branch.c b/test/regression/2007-10-11-illegal-access-after-free-and-branch.c new file mode 100644 index 00000000..fbbb99c3 --- /dev/null +++ b/test/regression/2007-10-11-illegal-access-after-free-and-branch.c @@ -0,0 +1,19 @@ +// RUN: %llvmgcc %s -emit-llvm -g -c -o %t1.bc +// RUN: %klee --optimize %t1.bc +// RUN: test -f klee-last/test000001.ptr.err + +#include <stdlib.h> +#include <stdio.h> +#include <assert.h> + +int main(int argc, char **argv) { + unsigned char *buf = malloc(3); + klee_make_symbolic(buf, 3); + if (buf[0]>4) klee_silent_exit(0); + unsigned char x = buf[1]; + free(buf); + if (x) + return buf[2]; + klee_silent_exit(0); + return 0; +} diff --git a/test/regression/2007-10-12-failed-make-symbolic-after-copy.c b/test/regression/2007-10-12-failed-make-symbolic-after-copy.c new file mode 100644 index 00000000..144281fa --- /dev/null +++ b/test/regression/2007-10-12-failed-make-symbolic-after-copy.c @@ -0,0 +1,22 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: test -f klee-last/test000001.bout + +int main() { + unsigned x, y[4]; + + klee_make_symbolic(&x,sizeof x); + if (x>=4) klee_silent_exit(0); + + y[x] = 0; + + if (x) { // force branch so y is copied + klee_make_symbolic(&y, sizeof y); + if (y[x]==0) klee_silent_exit(0); + return 0; // should be reachable + } else { + // force read here in case we try to optimize copies smartly later + if (y[x]==0) klee_silent_exit(0); + return 0; // not reachable + } +} diff --git a/test/regression/2008-02-11-phi-nodes-after-invoke.ll b/test/regression/2008-02-11-phi-nodes-after-invoke.ll new file mode 100644 index 00000000..f6077f25 --- /dev/null +++ b/test/regression/2008-02-11-phi-nodes-after-invoke.ll @@ -0,0 +1,47 @@ +; RUN: llvm-as -f %s -o - | %klee --no-output --exit-on-error + +declare void @klee_abort() + +define i32 @foo(i32 %val, i32 %fail) { + %code = icmp ne i32 0, %fail + br i1 %code, label %failing, label %return +failing: + unwind +return: + ret i32 %val +} + +define void @test(i32 %should_fail) { +entry: + %res0 = invoke i32 (i32, i32)* @foo(i32 0, i32 %should_fail) + to label %check_phi unwind label %error + +error: + %res1 = zext i8 1 to i32 + br label %check_phi + +check_phi: + %val = phi i32 [%never_used, %never_used_label], [%res0, %entry], [%res1, %error] + %ok = icmp eq i32 %val, %should_fail + br i1 %ok, label %exit, label %on_error + call void @klee_abort() + unreachable + +on_error: + call void @klee_abort() + unreachable + +exit: + ret void + + ;; this is so we hopefully fail if incomingBBIndex isn't set properly +never_used_label: + %never_used = zext i8 undef to i32 + br label %check_phi +} + +define i32 @main() { + call void (i32)* @test(i32 0) + call void (i32)* @test(i32 1) + ret i32 0 +} diff --git a/test/regression/2008-03-04-free-of-global.c b/test/regression/2008-03-04-free-of-global.c new file mode 100644 index 00000000..7821398d --- /dev/null +++ b/test/regression/2008-03-04-free-of-global.c @@ -0,0 +1,10 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee %t1.bc +// RUN: test -f klee-last/test000001.free.err + +int buf[4]; + +int main() { + free(buf); // this should give runtime error, not crash + return 0; +} diff --git a/test/regression/2008-03-11-free-of-malloc-zero.c b/test/regression/2008-03-11-free-of-malloc-zero.c new file mode 100644 index 00000000..d096818b --- /dev/null +++ b/test/regression/2008-03-11-free-of-malloc-zero.c @@ -0,0 +1,16 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc + +#include <stdlib.h> + +int main() { + // concrete case + void *p = malloc(0); + free(p); + + p = malloc(0); + void *arr[4] = { p, 0, 0, 0 }; + + // symbolic case + free(arr[klee_range(0, 4, "range")]); +} diff --git a/test/regression/2008-04-10-bad-alloca-free.c b/test/regression/2008-04-10-bad-alloca-free.c new file mode 100644 index 00000000..46e2b0cf --- /dev/null +++ b/test/regression/2008-04-10-bad-alloca-free.c @@ -0,0 +1,12 @@ +// RUN: %llvmgcc %s -emit-llvm -O0 -c -o %t1.bc +// RUN: %klee --exit-on-error %t1.bc + +void f(int *addr) { + klee_make_symbolic_name(addr, sizeof *addr, "moo"); +} + +int main() { + int x; + f(&x); + return x; +} diff --git a/test/regression/2008-05-23-gep-with-global-const.c b/test/regression/2008-05-23-gep-with-global-const.c new file mode 100644 index 00000000..5e03ec1d --- /dev/null +++ b/test/regression/2008-05-23-gep-with-global-const.c @@ -0,0 +1,15 @@ +// RUN: %llvmgcc -O0 -c -o %t.bc %s +// RUN: %klee --exit-on-error %t.bc + +#include <assert.h> + +int a; + +int main() { + void *p1 = &((char*) 0)[(long) &a]; + void *p2 = &a; + + assert(p1 == p2); + + return 0; +} diff --git a/test/regression/dg.exp b/test/regression/dg.exp new file mode 100644 index 00000000..879685ca --- /dev/null +++ b/test/regression/dg.exp @@ -0,0 +1,3 @@ +load_lib llvm.exp + +RunLLVMTests [lsort [glob -nocomplain $srcdir/$subdir/*.{ll,llx,c,cpp,tr}]] |