├── .gitignore ├── COPYING ├── INSTALL ├── Makefile.am ├── README ├── configure.ac ├── doc ├── Makefile.am ├── install.html.erb ├── readme.html.erb └── using.html ├── lib ├── Makefile.am ├── boolector-1.5.116-eeaf10b-121004.tar.gz └── lingeling-al6-080d45d-120922.tar.gz ├── src ├── Annotation.cc ├── Annotation.h ├── CRange.h ├── CallGraph.cc ├── CmpOverflow.cc ├── CmpSat.cc ├── CmpTautology.cc ├── Diagnostic.cc ├── Diagnostic.h ├── IdealShift.cc ├── IntGlobal.cc ├── IntGlobal.h ├── IntLibcalls.cc ├── IntRewrite.cc ├── IntSat.cc ├── LoadRewrite.cc ├── Makefile.am ├── OverflowIdiom.cc ├── OverflowSimplify.cc ├── PathGen.cc ├── PathGen.h ├── Range.cc ├── SMTBoolector.cc ├── SMTSolver.cc ├── SMTSolver.h ├── SMTSonolar.cc ├── SMTZ3.cc ├── Taint.cc ├── ValueGen.cc ├── ValueGen.h ├── cmpck ├── intck ├── llvm │ ├── DataLayout.h │ ├── DebugInfo.h │ ├── IRBuilder.h │ └── InstVisitor.h ├── ncpu ├── pcmpck └── pintck ├── test ├── Makefile.am ├── cmp │ ├── nouveau_dp.c │ └── pch_can.c ├── diagdiff ├── int │ ├── camel-2005-0102.c │ ├── chromium-gpu-117656.c │ ├── gocr-2005-1141.c │ ├── linux.h │ ├── malloc_array.c │ ├── openssh-2002-0639.c │ ├── rpc-2002-0391.c │ └── sctp-2004-2013.c ├── kint-build ├── kint-cc1 ├── kint-g++ ├── kint-gcc ├── linux │ ├── agp-2011-1745.c │ ├── agp-2011-1746.c │ ├── agp-2011-2022.c │ ├── aio-2010-3067.c │ ├── av7110-2011-0521.c │ ├── ax25-2009-2909.c │ ├── bcm-2010-2959.c │ ├── btrfs-2010-2538.c │ ├── cfg80211-2009-3280.c │ ├── cifs-2011-3191.c │ ├── gdth-2010-4157.c │ ├── kvm-2009-3638.c │ ├── linux.h │ ├── mpt2sas-2011-1494.c │ ├── oabi-2011-1759.c │ ├── pktcdvd-2010-3437.c │ ├── rose-2009-1265.c │ ├── sctp-2008-3526.c │ ├── si4713-2011-2700.c │ ├── snd-2010-3442.c │ └── xfs-2011-4077.c └── lit.cfg.in └── web └── index.html /.gitignore: -------------------------------------------------------------------------------- 1 | *~ 2 | .DS_Store 3 | Makefile.in 4 | /aclocal.m4 5 | /autom4te.cache 6 | /build* 7 | /config.h.in 8 | /config.h 9 | /config.log 10 | /config.status 11 | /configure 12 | /m4 13 | /Makefile 14 | /tools/Makefile 15 | /lib/Makefile 16 | /src/Makefile 17 | /tests/Makefile 18 | /libtool 19 | /stamp-h1 20 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | To build Kint from source code, you need LLVM 3.1 or later, and 2 | Clang. One option is to install recent versions of LLVM and Clang 3 | from Ubuntu 12.10 (earlier versions of Ubuntu have older versions 4 | of LLVM that are not compatible with Kint): 5 | 6 | $ apt-get install llvm-dev clang 7 | 8 | Another option is to build the latest LLVM & Clang, as detailed at: 9 | 10 | http://clang.llvm.org/get_started.html 11 | 12 | We use the following parameters to LLVM's configure: 13 | 14 | --enable-optimized --enable-targets=host --enable-bindings=none --enable-shared --enable-debug-symbols 15 | 16 | Then build Kint in its source root directory. 17 | 18 | If building from git, first do: 19 | 20 | $ autoreconf -fvi 21 | 22 | If building from a source tarball, skip the above step. 23 | 24 | Then configure and make. 25 | 26 | $ mkdir build 27 | $ cd build 28 | $ ../configure 29 | $ make 30 | 31 | Finally, either add `/build/bin` to PATH, or do: 32 | 33 | $ sudo make install 34 | -------------------------------------------------------------------------------- /Makefile.am: -------------------------------------------------------------------------------- 1 | SUBDIRS = lib src test doc 2 | 3 | EXTRA_DIST = COPYING INSTALL README 4 | 5 | intck_bin_distdir = intck-$(PACKAGE_VERSION)-bin 6 | 7 | intck-bin: all html 8 | rm -rf $(intck_bin_distdir) 9 | $(MKDIR_P) $(intck_bin_distdir)/bin 10 | cp bin/* $(intck_bin_distdir)/bin/ 11 | $(MKDIR_P) $(intck_bin_distdir)/lib 12 | cp lib/*.so $(intck_bin_distdir)/lib/ 13 | cp `which opt` $(intck_bin_distdir)/bin/ 14 | cp `llvm-config --libdir`/libLLVM-`llvm-config --version`* $(intck_bin_distdir)/lib/ 15 | $(MKDIR_P) $(intck_bin_distdir)/doc 16 | cp doc/*.html $(intck_bin_distdir)/doc/ 17 | tar chvjf $(intck_bin_distdir).tar.bz2 $(intck_bin_distdir) 18 | rm -rf $(intck_bin_distdir) 19 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | See INSTALL for build instructions or download prebuilt binaries. 2 | Make sure Kint binaries are in the PATH. 3 | 4 | 5 | Preparation 6 | ----------- 7 | 8 | Kint works on LLVM bitcode. To analyze a software project, the 9 | first step is to generate LLVM bitcode. Kint provides a script 10 | called `kint-build`, which both calls gcc (or g++) and in parallel 11 | uses Clang to obtain LLVM bitcode from your source code, stored in 12 | .ll files. For example: 13 | 14 | $ cd /path/to/your/project 15 | $ kint-build make 16 | 17 | 18 | Integer overflow checker 19 | ------------------------ 20 | 21 | To find integer overflows, you can first run Kint's global analysis 22 | on the generated LLVM bitcode (the .ll files) to generate some 23 | whole-program constraints that will reduce false positives in the 24 | subsequent analysis steps. This step is optional, and if it doesn't 25 | work (e.g., due to some bug), you can skip it and continue on to 26 | the next step. 27 | 28 | This global analysis writes its output back to the LLVM bitcode .ll 29 | files, so it produces no terminal output (unless you specify the 30 | -v flag). In our example, you can run the global analysis as 31 | follows: 32 | 33 | $ find . -name "*.ll" > bitcode.lst 34 | $ intglobal @bitcode.lst 35 | 36 | Finally, run the following command in the project directory. 37 | 38 | $ pintck 39 | 40 | You can find bug reports in `pintck.txt`. 41 | 42 | 43 | Taint annotation 44 | ------------------------ 45 | 46 | To help you focus on high-risk reports, the global analysis performs 47 | taint analysis that marks values derived from untrusted inputs in the 48 | generated LLVM bitcode. You can tell Kint what is taint source by 49 | annotating the target software's source code with this intrinsic 50 | function: 51 | 52 | int __kint_taint(const char *description, value, ...); 53 | 54 | Kint will mark the second argument (value) as a taint source. 'value' 55 | can be of any integer or pointer types. The return value of 56 | __kint_taint(), if used, is also considered as a taint. 57 | 58 | For Linux kernel, for example, we redefined the macro copy_from_user() 59 | and get_user() as follows: 60 | 61 | #define copy_from_user(to, from, n) \ 62 | __kint_taint("copy_from_user", (to), from, n) 63 | #define get_user(x, ptr) \ 64 | ({ (x) = *(ptr); __kint_taint("get_user", (x)); }) 65 | 66 | To annotate sensitive contexts (taint sinks, such as allocation 67 | sizes), you should change annotateSink() in Kint's src/Annotation.cc. 68 | Each pair in the 'Allocs' array specifies a function name and which of 69 | its argument is sensitive. Kint will highlight the report if it sees a 70 | tainted and overflowed value reaches that argument. 71 | 72 | You can obtain our annotated linux kernel source as follows: 73 | 74 | $ git clone -b kint git://g.csail.mit.edu/kint-linux 75 | 76 | 77 | Tautological comparison checker 78 | ------------------------------- 79 | 80 | Tautological control flow decisions (i.e., branches that are always 81 | taken or never taken) are often indicative of bugs. To find them, 82 | simply run the following command in the project directory. 83 | 84 | $ pcmpck 85 | 86 | You can find bug reports in `pcmpck.txt`. 87 | 88 | 89 | Contact 90 | ------- 91 | 92 | If you find any bugs in Kint, feel free to contact us: you can send 93 | us email at int@pdos.csail.mit.edu. 94 | -------------------------------------------------------------------------------- /configure.ac: -------------------------------------------------------------------------------- 1 | # -*- Autoconf -*- 2 | # Process this file with autoconf to produce a configure script. 3 | 4 | AC_INIT([kint],[0.3],[int@pdos.csail.mit.edu]) 5 | AC_CONFIG_AUX_DIR([build-aux]) 6 | AC_CONFIG_HEADERS([config.h]) 7 | 8 | AM_INIT_AUTOMAKE([foreign -Wall -Werror]) 9 | m4_ifdef([AM_SILENT_RULES],[AM_SILENT_RULES([yes])]) 10 | 11 | # Checks for programs. 12 | AM_PROG_CC_C_O 13 | AC_PROG_CXX 14 | m4_ifdef([AM_PROG_AR],[AM_PROG_AR]) 15 | AC_PROG_LN_S 16 | AC_PROG_MKDIR_P 17 | AC_PROG_SED 18 | 19 | LT_INIT([disable-static pic-only]) 20 | AC_PROG_LIBTOOL 21 | 22 | AC_CONFIG_FILES([ 23 | Makefile 24 | lib/Makefile 25 | src/Makefile 26 | test/Makefile 27 | test/lit.cfg 28 | doc/Makefile 29 | ]) 30 | AC_CONFIG_LINKS([ 31 | bin/kint-cc1:test/kint-cc1 32 | bin/kint-gcc:test/kint-gcc 33 | bin/kint-g++:test/kint-g++ 34 | bin/kint-build:test/kint-build 35 | bin/ncpu:src/ncpu 36 | bin/intck:src/intck 37 | bin/cmpck:src/cmpck 38 | bin/pintck:src/pintck 39 | bin/pcmpck:src/pcmpck 40 | ]) 41 | AC_OUTPUT 42 | -------------------------------------------------------------------------------- /doc/Makefile.am: -------------------------------------------------------------------------------- 1 | DOCS = readme.html install.html 2 | html-local: $(DOCS) 3 | CLEANFILES = $(DOCS) 4 | EXTRA_DIST = install.html.erb readme.html.erb 5 | 6 | install.html: $(top_srcdir)/INSTALL 7 | kramdown --template $(srcdir)/install.html.erb $< > $@ 8 | 9 | readme.html: $(top_srcdir)/README 10 | kramdown --template $(srcdir)/readme.html.erb $< > $@ 11 | -------------------------------------------------------------------------------- /doc/install.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | Kint Installation Guide 4 | 5 | 6 | 7 | 8 |

Kint Installation Guide

9 | <%= @body %> 10 | 11 | 12 | -------------------------------------------------------------------------------- /doc/readme.html.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | Kint User Guide 4 | 5 | 6 | 7 | 8 |

Kint User Guide

9 | <%= @body %> 10 | 11 | 12 | -------------------------------------------------------------------------------- /doc/using.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | Using KINT 4 | 5 | 30 | 31 | 41 | 42 | 43 | 44 | 45 | 46 |

Using KINT

47 | 48 |

49 | To explain how to use KINT to analyze a program for integer errors, 50 | we present an example of how you can build KINT and run it over an 51 | existing project. 52 | 53 |

Build KINT

54 | 55 |

56 | The first step is to check out and build the KINT source code, as 57 | follows: 58 | 59 |

 60 | nickolai@sahara:~$ git clone git://g.csail.mit.edu/kint
 61 | Cloning into 'kint'...
 62 | remote: Counting objects: 1292, done.
 63 | remote: Compressing objects: 100% (832/832), done.
 64 | remote: Total 1292 (delta 877), reused 654 (delta 446)
 65 | Receiving objects: 100% (1292/1292), 568.67 KiB | 259 KiB/s, done.
 66 | Resolving deltas: 100% (877/877), done.
 67 | nickolai@sahara:~$ cd kint
 68 | nickolai@sahara:~/kint$ cat INSTALL
 69 | ...
 70 | nickolai@sahara:~/kint$ autoreconf -fvi
 71 | autoreconf: Entering directory `.'
 72 | autoreconf: configure.ac: not using Gettext
 73 | autoreconf: running: aclocal --force 
 74 | ...
 75 | autoreconf: Leaving directory `.'
 76 | nickolai@sahara:~/kint$ mkdir build
 77 | nickolai@sahara:~/kint$ ( cd build && ../configure )
 78 | checking for a BSD-compatible install... /usr/bin/install -c
 79 | checking whether build environment is sane... yes
 80 | ...
 81 | config.status: executing libtool commands
 82 | nickolai@sahara:~/kint$ ( cd build && make )
 83 | make  all-recursive
 84 | make[1]: Entering directory `/home/nickolai/kint/build'
 85 | ...
 86 | make[1]: Leaving directory `/home/nickolai/kint/build'
 87 | nickolai@sahara:~/kint$ 
 88 | 
89 | 90 |

Extract bitcode

91 | 92 |

93 | The next step is to obtain LLVM bitcode for the software project you 94 | want to analyze. KINT provides a wrapper called kint-gcc (and 95 | kint-g++ for C++ source code), which both calls gcc 96 | (or g++) and in parallel uses Clang to obtain LLVM bitcode from 97 | your source code, which is stored in .ll files. For example: 98 | 99 |

100 | $ cd /path/to/your/project
101 | $ make CC=~/kint/build/bin/kint-gcc 
102 | 
103 | 104 |

Analyze bitcode

105 | 106 |

107 | Next, you can run KINT's global analysis on the generated LLVM bitcode 108 | (the .ll files) to generate some whole-program constraints 109 | that will reduce false positives in the subsequent analysis steps. 110 | This step is optional, and if it doesn't work (e.g., due to some bug), 111 | you can skip it and continue on to the next step. This global analysis 112 | writes its output back to the LLVM bitcode .ll files, so it 113 | produces no terminal output (unless you specify the -v flag). 114 | In our example, you can run the global analysis as follows: 115 | 116 |

117 | $ find . -name "*.ll" > bitcode.lst
118 | $ ~/kint/build/bin/intglobal @bitcode.lst
119 | 
120 | 121 |

122 | Finally, you can run KINT's pintck tool to analyze the LLVM 123 | bitcode for integer errors, or KINT's cmpck tool to analyze 124 | the LLVM bitcode for tautological control flow decisions (i.e., branches 125 | that are always taken or never taken), which are often indicative of bugs. 126 | For example: 127 | 128 |

129 | $ ~/kint/build/bin/intck main.ll
130 | $ ~/kint/build/bin/cmpck main.ll
131 | 
132 | 133 |

Contact

134 | 135 |

136 | If you find any bugs in KINT, feel free to contact us: you can send us 137 | email at . 138 | 139 | 140 | 141 | -------------------------------------------------------------------------------- /lib/Makefile.am: -------------------------------------------------------------------------------- 1 | BOOLECTOR = boolector-1.5.116-eeaf10b-121004 2 | LINGELING = lingeling-al6-080d45d-120922 3 | 4 | EXTRA_DIST = $(BOOLECTOR).tar.gz $(LINGELING).tar.gz 5 | 6 | all-local: libboolector.a 7 | 8 | libboolector.a: $(BOOLECTOR).tar.gz liblgl.a 9 | tar xzf $< 10 | $(LN_S) -f $(BOOLECTOR) boolector 11 | sed -i -e "s/CFLAGS=/CFLAGS=-fPIC /" boolector/makefile.in 12 | cd boolector && ./configure && make 13 | $(LN_S) -f boolector/libboolector.a 14 | 15 | liblgl.a: $(LINGELING).tar.gz 16 | tar xzf $< 17 | $(LN_S) -f $(LINGELING) lingeling 18 | sed -i -e "s/CFLAGS=/CFLAGS=-fPIC /" lingeling/makefile.in 19 | cd lingeling && ./configure && make 20 | $(LN_S) -f lingeling/liblgl.a 21 | -------------------------------------------------------------------------------- /lib/boolector-1.5.116-eeaf10b-121004.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CRYPTOlab/kint/c3402fa03ff76657045ca564a96176e356fa0e7a/lib/boolector-1.5.116-eeaf10b-121004.tar.gz -------------------------------------------------------------------------------- /lib/lingeling-al6-080d45d-120922.tar.gz: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/CRYPTOlab/kint/c3402fa03ff76657045ca564a96176e356fa0e7a/lib/lingeling-al6-080d45d-120922.tar.gz -------------------------------------------------------------------------------- /src/Annotation.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "Annotation.h" 16 | 17 | using namespace llvm; 18 | 19 | 20 | static inline bool needAnnotation(Value *V) { 21 | if (PointerType *PTy = dyn_cast(V->getType())) { 22 | Type *Ty = PTy->getElementType(); 23 | return (Ty->isIntegerTy() || isFunctionPointer(Ty)); 24 | } 25 | return false; 26 | } 27 | 28 | std::string getAnnotation(Value *V, Module *M) { 29 | std::string id; 30 | 31 | if (GlobalVariable *GV = dyn_cast(V)) 32 | id = getVarId(GV); 33 | else { 34 | User::op_iterator is, ie; // GEP indices 35 | Type *PTy = NULL; // Type of pointer in GEP 36 | if (GetElementPtrInst *GEP = dyn_cast(V)) { 37 | // GEP instruction 38 | is = GEP->idx_begin(); 39 | ie = GEP->idx_end() - 1; 40 | PTy = GEP->getPointerOperandType(); 41 | } else if (ConstantExpr *CE = dyn_cast(V)) { 42 | // constant GEP expression 43 | if (CE->getOpcode() == Instruction::GetElementPtr) { 44 | is = CE->op_begin() + 1; 45 | ie = CE->op_end() - 1; 46 | PTy = CE->getOperand(0)->getType(); 47 | } 48 | } 49 | // id is in the form of struct.[name].[offset] 50 | if (PTy) { 51 | SmallVector Idx(is, ie); 52 | Type *Ty = GetElementPtrInst::getIndexedType(PTy, Idx); 53 | ConstantInt *Offset = dyn_cast(ie->get()); 54 | if (Offset && isa(Ty)) 55 | id = getStructId(Ty, M, Offset->getLimitedValue()); 56 | } 57 | } 58 | 59 | return id; 60 | } 61 | 62 | static bool annotateLoadStore(Instruction *I) { 63 | std::string Anno; 64 | LLVMContext &VMCtx = I->getContext(); 65 | Module *M = I->getParent()->getParent()->getParent(); 66 | 67 | if (LoadInst *LI = dyn_cast(I)) { 68 | llvm::Value *V = LI->getPointerOperand(); 69 | if (needAnnotation(V)) 70 | Anno = getAnnotation(V, M); 71 | } else if (StoreInst *SI = dyn_cast(I)) { 72 | Value *V = SI->getPointerOperand(); 73 | if (needAnnotation(V)) 74 | Anno = getAnnotation(V, M); 75 | } 76 | 77 | if (Anno.empty()) 78 | return false; 79 | 80 | MDNode *MD = MDNode::get(VMCtx, MDString::get(VMCtx, Anno)); 81 | I->setMetadata(MD_ID, MD); 82 | return true; 83 | } 84 | 85 | static bool annotateArguments(Function &F) { 86 | bool Changed = false; 87 | LLVMContext &VMCtx = F.getContext(); 88 | 89 | // replace integer arguments with function calls 90 | for (Function::arg_iterator i = F.arg_begin(), 91 | e = F.arg_end(); i != e; ++i) { 92 | if (F.isVarArg()) 93 | break; 94 | 95 | Argument *A = &*i; 96 | IntegerType *Ty = dyn_cast(A->getType()); 97 | if (A->use_empty() || !Ty) 98 | continue; 99 | 100 | std::string Name = "kint_arg.i" + Twine(Ty->getBitWidth()).str(); 101 | Function *AF = cast( 102 | F.getParent()->getOrInsertFunction(Name, Ty, NULL)); 103 | CallInst *CI = IntrinsicInst::Create(AF, A->getName(), 104 | F.getEntryBlock().getFirstInsertionPt()); 105 | 106 | MDNode *MD = MDNode::get(VMCtx, MDString::get(VMCtx, getArgId(A))); 107 | CI->setMetadata(MD_ID, MD); 108 | A->replaceAllUsesWith(CI); 109 | Changed = true; 110 | } 111 | return Changed; 112 | } 113 | 114 | static StringRef extractConstantString(Value *V) { 115 | if (ConstantExpr *CE = dyn_cast(V)) { 116 | if (CE->isGEPWithNoNotionalOverIndexing()) 117 | if (GlobalVariable *GV = dyn_cast(CE->getOperand(0))) 118 | if (Constant *C = GV->getInitializer()) 119 | if (ConstantDataSequential *S = 120 | dyn_cast(C)) 121 | if (S->isCString()) 122 | return S->getAsCString(); 123 | } 124 | return ""; 125 | } 126 | 127 | static bool annotateTaintSource(CallInst *CI, 128 | SmallPtrSet &Erase) { 129 | LLVMContext &VMCtx = CI->getContext(); 130 | Function *F = CI->getParent()->getParent(); 131 | Function *CF = CI->getCalledFunction(); 132 | StringRef Name = CF->getName(); 133 | 134 | // linux system call arguemnts are taint 135 | if (Name.startswith("kint_arg.i") && F->getName().startswith("sys_")) { 136 | MDNode *MD = MDNode::get(VMCtx, MDString::get(VMCtx, "syscall")); 137 | CI->setMetadata(MD_TaintSrc, MD); 138 | return true; 139 | } 140 | 141 | // other taint sources: int __kint_taint(const char *, ...); 142 | if (Name == "__kint_taint") { 143 | // the 1st arg is the description 144 | StringRef Desc = extractConstantString(CI->getArgOperand(0)); 145 | // the 2nd arg and return value are tainted 146 | MDNode *MD = MDNode::get(VMCtx, MDString::get(VMCtx, Desc)); 147 | if (Instruction *I = dyn_cast_or_null(CI->getArgOperand(1))) 148 | I->setMetadata(MD_TaintSrc, MD); 149 | if (!CI->use_empty()) 150 | CI->setMetadata(MD_TaintSrc, MD); 151 | else 152 | Erase.insert(CI); 153 | return true; 154 | } 155 | return false; 156 | } 157 | 158 | static bool annotateSink(CallInst *CI) { 159 | #define P std::make_pair 160 | static std::pair Allocs[] = { 161 | P("dma_alloc_from_coherent", 1), 162 | P("__kmalloc", 0), 163 | P("kmalloc", 0), 164 | P("__kmalloc_node", 0), 165 | P("kmalloc_node", 0), 166 | P("kzalloc", 0), 167 | P("kcalloc", 0), 168 | P("kcalloc", 1), 169 | P("kmemdup", 1), 170 | P("memdup_user", 1), 171 | P("pci_alloc_consistent", 1), 172 | P("__vmalloc", 0), 173 | P("vmalloc", 0), 174 | P("vmalloc_user", 0), 175 | P("vmalloc_node", 0), 176 | P("vzalloc", 0), 177 | P("vzalloc_node", 0), 178 | }; 179 | #undef P 180 | 181 | LLVMContext &VMCtx = CI->getContext(); 182 | StringRef Name = CI->getCalledFunction()->getName(); 183 | 184 | for (unsigned i = 0; i < sizeof(Allocs) / sizeof(Allocs[0]); ++i) { 185 | if (Name == Allocs[i].first) { 186 | Value *V = CI->getArgOperand(Allocs[i].second); 187 | if (Instruction *I = dyn_cast_or_null(V)) { 188 | MDNode *MD = MDNode::get(VMCtx, MDString::get(VMCtx, Name)); 189 | I->setMetadata(MD_Sink, MD); 190 | return true; 191 | } 192 | } 193 | } 194 | return false; 195 | } 196 | 197 | 198 | bool AnnotationPass::runOnFunction(Function &F) { 199 | bool Changed = false; 200 | 201 | Changed |= annotateArguments(F); 202 | 203 | SmallPtrSet EraseSet; 204 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 205 | Instruction *I = &*i; 206 | 207 | if (isa(I) || isa(I)) { 208 | Changed |= annotateLoadStore(I); 209 | } else if (CallInst *CI = dyn_cast(I)) { 210 | if (!CI->getCalledFunction()) 211 | continue; 212 | Changed |= annotateTaintSource(CI, EraseSet); 213 | Changed |= annotateSink(CI); 214 | } 215 | } 216 | for (SmallPtrSet::iterator i = EraseSet.begin(), 217 | e = EraseSet.end(); i != e; ++i) { 218 | (*i)->eraseFromParent(); 219 | } 220 | return Changed; 221 | } 222 | 223 | bool AnnotationPass::doInitialization(Module &M) 224 | { 225 | this->M = &M; 226 | return true; 227 | } 228 | 229 | 230 | char AnnotationPass::ID; 231 | 232 | static RegisterPass 233 | X("anno", "add id annotation for load/stores; add taint annotation for calls"); 234 | 235 | 236 | -------------------------------------------------------------------------------- /src/Annotation.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #define MD_TaintSrc "taint_src" 13 | #define MD_Taint "taint" 14 | #define MD_Sink "sink" 15 | #define MD_ID "id" 16 | 17 | class AnnotationPass : public llvm::FunctionPass { 18 | protected: 19 | llvm::Module *M; 20 | public: 21 | static char ID; 22 | AnnotationPass() : FunctionPass(ID) { } 23 | 24 | virtual void getAnalysisUsage(llvm::AnalysisUsage &AU) const { 25 | AU.setPreservesCFG(); 26 | } 27 | virtual bool runOnFunction(llvm::Function &); 28 | virtual bool doInitialization(llvm::Module &); 29 | }; 30 | 31 | 32 | static inline bool isFunctionPointer(llvm::Type *Ty) { 33 | llvm::PointerType *PTy = llvm::dyn_cast(Ty); 34 | return PTy && PTy->getElementType()->isFunctionTy(); 35 | } 36 | 37 | static inline std::string getScopeName(llvm::GlobalValue *GV) { 38 | if (llvm::GlobalValue::isExternalLinkage(GV->getLinkage())) 39 | return GV->getName(); 40 | else { 41 | llvm::StringRef moduleName = llvm::sys::path::stem( 42 | GV->getParent()->getModuleIdentifier()); 43 | return "_" + moduleName.str() + "." + GV->getName().str(); 44 | } 45 | } 46 | 47 | // prefix anonymous struct name with module name 48 | static inline std::string getScopeName(llvm::StructType *Ty, llvm::Module *M) { 49 | if (Ty->getStructName().startswith("struct.anon")) { 50 | llvm::StringRef rest = Ty->getStructName().substr(6); 51 | llvm::StringRef moduleName = llvm::sys::path::stem( 52 | M->getModuleIdentifier()); 53 | return "struct._" + moduleName.str() + rest.str(); 54 | } 55 | return Ty->getStructName().str(); 56 | } 57 | 58 | static inline llvm::StringRef getLoadStoreId(llvm::Instruction *I) { 59 | if (llvm::MDNode *MD = I->getMetadata(MD_ID)) 60 | return llvm::dyn_cast(MD->getOperand(0))->getString(); 61 | return llvm::StringRef(); 62 | } 63 | 64 | static inline std::string 65 | getStructId(llvm::Type *Ty, llvm::Module *M, unsigned offset) { 66 | llvm::StructType *STy = llvm::dyn_cast(Ty); 67 | if (!STy || STy->isLiteral()) 68 | return ""; 69 | return getScopeName(STy, M) + "." + llvm::Twine(offset).str(); 70 | } 71 | 72 | static inline std::string getVarId(llvm::GlobalValue *GV) { 73 | return "var." + getScopeName(GV); 74 | } 75 | 76 | static inline std::string getArgId(llvm::Argument *A) { 77 | return "arg." + getScopeName(A->getParent()) + "." 78 | + llvm::Twine(A->getArgNo()).str(); 79 | } 80 | 81 | static inline std::string getArgId(llvm::Function *F, unsigned no) { 82 | return "arg." + getScopeName(F) + "." + llvm::Twine(no).str(); 83 | } 84 | 85 | static inline std::string getRetId(llvm::Function *F) { 86 | return "ret." + getScopeName(F); 87 | } 88 | 89 | static inline std::string getValueId(llvm::Value *V); 90 | static inline std::string getRetId(llvm::CallInst *CI) { 91 | if (llvm::Function *CF = CI->getCalledFunction()) 92 | return getRetId(CF); 93 | else { 94 | std::string sID = getValueId(CI->getCalledValue()); 95 | if (sID != "") 96 | return "ret." + sID; 97 | } 98 | return ""; 99 | } 100 | 101 | static inline std::string getValueId(llvm::Value *V) { 102 | if (llvm::Argument *A = llvm::dyn_cast(V)) 103 | return getArgId(A); 104 | else if (llvm::CallInst *CI = llvm::dyn_cast(V)) { 105 | if (llvm::Function *F = CI->getCalledFunction()) 106 | if (F->getName().startswith("kint_arg.i")) 107 | return getLoadStoreId(CI); 108 | return getRetId(CI); 109 | } else if (llvm::isa(V) || llvm::isa(V)) 110 | return getLoadStoreId(llvm::dyn_cast(V)); 111 | return ""; 112 | } 113 | 114 | -------------------------------------------------------------------------------- /src/CRange.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | 6 | // llvm::ConstantRange fixup. 7 | class CRange : public llvm::ConstantRange { 8 | typedef llvm::APInt APInt; 9 | typedef llvm::ConstantRange super; 10 | public: 11 | CRange(uint32_t BitWidth, bool isFullSet) : super(BitWidth, isFullSet) {} 12 | // Constructors. 13 | CRange(const super &CR) : super(CR) {} 14 | CRange(const APInt &Value) 15 | : super(Value) {} 16 | CRange(const APInt &Lower, const APInt &Upper) 17 | : super(Lower, Upper) {} 18 | static CRange makeFullSet(uint32_t BitWidth) { 19 | return CRange(BitWidth, true); 20 | } 21 | static CRange makeEmptySet(uint32_t BitWidth) { 22 | return CRange(BitWidth, false); 23 | } 24 | static CRange makeICmpRegion(unsigned Pred, const CRange &other) { 25 | return super::makeICmpRegion(Pred, other); 26 | } 27 | 28 | void match(const CRange &R) { 29 | if (this->getBitWidth() != R.getBitWidth()) { 30 | llvm::dbgs() << "warning: range " << *this << " " 31 | << this->getBitWidth() << " and " << R << " " 32 | << R.getBitWidth() << " unmatch\n"; 33 | *this = this->zextOrTrunc(R.getBitWidth()); 34 | } 35 | } 36 | 37 | bool safeUnion(const CRange &R) { 38 | CRange V = R, Old = *this; 39 | V.match(*this); 40 | *this = this->unionWith(V); 41 | return Old != *this; 42 | } 43 | 44 | 45 | CRange sdiv(const CRange &RHS) const { 46 | if (isEmptySet() || RHS.isEmptySet()) 47 | return makeEmptySet(getBitWidth()); 48 | // FIXME: too conservative. 49 | return makeFullSet(getBitWidth()); 50 | } 51 | 52 | }; 53 | -------------------------------------------------------------------------------- /src/CallGraph.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | #include "Annotation.h" 12 | #include "IntGlobal.h" 13 | 14 | using namespace llvm; 15 | 16 | // collect function pointer assignments in global initializers 17 | void 18 | CallGraphPass::processInitializers(Module *M, Constant *I, GlobalValue *V) { 19 | // structs 20 | if (ConstantStruct *CS = dyn_cast(I)) { 21 | StructType *STy = CS->getType(); 22 | if (!STy->hasName()) 23 | return; 24 | for (unsigned i = 0; i != STy->getNumElements(); ++i) { 25 | Type *ETy = STy->getElementType(i); 26 | if (ETy->isStructTy() || ETy->isArrayTy()) { 27 | // nested array or struct 28 | processInitializers(M, CS->getOperand(i), NULL); 29 | } else if (isFunctionPointer(ETy)) { 30 | // found function pointers in struct fields 31 | if (Function *F = dyn_cast(CS->getOperand(i))) { 32 | std::string Id = getStructId(STy, M, i); 33 | Ctx->FuncPtrs[Id].insert(F); 34 | } 35 | } 36 | } 37 | } else if (ConstantArray *CA = dyn_cast(I)) { 38 | // array of structs 39 | if (CA->getType()->getElementType()->isStructTy()) 40 | for (unsigned i = 0; i != CA->getNumOperands(); ++i) 41 | processInitializers(M, CA->getOperand(i), NULL); 42 | } else if (Function *F = dyn_cast(I)) { 43 | // global function pointer variables 44 | if (V) { 45 | std::string Id = getVarId(V); 46 | Ctx->FuncPtrs[Id].insert(F); 47 | } 48 | } 49 | } 50 | 51 | bool CallGraphPass::mergeFuncSet(FuncSet &S, const std::string &Id) { 52 | FuncPtrMap::iterator i = Ctx->FuncPtrs.find(Id); 53 | if (i != Ctx->FuncPtrs.end()) 54 | return mergeFuncSet(S, i->second); 55 | return false; 56 | } 57 | 58 | bool CallGraphPass::mergeFuncSet(FuncSet &Dst, const FuncSet &Src) { 59 | bool Changed = false; 60 | for (FuncSet::const_iterator i = Src.begin(), e = Src.end(); i != e; ++i) 61 | Changed |= Dst.insert(*i); 62 | return Changed; 63 | } 64 | 65 | 66 | bool CallGraphPass::findFunctions(Value *V, FuncSet &S) { 67 | SmallPtrSet Visited; 68 | return findFunctions(V, S, Visited); 69 | } 70 | 71 | bool CallGraphPass::findFunctions(Value *V, FuncSet &S, 72 | SmallPtrSet Visited) { 73 | if (!Visited.insert(V)) 74 | return false; 75 | 76 | // real function, S = S + {F} 77 | if (Function *F = dyn_cast(V)) { 78 | if (!F->empty()) 79 | return S.insert(F); 80 | 81 | // prefer the real definition to declarations 82 | FuncMap::iterator it = Ctx->Funcs.find(F->getName()); 83 | if (it != Ctx->Funcs.end()) 84 | return S.insert(it->second); 85 | else 86 | return S.insert(F); 87 | } 88 | 89 | // bitcast, ignore the cast 90 | if (BitCastInst *B = dyn_cast(V)) 91 | return findFunctions(B->getOperand(0), S, Visited); 92 | 93 | // const bitcast, ignore the cast 94 | if (ConstantExpr *C = dyn_cast(V)) { 95 | if (C->isCast()) 96 | return findFunctions(C->getOperand(0), S, Visited); 97 | } 98 | 99 | // PHI node, recursively collect all incoming values 100 | if (PHINode *P = dyn_cast(V)) { 101 | bool Changed = false; 102 | for (unsigned i = 0; i != P->getNumIncomingValues(); ++i) 103 | Changed |= findFunctions(P->getIncomingValue(i), S, Visited); 104 | return Changed; 105 | } 106 | 107 | // select, recursively collect both paths 108 | if (SelectInst *SI = dyn_cast(V)) { 109 | bool Changed = false; 110 | Changed |= findFunctions(SI->getTrueValue(), S, Visited); 111 | Changed |= findFunctions(SI->getFalseValue(), S, Visited); 112 | return Changed; 113 | } 114 | 115 | // arguement, S = S + FuncPtrs[arg.ID] 116 | if (Argument *A = dyn_cast(V)) 117 | return mergeFuncSet(S, getArgId(A)); 118 | 119 | // return value, S = S + FuncPtrs[ret.ID] 120 | if (CallInst *CI = dyn_cast(V)) { 121 | if (Function *CF = CI->getCalledFunction()) 122 | return mergeFuncSet(S, getRetId(CF)); 123 | 124 | // TODO: handle indirect calls 125 | return false; 126 | } 127 | 128 | // loads, S = S + FuncPtrs[struct.ID] 129 | if (LoadInst *L = dyn_cast(V)) 130 | return mergeFuncSet(S, getLoadStoreId(L)); 131 | 132 | // ignore other constant (usually null), inline asm and inttoptr 133 | if (isa(V) || isa(V) || isa(V)) 134 | return false; 135 | 136 | V->dump(); 137 | report_fatal_error("findFunctions: unhandled value type\n"); 138 | return false; 139 | } 140 | 141 | bool CallGraphPass::runOnFunction(Function *F) { 142 | bool Changed = false; 143 | 144 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 145 | Instruction *I = &*i; 146 | if (StoreInst *SI = dyn_cast(I)) { 147 | // stores to function pointers 148 | Value *V = SI->getValueOperand(); 149 | if (isFunctionPointer(V->getType())) { 150 | StringRef Id = getLoadStoreId(SI); 151 | if (!Id.empty()) 152 | Changed |= findFunctions(V, Ctx->FuncPtrs[Id]); 153 | } 154 | } else if (ReturnInst *RI = dyn_cast(I)) { 155 | // function returns 156 | if (isFunctionPointer(F->getReturnType())) { 157 | Value *V = RI->getReturnValue(); 158 | std::string Id = getRetId(F); 159 | Changed |= findFunctions(V, Ctx->FuncPtrs[Id]); 160 | } 161 | } else if (CallInst *CI = dyn_cast(I)) { 162 | // ignore inline asm or intrinsic calls 163 | if (CI->isInlineAsm() || (CI->getCalledFunction() 164 | && CI->getCalledFunction()->isIntrinsic())) 165 | continue; 166 | 167 | // might be an indirect call, find all possible callees 168 | FuncSet FS; 169 | if (!findFunctions(CI->getCalledValue(), FS)) 170 | continue; 171 | 172 | // looking for function pointer arguments 173 | for (unsigned no = 0; no != CI->getNumArgOperands(); ++no) { 174 | Value *V = CI->getArgOperand(no); 175 | if (!isFunctionPointer(V->getType())) 176 | continue; 177 | 178 | // find all possible assignments to the argument 179 | FuncSet VS; 180 | if (!findFunctions(V, VS)) 181 | continue; 182 | 183 | // update argument FP-set for possible callees 184 | for (FuncSet::iterator k = FS.begin(), ke = FS.end(); 185 | k != ke; ++k) { 186 | llvm::Function *CF = *k; 187 | std::string Id = getArgId(CF, no); 188 | Changed |= mergeFuncSet(Ctx->FuncPtrs[Id], VS); 189 | } 190 | } 191 | } 192 | } 193 | return Changed; 194 | } 195 | 196 | bool CallGraphPass::doInitialization(Module *M) { 197 | // collect function pointer assignments in global initializers 198 | Module::global_iterator i, e; 199 | for (i = M->global_begin(), e = M->global_end(); i != e; ++i) { 200 | if (i->hasInitializer()) 201 | processInitializers(M, i->getInitializer(), &*i); 202 | } 203 | 204 | // collect global function definitions 205 | for (Module::iterator f = M->begin(), fe = M->end(); f != fe; ++f) { 206 | if (f->hasExternalLinkage() && !f->empty()) 207 | Ctx->Funcs[f->getName()] = &*f; 208 | } 209 | 210 | return true; 211 | } 212 | 213 | bool CallGraphPass::doFinalization(Module *M) { 214 | // update callee mapping 215 | for (Module::iterator f = M->begin(), fe = M->end(); f != fe; ++f) { 216 | Function *F = &*f; 217 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 218 | // map callsite to possible callees 219 | if (CallInst *CI = dyn_cast(&*i)) { 220 | FuncSet &FS = Ctx->Callees[CI]; 221 | findFunctions(CI->getCalledValue(), FS); 222 | } 223 | } 224 | } 225 | return false; 226 | } 227 | 228 | bool CallGraphPass::doModulePass(Module *M) { 229 | bool Changed = true, ret = false; 230 | while (Changed) { 231 | Changed = false; 232 | for (Module::iterator i = M->begin(), e = M->end(); i != e; ++i) 233 | Changed |= runOnFunction(&*i); 234 | ret |= Changed; 235 | } 236 | return ret; 237 | } 238 | 239 | // debug 240 | void CallGraphPass::dumpFuncPtrs() { 241 | raw_ostream &OS = dbgs(); 242 | for (FuncPtrMap::iterator i = Ctx->FuncPtrs.begin(), 243 | e = Ctx->FuncPtrs.end(); i != e; ++i) { 244 | OS << i->first << "\n"; 245 | FuncSet &v = i->second; 246 | for (FuncSet::iterator j = v.begin(), ej = v.end(); 247 | j != ej; ++j) { 248 | OS << " " << ((*j)->hasInternalLinkage() ? "f" : "F") 249 | << " " << (*j)->getName() << "\n"; 250 | } 251 | } 252 | } 253 | 254 | void CallGraphPass::dumpCallees() { 255 | raw_ostream &OS = dbgs(); 256 | for (CalleeMap::iterator i = Ctx->Callees.begin(), 257 | e = Ctx->Callees.end(); i != e; ++i) { 258 | 259 | CallInst *CI = i->first; 260 | FuncSet &v = i->second; 261 | if (CI->isInlineAsm() || CI->getCalledFunction() || v.empty()) 262 | continue; 263 | 264 | CI->dump(); 265 | for (FuncSet::iterator j = v.begin(), ej = v.end(); 266 | j != ej; ++j) { 267 | OS << " " << ((*j)->hasInternalLinkage() ? "f" : "F") 268 | << " " << (*j)->getName() << "\n"; 269 | } 270 | } 271 | } 272 | 273 | -------------------------------------------------------------------------------- /src/CmpOverflow.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "cmp-overflow" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "Diagnostic.h" 10 | 11 | using namespace llvm; 12 | 13 | namespace { 14 | 15 | typedef const char *CmpStatus; 16 | static CmpStatus CMP_AXB_0 = "UMAX / b => (UMAX - a) / b"; 17 | static CmpStatus CMP_AXB_1 = "UMAX / b - a => (UMAX - a) / b"; 18 | static CmpStatus CMP_XY_X = "x * y cmp x"; 19 | static CmpStatus CMP_XY_EXT = "zext(x * y) cmp z"; 20 | 21 | struct CmpOverflow : FunctionPass { 22 | static char ID; 23 | CmpOverflow() : FunctionPass(ID) { 24 | PassRegistry &Registry = *PassRegistry::getPassRegistry(); 25 | initializeScalarEvolutionPass(Registry); 26 | } 27 | 28 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 29 | AU.setPreservesAll(); 30 | AU.addRequired(); 31 | } 32 | 33 | virtual bool runOnFunction(Function &F) { 34 | SE = &getAnalysis(); 35 | inst_iterator i, e = inst_end(F); 36 | for (i = inst_begin(F); i != e; ++i) { 37 | CallSite CS(&*i); 38 | if (CS) 39 | collect(CS); 40 | } 41 | for (i = inst_begin(F); i != e; ++i) { 42 | if (ICmpInst *ICI = dyn_cast(&*i)) 43 | check(ICI); 44 | } 45 | AxBs.clear(); 46 | return false; 47 | } 48 | 49 | private: 50 | Diagnostic Diag; 51 | ScalarEvolution *SE; 52 | // a + x * b 53 | typedef std::pair AxBTy; 54 | DenseMap AxBs; 55 | 56 | void collect(CallSite); 57 | void check(ICmpInst *); 58 | CmpStatus checkAxB(const SCEV *, const SCEV *); 59 | CmpStatus checkXY(const SCEV *, const SCEV *); 60 | }; 61 | 62 | } // anonymous namespace 63 | 64 | void CmpOverflow::collect(CallSite CS) { 65 | CallSite::arg_iterator i = CS.arg_begin(), e = CS.arg_end(); 66 | for (; i != e; ++i) { 67 | Value *V = *i; 68 | if (!SE->isSCEVable(V->getType())) 69 | continue; 70 | const SCEV *S = SE->getSCEV(V); 71 | // A + X * B 72 | if (const SCEVAddExpr *Add = dyn_cast(S)) { 73 | const SCEVConstant *A, *B; 74 | if (Add->getNumOperands() != 2) 75 | continue; 76 | A = dyn_cast(Add->getOperand(0)); 77 | if (!A) 78 | continue; 79 | const SCEVMulExpr *Mul; 80 | Mul = dyn_cast(Add->getOperand(1)); 81 | if (!Mul || Mul->getNumOperands() != 2) 82 | continue; 83 | B = dyn_cast(Mul->getOperand(0)); 84 | if (!B) 85 | continue; 86 | const SCEV *X = Mul->getOperand(1); 87 | AxBs[X] = std::make_pair(A->getValue(), B->getValue()); 88 | continue; 89 | } 90 | } 91 | } 92 | 93 | void CmpOverflow::check(ICmpInst *I) { 94 | const SCEV *L = SE->getSCEV(I->getOperand(0)); 95 | const SCEV *R = SE->getSCEV(I->getOperand(1)); 96 | CmpStatus Status = NULL; 97 | if (!Status) Status = checkAxB(L, R); 98 | if (!Status) Status = checkXY(L, R); 99 | if (!Status) return; 100 | Diag.bug("bad overflow check"); 101 | Diag << "mode: |\n " << Status << "\n"; 102 | Diag.backtrace(I); 103 | } 104 | 105 | CmpStatus CmpOverflow::checkAxB(const SCEV *L, const SCEV *R) { 106 | Type *T = L->getType(); 107 | if (!T->isIntegerTy()) 108 | return NULL; 109 | if (isa(L)) 110 | std::swap(L, R); 111 | if (!isa(R)) 112 | return NULL; 113 | AxBTy AxB = AxBs.lookup(L); 114 | if (!AxB.first || !AxB.second) 115 | return NULL; 116 | unsigned n = T->getIntegerBitWidth(); 117 | APInt Max = APInt::getMaxValue(n); 118 | const APInt &A = AxB.first->getValue(); 119 | const APInt &B = AxB.second->getValue(); 120 | const APInt &C = cast(R)->getValue()->getValue(); 121 | if (C == (Max - A).udiv(B)) 122 | return NULL; 123 | APInt C0 = Max.udiv(B); 124 | if (C == C0) 125 | return CMP_AXB_0; 126 | APInt C1 = C0 - A; 127 | if (C == C1) 128 | return CMP_AXB_1; 129 | return NULL; 130 | } 131 | 132 | static CmpStatus checkMul(const SCEV *MS, const SCEV *S) { 133 | if (const SCEVZeroExtendExpr *ZExt = dyn_cast(MS)) { 134 | if (isa(ZExt->getOperand())) 135 | return CMP_XY_EXT; 136 | } 137 | const SCEVMulExpr *Mul = dyn_cast(MS); 138 | if (!Mul) 139 | return NULL; 140 | if (Mul->getNumOperands() != 2) 141 | return NULL; 142 | if (S == Mul->getOperand(0) || S == Mul->getOperand(1)) 143 | return CMP_XY_X; 144 | 145 | return NULL; 146 | } 147 | 148 | CmpStatus CmpOverflow::checkXY(const SCEV *L, const SCEV *R) { 149 | CmpStatus Status = NULL; 150 | if (!Status) Status = checkMul(L, R); 151 | if (!Status) Status = checkMul(R, L); 152 | return NULL; 153 | } 154 | 155 | char CmpOverflow::ID; 156 | 157 | static RegisterPass 158 | X("cmp-overflow", "Detecting broken overflow checks", false, true); 159 | -------------------------------------------------------------------------------- /src/CmpSat.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "cmp-sat" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include "Diagnostic.h" 10 | #include "PathGen.h" 11 | #include "ValueGen.h" 12 | 13 | using namespace llvm; 14 | 15 | namespace { 16 | 17 | typedef const char *CmpStatus; 18 | static CmpStatus CMP_FALSE = "comparison always false"; 19 | static CmpStatus CMP_TRUE = "comparison always true"; 20 | 21 | struct CmpSat : FunctionPass { 22 | static char ID; 23 | CmpSat() : FunctionPass(ID) { 24 | PassRegistry &Registry = *PassRegistry::getPassRegistry(); 25 | initializeDataLayoutPass(Registry); 26 | initializeDominatorTreePass(Registry); 27 | } 28 | 29 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 30 | AU.addRequired(); 31 | AU.addRequired(); 32 | AU.setPreservesAll(); 33 | } 34 | 35 | virtual bool runOnFunction(Function &F) { 36 | DL = &getAnalysis(); 37 | DT = &getAnalysis(); 38 | FindFunctionBackedges(F, Backedges); 39 | for (Function::iterator i = F.begin(), e = F.end(); i != e; ++i) { 40 | BranchInst *BI = dyn_cast(i->getTerminator()); 41 | if (!BI || !BI->isConditional()) 42 | continue; 43 | check(BI); 44 | } 45 | Backedges.clear(); 46 | return false; 47 | } 48 | 49 | private: 50 | Diagnostic Diag; 51 | DataLayout *DL; 52 | DominatorTree *DT; 53 | SmallVector Backedges; 54 | 55 | void check(BranchInst *); 56 | }; 57 | 58 | } // anonymous namespace 59 | 60 | void CmpSat::check(BranchInst *I) { 61 | BasicBlock *BB = I->getParent(); 62 | Value *V = I->getCondition(); 63 | SMTSolver SMT(false); 64 | ValueGen VG(*DL, SMT); 65 | PathGen PG(VG, Backedges, *DT); 66 | SMTExpr ValuePred = VG.get(V); 67 | SMTExpr PathPred = PG.get(BB); 68 | SMTExpr Query = SMT.bvand(ValuePred, PathPred); 69 | SMTStatus Status = SMT.query(Query); 70 | SMT.decref(Query); 71 | CmpStatus Reason = 0; 72 | if (Status == SMT_UNSAT) { 73 | Reason = CMP_FALSE; 74 | } else { 75 | SMTExpr NotValuePred = SMT.bvnot(ValuePred); 76 | Query = SMT.bvand(NotValuePred, PathPred); 77 | Status = SMT.query(Query); 78 | SMT.decref(Query); 79 | SMT.decref(NotValuePred); 80 | if (Status == SMT_UNSAT) 81 | Reason = CMP_TRUE; 82 | } 83 | if (!Reason) 84 | return; 85 | Diag.bug(Reason); 86 | Diag.backtrace(I); 87 | } 88 | 89 | char CmpSat::ID; 90 | 91 | static RegisterPass 92 | X("cmp-sat", "Detecting bogus comparisons via satisfiability", false, true); 93 | -------------------------------------------------------------------------------- /src/CmpTautology.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "cmp-tautology" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include "Diagnostic.h" 9 | using namespace llvm; 10 | 11 | namespace { 12 | 13 | typedef const char *CmpStatus; 14 | static CmpStatus CMP_FALSE = "comparison always false"; 15 | static CmpStatus CMP_TRUE = "comparison always true"; 16 | 17 | struct CmpTautology : FunctionPass { 18 | static char ID; 19 | CmpTautology() : FunctionPass(ID) { 20 | PassRegistry &Registry = *PassRegistry::getPassRegistry(); 21 | initializeScalarEvolutionPass(Registry); 22 | } 23 | 24 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 25 | AU.setPreservesAll(); 26 | AU.addRequired(); 27 | } 28 | 29 | virtual bool runOnFunction(Function &F) { 30 | SE = &getAnalysis(); 31 | inst_iterator i = inst_begin(F), e = inst_end(F); 32 | for (; i != e; ++i) { 33 | if (ICmpInst *ICI = dyn_cast(&*i)) 34 | check(ICI); 35 | } 36 | return false; 37 | } 38 | 39 | private: 40 | Diagnostic Diag; 41 | ScalarEvolution *SE; 42 | 43 | void check(ICmpInst *); 44 | }; 45 | 46 | } // anonymous namespace 47 | 48 | void CmpTautology::check(ICmpInst *I) { 49 | if (!SE->isSCEVable(I->getOperand(0)->getType())) 50 | return; 51 | const SCEV *L = SE->getSCEV(I->getOperand(0)); 52 | const SCEV *R = SE->getSCEV(I->getOperand(1)); 53 | // Ignore constant comparison. 54 | if (isa(L) && isa(R)) 55 | return; 56 | // Ignore loop variables. 57 | if (isa(L) || isa(R)) 58 | return; 59 | CmpStatus Reason; 60 | if (SE->isKnownPredicate(I->getPredicate(), L, R)) 61 | Reason = CMP_TRUE; 62 | else if (SE->isKnownPredicate(I->getInversePredicate(), L, R)) 63 | Reason = CMP_FALSE; 64 | else 65 | return; 66 | Diag.bug(Reason); 67 | Diag << "model: |\n"; 68 | Diag << " lhs: " << *L << '\n'; 69 | Diag << " rhs: " << *R << '\n'; 70 | Diag.backtrace(I); 71 | } 72 | 73 | char CmpTautology::ID; 74 | 75 | static RegisterPass 76 | X("cmp-tautology", "Detecting tautological comparisons", false, true); 77 | -------------------------------------------------------------------------------- /src/Diagnostic.cc: -------------------------------------------------------------------------------- 1 | #include "Diagnostic.h" 2 | #include "SMTSolver.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace llvm; 14 | 15 | Diagnostic::Diagnostic() : OS(errs()) {} 16 | 17 | static void getPath(SmallVectorImpl &Path, const MDNode *MD) { 18 | StringRef Filename = DIScope(MD).getFilename(); 19 | if (sys::path::is_absolute(Filename)) 20 | Path.append(Filename.begin(), Filename.end()); 21 | else 22 | sys::path::append(Path, DIScope(MD).getDirectory(), Filename); 23 | } 24 | 25 | void Diagnostic::backtrace(Instruction *I) { 26 | const char *Prefix = " - "; 27 | MDNode *MD = I->getDebugLoc().getAsMDNode(I->getContext()); 28 | if (!MD) 29 | return; 30 | OS << "stack: \n"; 31 | DILocation Loc(MD); 32 | for (;;) { 33 | SmallString<64> Path; 34 | getPath(Path, Loc.getScope()); 35 | OS << Prefix << Path 36 | << ':' << Loc.getLineNumber() 37 | << ':' << Loc.getColumnNumber() << '\n'; 38 | Loc = Loc.getOrigLocation(); 39 | if (!Loc.Verify()) 40 | break; 41 | } 42 | } 43 | 44 | void Diagnostic::bug(const Twine &Str) { 45 | OS << "---\n" << "bug: " << Str << "\n"; 46 | } 47 | 48 | void Diagnostic::classify(Value *V) { 49 | Instruction *I = dyn_cast(V); 50 | if (!I) 51 | return; 52 | 53 | if (MDNode *MD = I->getMetadata("taint")) { 54 | StringRef s = dyn_cast(MD->getOperand(0))->getString(); 55 | OS << "taint: " << s << "\n"; 56 | } 57 | if (MDNode *MD = I->getMetadata("sink")) { 58 | StringRef s = dyn_cast(MD->getOperand(0))->getString(); 59 | OS << "sink: " << s << "\n"; 60 | } 61 | } 62 | 63 | void Diagnostic::status(int Status) { 64 | const char *Str; 65 | switch (Status) { 66 | case SMT_UNDEF: Str = "undef"; break; 67 | case SMT_UNSAT: Str = "unsat"; break; 68 | case SMT_SAT: Str = "sat"; break; 69 | default: Str = "timeout"; break; 70 | } 71 | OS << "status: " << Str << "\n"; 72 | } 73 | -------------------------------------------------------------------------------- /src/Diagnostic.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace llvm { 4 | class Instruction; 5 | class raw_ostream; 6 | class Twine; 7 | class Value; 8 | } // namespace llvm 9 | 10 | 11 | class Diagnostic { 12 | public: 13 | Diagnostic(); 14 | 15 | llvm::raw_ostream &os() { return OS; } 16 | 17 | void bug(const llvm::Twine &); 18 | void classify(llvm::Value *); 19 | 20 | void backtrace(llvm::Instruction *); 21 | void status(int); 22 | 23 | template Diagnostic & 24 | operator <<(const T &Val) { 25 | OS << Val; 26 | return *this; 27 | } 28 | 29 | private: 30 | llvm::raw_ostream &OS; 31 | }; 32 | -------------------------------------------------------------------------------- /src/IdealShift.cc: -------------------------------------------------------------------------------- 1 | // This pass changes the semantics of shifting instructions, by inserting 2 | // select instructions. If the shifting amount is oversized, the result 3 | // is set to either 0 (for shl/lshr) or the sign (ashr). 4 | 5 | #define DEBUG_TYPE "ideal-shift" 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace llvm; 12 | 13 | namespace { 14 | 15 | struct IdealShift : FunctionPass { 16 | static char ID; 17 | IdealShift() : FunctionPass(ID) {} 18 | 19 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 20 | AU.setPreservesAll(); 21 | } 22 | 23 | virtual bool runOnFunction(Function &); 24 | }; 25 | 26 | } // anonymous namespace 27 | 28 | bool IdealShift::runOnFunction(Function &F) { 29 | bool Changed = false; 30 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ) { 31 | Instruction *I = &*i++; 32 | unsigned Opcode = I->getOpcode(); 33 | switch (Opcode) { 34 | default: continue; 35 | case Instruction::Shl: 36 | case Instruction::LShr: 37 | case Instruction::AShr: 38 | break; 39 | } 40 | IntegerType *T = dyn_cast(I->getType()); 41 | if (!T) 42 | continue; 43 | Value *L = I->getOperand(0); 44 | Value *R = I->getOperand(1); 45 | if (isa(R)) 46 | continue; 47 | // Set the insert point to be after I since the result is used. 48 | Instruction *IP = &*i; 49 | unsigned n = T->getBitWidth(); 50 | ConstantInt *BitWidth = ConstantInt::get(T, n); 51 | ICmpInst *Cond = new ICmpInst(IP, CmpInst::ICMP_UGE, R, BitWidth); 52 | Value *IdealVal; 53 | // The ideal value is zero for logical shifts, 54 | // and the sign for arithmetic shifts. 55 | if (Opcode == Instruction::AShr) 56 | IdealVal = BinaryOperator::CreateAShr(L, ConstantInt::get(T, n - 1), "", IP); 57 | else 58 | IdealVal = Constant::getNullValue(T); 59 | // The new select instruction will use I, but we need to replace 60 | // all other uses with this select. So use a fake false value 61 | // first, and then set it to I after RAUW. 62 | SelectInst *SI = SelectInst::Create(Cond, IdealVal, IdealVal, "", IP); 63 | SI->setDebugLoc(I->getDebugLoc()); 64 | I->replaceAllUsesWith(SI); 65 | SI->setOperand(2, I); 66 | Changed = true; 67 | } 68 | return Changed; 69 | } 70 | 71 | char IdealShift::ID; 72 | 73 | static RegisterPass 74 | X("ideal-shift", "Rewrite shift instructions for ideal results for oversized shifting amount"); 75 | -------------------------------------------------------------------------------- /src/IntGlobal.cc: -------------------------------------------------------------------------------- 1 | #include "llvm/LLVMContext.h" 2 | #include "llvm/PassManager.h" 3 | #include "llvm/Module.h" 4 | #include "llvm/Analysis/Verifier.h" 5 | #include "llvm/Bitcode/ReaderWriter.h" 6 | #include "llvm/Support/CommandLine.h" 7 | #include "llvm/Support/ManagedStatic.h" 8 | #include "llvm/Support/PrettyStackTrace.h" 9 | #include "llvm/Support/ToolOutputFile.h" 10 | #include "llvm/Support/SystemUtils.h" 11 | #include "llvm/Support/IRReader.h" 12 | #include "llvm/Support/Signals.h" 13 | #include "llvm/Support/Path.h" 14 | #include 15 | #include 16 | 17 | #include "IntGlobal.h" 18 | #include "Annotation.h" 19 | 20 | using namespace llvm; 21 | 22 | static cl::list 23 | InputFilenames(cl::Positional, cl::OneOrMore, 24 | cl::desc("")); 25 | 26 | static cl::opt 27 | Verbose("v", cl::desc("Print information about actions taken")); 28 | 29 | static cl::opt 30 | NoWriteback("p", cl::desc("Do not writeback annotated bytecode")); 31 | 32 | ModuleList Modules; 33 | GlobalContext GlobalCtx; 34 | 35 | #define Diag if (Verbose) llvm::errs() 36 | 37 | void doWriteback(Module *M, StringRef name) 38 | { 39 | std::string err; 40 | OwningPtr out( 41 | new tool_output_file(name.data(), err, raw_fd_ostream::F_Binary)); 42 | if (!err.empty()) { 43 | Diag << "Cannot write back to " << name << ": " << err << "\n"; 44 | return; 45 | } 46 | M->print(out->os(), NULL); 47 | out->keep(); 48 | } 49 | 50 | 51 | void IterativeModulePass::run(ModuleList &modules) { 52 | 53 | ModuleList::iterator i, e; 54 | Diag << "[" << ID << "] Initializing " << modules.size() << " modules "; 55 | for (i = modules.begin(), e = modules.end(); i != e; ++i) { 56 | doInitialization(i->first); 57 | Diag << "."; 58 | } 59 | Diag << "\n"; 60 | 61 | unsigned iter = 0, changed = 1; 62 | while (changed) { 63 | ++iter; 64 | changed = 0; 65 | for (i = modules.begin(), e = modules.end(); i != e; ++i) { 66 | Diag << "[" << ID << " / " << iter << "] "; 67 | Diag << "'" << i->first->getModuleIdentifier() << "'"; 68 | 69 | bool ret = doModulePass(i->first); 70 | if (ret) { 71 | ++changed; 72 | Diag << " [CHANGED]\n"; 73 | } else 74 | Diag << "\n"; 75 | } 76 | Diag << "[" << ID << "] Updated in " << changed << " modules.\n"; 77 | } 78 | 79 | Diag << "\n[" << ID << "] Postprocessing ...\n"; 80 | for (i = modules.begin(), e = modules.end(); i != e; ++i) { 81 | if (doFinalization(i->first) && !NoWriteback) { 82 | Diag << "[" << ID << "] Writeback " << i->second << "\n"; 83 | doWriteback(i->first, i->second); 84 | } 85 | } 86 | 87 | Diag << "[" << ID << "] Done!\n"; 88 | } 89 | 90 | int main(int argc, char **argv) 91 | { 92 | // Print a stack trace if we signal out. 93 | sys::PrintStackTraceOnErrorSignal(); 94 | PrettyStackTraceProgram X(argc, argv); 95 | 96 | llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 97 | cl::ParseCommandLineOptions(argc, argv, "global analysis\n"); 98 | SMDiagnostic Err; 99 | 100 | // Loading modules 101 | Diag << "Total " << InputFilenames.size() << " file(s)\n"; 102 | 103 | for (unsigned i = 0; i < InputFilenames.size(); ++i) { 104 | // use separate LLVMContext to avoid type renaming 105 | LLVMContext *LLVMCtx = new LLVMContext(); 106 | Module *M = ParseIRFile(InputFilenames[i], Err, *LLVMCtx); 107 | 108 | if (M == NULL) { 109 | errs() << argv[0] << ": error loading file '" 110 | << InputFilenames[i] << "'\n"; 111 | continue; 112 | } 113 | 114 | Diag << "Loading '" << InputFilenames[i] << "'\n"; 115 | 116 | // annotate 117 | static AnnotationPass AnnoPass; 118 | AnnoPass.doInitialization(*M); 119 | for (Module::iterator j = M->begin(), je = M->end(); j != je; ++j) 120 | AnnoPass.runOnFunction(*j); 121 | if (!NoWriteback) 122 | doWriteback(M, InputFilenames[i].c_str()); 123 | 124 | Modules.push_back(std::make_pair(M, InputFilenames[i])); 125 | } 126 | 127 | // Main workflow 128 | CallGraphPass CGPass(&GlobalCtx); 129 | CGPass.run(Modules); 130 | 131 | TaintPass TPass(&GlobalCtx); 132 | TPass.run(Modules); 133 | 134 | RangePass RPass(&GlobalCtx); 135 | RPass.run(Modules); 136 | 137 | if (NoWriteback) { 138 | TPass.dumpTaints(); 139 | RPass.dumpRange(); 140 | } 141 | 142 | return 0; 143 | } 144 | 145 | -------------------------------------------------------------------------------- /src/IntGlobal.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "CRange.h" 20 | 21 | typedef std::vector< std::pair > ModuleList; 22 | typedef llvm::SmallPtrSet FuncSet; 23 | typedef std::map FuncMap; 24 | typedef std::map FuncPtrMap; 25 | typedef llvm::DenseMap CalleeMap; 26 | typedef std::set DescSet; 27 | typedef std::map RangeMap; 28 | 29 | 30 | class TaintMap { 31 | 32 | public: 33 | typedef std::map > GlobalMap; 34 | typedef std::map ValueMap; 35 | 36 | GlobalMap GTS; 37 | ValueMap VTS; 38 | 39 | void add(llvm::Value *V, const DescSet &D) { 40 | VTS[V].insert(D.begin(), D.end()); 41 | } 42 | void add(llvm::Value *V, llvm::StringRef D) { 43 | VTS[V].insert(D); 44 | } 45 | DescSet* get(llvm::Value *V) { 46 | ValueMap::iterator it = VTS.find(V); 47 | if (it != VTS.end()) 48 | return &it->second; 49 | return NULL; 50 | } 51 | 52 | DescSet* get(const std::string &ID) { 53 | if (ID.empty()) 54 | return NULL; 55 | GlobalMap::iterator it = GTS.find(ID); 56 | if (it != GTS.end()) 57 | return &it->second.first; 58 | return NULL; 59 | } 60 | bool add(const std::string &ID, const DescSet &D, bool isSource = false) { 61 | if (ID.empty()) 62 | return false; 63 | std::pair &entry = GTS[ID]; 64 | bool isNew = entry.first.empty(); 65 | entry.first.insert(D.begin(), D.end()); 66 | entry.second |= isSource; 67 | return isNew; 68 | } 69 | bool isSource(const std::string &ID) { 70 | if (ID.empty()) 71 | return false; 72 | GlobalMap::iterator it = GTS.find(ID); 73 | if (it == GTS.end()) 74 | return false; 75 | return it->second.second; 76 | } 77 | }; 78 | 79 | struct GlobalContext { 80 | // Map global function name to function defination 81 | FuncMap Funcs; 82 | 83 | // Map function pointers (IDs) to possible assignments 84 | FuncPtrMap FuncPtrs; 85 | 86 | // Map a callsite to all potential callees 87 | CalleeMap Callees; 88 | 89 | // Taints 90 | TaintMap Taints; 91 | 92 | // Ranges 93 | RangeMap IntRanges; 94 | }; 95 | 96 | class IterativeModulePass { 97 | protected: 98 | GlobalContext *Ctx; 99 | const char * ID; 100 | public: 101 | IterativeModulePass(GlobalContext *Ctx_, const char *ID_) 102 | : Ctx(Ctx_), ID(ID_) { } 103 | 104 | // run on each module before iterative pass 105 | virtual bool doInitialization(llvm::Module *M) 106 | { return true; } 107 | 108 | // run on each module after iterative pass 109 | virtual bool doFinalization(llvm::Module *M) 110 | { return true; } 111 | 112 | // iterative pass 113 | virtual bool doModulePass(llvm::Module *M) 114 | { return false; } 115 | 116 | virtual void run(ModuleList &modules); 117 | }; 118 | 119 | class CallGraphPass : public IterativeModulePass { 120 | private: 121 | bool runOnFunction(llvm::Function *); 122 | void processInitializers(llvm::Module *, llvm::Constant *, llvm::GlobalValue *); 123 | bool mergeFuncSet(FuncSet &S, const std::string &Id); 124 | bool mergeFuncSet(FuncSet &Dst, const FuncSet &Src); 125 | bool findFunctions(llvm::Value *, FuncSet &); 126 | bool findFunctions(llvm::Value *, FuncSet &, 127 | llvm::SmallPtrSet); 128 | 129 | 130 | public: 131 | CallGraphPass(GlobalContext *Ctx_) 132 | : IterativeModulePass(Ctx_, "CallGraph") { } 133 | virtual bool doInitialization(llvm::Module *); 134 | virtual bool doFinalization(llvm::Module *); 135 | virtual bool doModulePass(llvm::Module *); 136 | 137 | // debug 138 | void dumpFuncPtrs(); 139 | void dumpCallees(); 140 | }; 141 | 142 | class TaintPass : public IterativeModulePass { 143 | private: 144 | DescSet* getTaint(llvm::Value *); 145 | bool runOnFunction(llvm::Function *); 146 | bool checkTaintSource(llvm::Value *); 147 | bool markTaint(const std::string &Id, bool isSource); 148 | 149 | bool checkTaintSource(llvm::Instruction *I); 150 | bool checkTaintSource(llvm::Function *F); 151 | 152 | typedef llvm::DenseMap ValueTaintSet; 153 | ValueTaintSet VTS; 154 | 155 | public: 156 | TaintPass(GlobalContext *Ctx_) 157 | : IterativeModulePass(Ctx_, "Taint") { } 158 | virtual bool doModulePass(llvm::Module *); 159 | virtual bool doFinalization(llvm::Module *); 160 | bool isTaintSource(const std::string &sID); 161 | 162 | // debug 163 | void dumpTaints(); 164 | }; 165 | 166 | 167 | class RangePass : public IterativeModulePass { 168 | 169 | private: 170 | const unsigned MaxIterations; 171 | 172 | bool safeUnion(CRange &CR, const CRange &R); 173 | bool unionRange(llvm::StringRef, const CRange &, llvm::Value *); 174 | bool unionRange(llvm::BasicBlock *, llvm::Value *, const CRange &); 175 | CRange getRange(llvm::BasicBlock *, llvm::Value *); 176 | 177 | void collectInitializers(llvm::GlobalVariable *, llvm::Constant *); 178 | bool updateRangeFor(llvm::Function *); 179 | bool updateRangeFor(llvm::BasicBlock *); 180 | bool updateRangeFor(llvm::Instruction *); 181 | 182 | typedef std::map ValueRangeMap; 183 | typedef std::map FuncValueRangeMaps; 184 | FuncValueRangeMaps FuncVRMs; 185 | 186 | typedef std::set ChangeSet; 187 | ChangeSet Changes; 188 | 189 | typedef std::pair Edge; 190 | typedef llvm::SmallVector EdgeList; 191 | EdgeList BackEdges; 192 | 193 | bool isBackEdge(const Edge &); 194 | 195 | CRange visitBinaryOp(llvm::BinaryOperator *); 196 | CRange visitCastInst(llvm::CastInst *); 197 | CRange visitSelectInst(llvm::SelectInst *); 198 | CRange visitPHINode(llvm::PHINode *); 199 | 200 | bool visitCallInst(llvm::CallInst *); 201 | bool visitReturnInst(llvm::ReturnInst *); 202 | bool visitStoreInst(llvm::StoreInst *); 203 | 204 | void visitBranchInst(llvm::BranchInst *, 205 | llvm::BasicBlock *, ValueRangeMap &); 206 | void visitTerminator(llvm::TerminatorInst *, 207 | llvm::BasicBlock *, ValueRangeMap &); 208 | void visitSwitchInst(llvm::SwitchInst *, 209 | llvm::BasicBlock *, ValueRangeMap &); 210 | 211 | public: 212 | RangePass(GlobalContext *Ctx_) 213 | : IterativeModulePass(Ctx_, "Range"), MaxIterations(5) { } 214 | 215 | virtual bool doInitialization(llvm::Module *); 216 | virtual bool doModulePass(llvm::Module *M); 217 | virtual bool doFinalization(llvm::Module *); 218 | 219 | // debug 220 | void dumpRange(); 221 | }; 222 | 223 | 224 | -------------------------------------------------------------------------------- /src/IntLibcalls.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "int-libcalls" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace llvm; 9 | 10 | namespace { 11 | 12 | struct NamedParam { 13 | const char *Name; 14 | unsigned int Index; 15 | }; 16 | 17 | struct IntLibcalls : ModulePass { 18 | static char ID; 19 | IntLibcalls() : ModulePass(ID) {} 20 | 21 | bool runOnModule(Module &); 22 | 23 | private: 24 | typedef IRBuilder<> BuilderTy; 25 | BuilderTy *Builder; 26 | 27 | void rewriteSize(Function *F); 28 | void rewriteSizeAt(CallInst *I, NamedParam *NPs); 29 | }; 30 | 31 | } // anonymous namespace 32 | 33 | static NamedParam LLVMSize[] = { 34 | {"llvm.memcpy.p0i8.p0i8.i32", 2}, 35 | {"llvm.memcpy.p0i8.p0i8.i64", 2}, 36 | {"llvm.memmove.p0i8.p0i8.i32", 2}, 37 | {"llvm.memmove.p0i8.p0i8.i64", 2}, 38 | {"llvm.memset.p0i8.i32", 2}, 39 | {"llvm.memset.p0i8.i64", 2}, 40 | {0, 0} 41 | }; 42 | 43 | static NamedParam LinuxSize[] = { 44 | {"copy_from_user", 2}, 45 | {"copy_in_user", 2}, 46 | {"copy_to_user", 2}, 47 | {"dma_free_coherent", 1}, 48 | {"memcpy", 2}, 49 | {"memcpy_fromiovec", 2}, 50 | {"memcpy_fromiovecend", 2}, 51 | {"memcpy_fromiovecend", 3}, 52 | {"memcpy_toiovec", 2}, 53 | {"memcpy_toiovecend", 2}, 54 | {"memcpy_toiovecend", 3}, 55 | {"memmove", 2}, 56 | {"memset", 2}, 57 | {"pci_free_consistent", 1}, 58 | {"sock_alloc_send_skb", 1}, 59 | {"sock_alloc_send_pskb", 1}, 60 | {"sock_alloc_send_pskb", 2}, 61 | {0, 0} 62 | }; 63 | 64 | void insertIntSat(Value *, Instruction *, StringRef); 65 | 66 | bool IntLibcalls::runOnModule(Module &M) { 67 | BuilderTy TheBuilder(M.getContext()); 68 | Builder = &TheBuilder; 69 | for (Module::iterator i = M.begin(), e = M.end(); i != e; ++i) { 70 | Function *F = i; 71 | if (F->empty()) 72 | continue; 73 | rewriteSize(F); 74 | } 75 | return true; 76 | } 77 | 78 | void IntLibcalls::rewriteSize(Function *F) { 79 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 80 | CallInst *I = dyn_cast(&*i); 81 | if (I && I->getCalledFunction()) { 82 | rewriteSizeAt(I, LLVMSize); 83 | rewriteSizeAt(I, LinuxSize); 84 | } 85 | } 86 | } 87 | 88 | void IntLibcalls::rewriteSizeAt(CallInst *I, NamedParam *NPs) { 89 | StringRef Name = I->getCalledFunction()->getName(); 90 | for (NamedParam *NP = NPs; NP->Name; ++NP) { 91 | if (Name != NP->Name) 92 | continue; 93 | Value *Arg = I->getArgOperand(NP->Index); 94 | Type *T = Arg->getType(); 95 | assert(T->isIntegerTy()); 96 | Builder->SetInsertPoint(I); 97 | Value *V = Builder->CreateICmpSLT(Arg, Constant::getNullValue(T)); 98 | insertIntSat(V, I, "size"); 99 | } 100 | } 101 | 102 | char IntLibcalls::ID; 103 | 104 | static RegisterPass 105 | X("int-libcalls", "Rewrite well-known library calls"); 106 | -------------------------------------------------------------------------------- /src/IntRewrite.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "int-rewrite" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | using namespace llvm; 21 | 22 | static cl::opt 23 | WrapOpt("fwrapv", cl::desc("Use two's complement for signed integers")); 24 | 25 | namespace { 26 | 27 | struct IntRewrite : FunctionPass { 28 | static char ID; 29 | IntRewrite() : FunctionPass(ID) { 30 | PassRegistry &Registry = *PassRegistry::getPassRegistry(); 31 | initializeDominatorTreePass(Registry); 32 | initializeLoopInfoPass(Registry); 33 | } 34 | 35 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 36 | AU.addRequired(); 37 | AU.addRequired(); 38 | AU.setPreservesCFG(); 39 | } 40 | 41 | virtual bool runOnFunction(Function &); 42 | 43 | private: 44 | typedef IRBuilder<> BuilderTy; 45 | BuilderTy *Builder; 46 | 47 | DominatorTree *DT; 48 | LoopInfo *LI; 49 | DataLayout *TD; 50 | 51 | bool insertOverflowCheck(Instruction *, Intrinsic::ID, Intrinsic::ID); 52 | bool insertDivCheck(Instruction *); 53 | bool insertShiftCheck(Instruction *); 54 | bool insertArrayCheck(Instruction *); 55 | 56 | bool isObservable(Value *); 57 | }; 58 | 59 | } // anonymous namespace 60 | 61 | static MDNode * findSink(Value *V) { 62 | for (Value::use_iterator i = V->use_begin(), e = V->use_end(); i != e; ++i) { 63 | if (Instruction *I = dyn_cast(*i)) { 64 | if (MDNode *MD = I->getMetadata("sink")) 65 | return MD; 66 | if (isa(I) || isa(I)) 67 | return findSink(I); 68 | } 69 | } 70 | return NULL; 71 | } 72 | 73 | static Instruction * insertIntSat(Value *V, Instruction *I, Instruction *IP, 74 | StringRef Bug, const DebugLoc &DbgLoc) { 75 | Module *M = IP->getParent()->getParent()->getParent(); 76 | LLVMContext &C = M->getContext(); 77 | FunctionType *T = FunctionType::get(Type::getVoidTy(C), Type::getInt1Ty(C), false); 78 | Function *F = cast(M->getOrInsertFunction("int.sat", T)); 79 | F->setDoesNotThrow(); 80 | CallInst *CI = CallInst::Create(F, V, "", IP); 81 | CI->setDebugLoc(DbgLoc); 82 | // Embed operation name in metadata. 83 | MDNode *MD = MDNode::get(C, MDString::get(C, Bug)); 84 | CI->setMetadata("bug", MD); 85 | 86 | // Add taint metadata 87 | for (unsigned i = 0; i < I->getNumOperands(); ++i) { 88 | if (MDNode *MD = I->getMetadata("taint")) { 89 | CI->setMetadata("taint", MD); 90 | break; 91 | } 92 | } 93 | // Add sink metadata 94 | if (MDNode *MD = findSink(I)) 95 | CI->setMetadata("sink", MD); 96 | 97 | return CI; 98 | } 99 | 100 | void insertIntSat(Value *V, Instruction *I, StringRef Bug) { 101 | insertIntSat(V, I, I, Bug, I->getDebugLoc()); 102 | } 103 | 104 | void insertIntSat(Value *V, Instruction *I) { 105 | insertIntSat(V, I, I->getOpcodeName()); 106 | } 107 | 108 | bool IntRewrite::runOnFunction(Function &F) { 109 | BuilderTy TheBuilder(F.getContext()); 110 | Builder = &TheBuilder; 111 | DT = &getAnalysis(); 112 | LI = &getAnalysis(); 113 | TD = getAnalysisIfAvailable(); 114 | bool Changed = false; 115 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 116 | Instruction *I = &*i; 117 | if (!isa(I) && !isa(I)) 118 | continue; 119 | Builder->SetInsertPoint(I); 120 | switch (I->getOpcode()) { 121 | default: continue; 122 | case Instruction::Add: 123 | Changed |= insertOverflowCheck(I, 124 | Intrinsic::sadd_with_overflow, 125 | Intrinsic::uadd_with_overflow); 126 | break; 127 | case Instruction::Sub: 128 | Changed |= insertOverflowCheck(I, 129 | Intrinsic::ssub_with_overflow, 130 | Intrinsic::usub_with_overflow); 131 | break; 132 | case Instruction::Mul: 133 | Changed |= insertOverflowCheck(I, 134 | Intrinsic::smul_with_overflow, 135 | Intrinsic::umul_with_overflow); 136 | break; 137 | case Instruction::SDiv: 138 | case Instruction::UDiv: 139 | Changed |= insertDivCheck(I); 140 | break; 141 | // Div by zero is not rewitten here, but done in a separate 142 | // pass before -overflow-idiom, which runs before this pass 143 | // and rewrites divisions as multiplications. 144 | case Instruction::Shl: 145 | case Instruction::LShr: 146 | case Instruction::AShr: 147 | Changed |= insertShiftCheck(I); 148 | break; 149 | case Instruction::GetElementPtr: 150 | Changed |= insertArrayCheck(I); 151 | break; 152 | } 153 | } 154 | return Changed; 155 | } 156 | 157 | bool IntRewrite::isObservable(Value *V) { 158 | Instruction *I = dyn_cast(V); 159 | if (!I) 160 | return false; 161 | BasicBlock *BB = I->getParent(); 162 | switch (I->getOpcode()) { 163 | default: break; 164 | case Instruction::Br: 165 | case Instruction::IndirectBr: 166 | case Instruction::Switch: 167 | if (Loop *L = LI->getLoopFor(BB)) { 168 | if (L->isLoopExiting(BB)) 169 | return true; 170 | } 171 | return false; 172 | } 173 | // Default: observable if unsafe to speculately execute. 174 | return !isSafeToSpeculativelyExecute(I, TD); 175 | } 176 | 177 | bool IntRewrite::insertOverflowCheck(Instruction *I, Intrinsic::ID SID, Intrinsic::ID UID) { 178 | // Skip pointer subtraction, where LLVM converts both operands into 179 | // integers first. 180 | Value *L = I->getOperand(0), *R = I->getOperand(1); 181 | if (isa(L) || isa(R)) 182 | return false; 183 | 184 | bool hasNSW = cast(I)->hasNoSignedWrap(); 185 | Intrinsic::ID ID = hasNSW ? SID : UID; 186 | Module *M = I->getParent()->getParent()->getParent(); 187 | Function *F = Intrinsic::getDeclaration(M, ID, I->getType()); 188 | CallInst *CI = Builder->CreateCall2(F, L, R); 189 | Value *V = Builder->CreateExtractValue(CI, 1); 190 | // llvm.[s|u][add|sub|mul].with.overflow.* 191 | StringRef Anno = F->getName().substr(5, 4); 192 | if (hasNSW) { 193 | // Insert the check eagerly for signed integer overflow, 194 | // if -fwrapv is not given. 195 | if (!WrapOpt) { 196 | insertIntSat(V, I, Anno); 197 | return true; 198 | } 199 | // Clear NSW flag given -fwrapv. 200 | cast(I)->setHasNoSignedWrap(false); 201 | } 202 | 203 | // Defer the check. 204 | SmallPtrSet Visited; 205 | SmallVector Worklist; 206 | typedef SmallPtrSet ObSet; 207 | ObSet ObPoints; 208 | BasicBlock *BB = I->getParent(); 209 | 210 | Worklist.push_back(I); 211 | Visited.insert(I); 212 | while (!Worklist.empty()) { 213 | Value *E = Worklist.back(); 214 | Worklist.pop_back(); 215 | for (Value::use_iterator i = E->use_begin(), e = E->use_end(); i != e; ++i) { 216 | User *U = *i; 217 | // Observable point. 218 | if (isObservable(U)) { 219 | // U must be an instruction for now. 220 | BasicBlock *ObBB = cast(U)->getParent(); 221 | // If the instruction's own BB is an observation 222 | // point, a check will be performed there, so 223 | // there is no need for other checks. 224 | // 225 | // If ObBB is not dominated by BB (e.g., due to 226 | // loops), fall back. 227 | if (ObBB == BB || !DT->dominates(BB, ObBB)) { 228 | insertIntSat(V, I, Anno); 229 | return true; 230 | } 231 | ObPoints.insert(ObBB); 232 | continue; 233 | } 234 | // Add to worklist if new. 235 | if (U->use_empty()) 236 | continue; 237 | if (Visited.insert(U)) 238 | Worklist.push_back(U); 239 | } 240 | } 241 | 242 | const DebugLoc &DbgLoc = I->getDebugLoc(); 243 | for (ObSet::iterator i = ObPoints.begin(), e = ObPoints.end(); i != e; ++i) { 244 | BasicBlock *ObBB = *i; 245 | insertIntSat(V, I, ObBB->getTerminator(), Anno, DbgLoc); 246 | } 247 | return true; 248 | } 249 | 250 | bool IntRewrite::insertDivCheck(Instruction *I) { 251 | Value *R = I->getOperand(1); 252 | // R == 0. 253 | Value *V = Builder->CreateIsNull(R); 254 | // L == INT_MIN && R == -1. 255 | if (I->getOpcode() == Instruction::SDiv) { 256 | Value *L = I->getOperand(0); 257 | IntegerType *T = cast(I->getType()); 258 | unsigned n = T->getBitWidth(); 259 | Constant *SMin = ConstantInt::get(T, APInt::getSignedMinValue(n)); 260 | Constant *MinusOne = Constant::getAllOnesValue(T); 261 | V = Builder->CreateOr(V, Builder->CreateAnd( 262 | Builder->CreateICmpEQ(L, SMin), 263 | Builder->CreateICmpEQ(R, MinusOne))); 264 | } 265 | insertIntSat(V, I); 266 | return true; 267 | } 268 | 269 | bool IntRewrite::insertShiftCheck(Instruction *I) { 270 | Value *Amount = I->getOperand(1); 271 | IntegerType *T = cast(Amount->getType()); 272 | Constant *C = ConstantInt::get(T, T->getBitWidth()); 273 | Value *V = Builder->CreateICmpUGE(Amount, C); 274 | insertIntSat(V, I); 275 | return true; 276 | } 277 | 278 | bool IntRewrite::insertArrayCheck(Instruction *I) { 279 | Value *V = NULL; 280 | gep_type_iterator i = gep_type_begin(I), e = gep_type_end(I); 281 | for (; i != e; ++i) { 282 | // For arr[idx], check idx >u n. Here we don't use idx >= n 283 | // since it is unclear if the pointer will be dereferenced. 284 | ArrayType *T = dyn_cast(*i); 285 | if (!T) 286 | continue; 287 | uint64_t n = T->getNumElements(); 288 | Value *Idx = i.getOperand(); 289 | Type *IdxTy = Idx->getType(); 290 | assert(IdxTy->isIntegerTy()); 291 | // a[0] or a[1] are weird idioms used at the end of a struct. 292 | // Use the maximum signed value instead for the upper bound. 293 | if (n <= 1) 294 | n = INT_MAX; 295 | Value *Check = Builder->CreateICmpUGT(Idx, ConstantInt::get(IdxTy, n)); 296 | if (V) 297 | V = Builder->CreateOr(V, Check); 298 | else 299 | V = Check; 300 | } 301 | if (!V) 302 | return false; 303 | insertIntSat(V, I, "array"); 304 | return true; 305 | } 306 | 307 | char IntRewrite::ID; 308 | 309 | static RegisterPass 310 | X("int-rewrite", "Insert int.sat calls", false, false); 311 | -------------------------------------------------------------------------------- /src/IntSat.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "int-sat" 2 | #include "Diagnostic.h" 3 | #include "PathGen.h" 4 | #include "SMTSolver.h" 5 | #include "ValueGen.h" 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | 22 | using namespace llvm; 23 | 24 | static cl::opt 25 | SMTModelOpt("smt-model", cl::desc("Output SMT model")); 26 | 27 | namespace { 28 | 29 | // Better to make this as a module pass rather than a function pass. 30 | // Otherwise, put `M.getFunction("int.sat")' in doInitialization() and 31 | // it will return NULL, since it's scheduled to run before -int-rewrite. 32 | struct IntSat : ModulePass { 33 | static char ID; 34 | IntSat() : ModulePass(ID) {} 35 | 36 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 37 | AU.setPreservesAll(); 38 | } 39 | 40 | virtual bool runOnModule(Module &); 41 | 42 | private: 43 | Diagnostic Diag; 44 | Function *Trap; 45 | OwningPtr TD; 46 | unsigned MD_bug; 47 | 48 | SmallVector BackEdges; 49 | SmallPtrSet ReportedBugs; 50 | 51 | void runOnFunction(Function &); 52 | void check(CallInst *); 53 | void classify(Value *); 54 | SMTStatus query(Value *, Instruction *); 55 | }; 56 | 57 | } // anonymous namespace 58 | 59 | bool IntSat::runOnModule(Module &M) { 60 | Trap = M.getFunction("int.sat"); 61 | if (!Trap) 62 | return false; 63 | TD.reset(new DataLayout(&M)); 64 | MD_bug = M.getContext().getMDKindID("bug"); 65 | for (Module::iterator i = M.begin(), e = M.end(); i != e; ++i) { 66 | Function &F = *i; 67 | if (F.empty()) 68 | continue; 69 | runOnFunction(F); 70 | } 71 | return false; 72 | } 73 | 74 | void IntSat::runOnFunction(Function &F) { 75 | BackEdges.clear(); 76 | FindFunctionBackedges(F, BackEdges); 77 | ReportedBugs.clear(); 78 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 79 | CallInst *CI = dyn_cast(&*i); 80 | if (CI && CI->getCalledFunction() == Trap) 81 | check(CI); 82 | } 83 | } 84 | 85 | void IntSat::check(CallInst *I) { 86 | assert(I->getNumArgOperands() >= 1); 87 | Value *V = I->getArgOperand(0); 88 | assert(V->getType()->isIntegerTy(1)); 89 | if (isa(V)) 90 | return; 91 | if (ReportedBugs.count(V)) 92 | return; 93 | 94 | const DebugLoc &DbgLoc = I->getDebugLoc(); 95 | if (DbgLoc.isUnknown()) 96 | return; 97 | if (!I->getMetadata(MD_bug)) 98 | return; 99 | 100 | int SMTRes; 101 | if (SMTFork() == 0) 102 | SMTRes = query(V, I); 103 | SMTJoin(&SMTRes); 104 | 105 | // Save to suppress furture warnings. 106 | if (SMTRes == SMT_SAT) 107 | ReportedBugs.insert(V); 108 | } 109 | 110 | SMTStatus IntSat::query(Value *V, Instruction *I) { 111 | SMTSolver SMT(SMTModelOpt); 112 | ValueGen VG(*TD, SMT); 113 | PathGen PG(VG, BackEdges); 114 | SMTExpr Query = SMT.bvand(VG.get(V), PG.get(I->getParent())); 115 | SMTModel Model = NULL; 116 | SMTStatus Res = SMT.query(Query, &Model); 117 | SMT.decref(Query); 118 | if (Res != SMT_SAT) 119 | return Res; 120 | // Output bug type. 121 | MDNode *MD = I->getMetadata(MD_bug); 122 | Diag.bug(cast(MD->getOperand(0))->getString()); 123 | // Output location. 124 | Diag.status(Res); 125 | Diag.classify(I); 126 | Diag.backtrace(I); 127 | // Output model. 128 | if (SMTModelOpt && Model) { 129 | Diag << "model: |\n"; 130 | raw_ostream &OS = Diag.os(); 131 | for (ValueGen::iterator i = VG.begin(), e = VG.end(); i != e; ++i) { 132 | Value *KeyV = i->first; 133 | if (isa(KeyV)) 134 | continue; 135 | OS << " "; 136 | WriteAsOperand(OS, KeyV, false, Trap->getParent()); 137 | OS << ": "; 138 | APInt Val; 139 | SMT.eval(Model, i->second, Val); 140 | if (Val.getLimitedValue(0xa) == 0xa) 141 | OS << "0x"; 142 | OS << Val.toString(16, false); 143 | OS << '\n'; 144 | } 145 | } 146 | if (Model) 147 | SMT.release(Model); 148 | return Res; 149 | } 150 | 151 | char IntSat::ID; 152 | 153 | static RegisterPass 154 | X("int-sat", "Check int.sat for satisfiability", false, true); 155 | -------------------------------------------------------------------------------- /src/LoadRewrite.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "load-rewrite" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | 11 | using namespace llvm; 12 | 13 | namespace { 14 | 15 | struct LoadRewrite : FunctionPass { 16 | static char ID; 17 | LoadRewrite() : FunctionPass(ID) { 18 | PassRegistry &Registry = *PassRegistry::getPassRegistry(); 19 | initializeScalarEvolutionPass(Registry); 20 | } 21 | 22 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 23 | AU.setPreservesCFG(); 24 | AU.addRequired(); 25 | } 26 | 27 | virtual bool runOnFunction(Function &); 28 | 29 | private: 30 | ScalarEvolution *SE; 31 | 32 | bool hoist(LoadInst *); 33 | }; 34 | 35 | } // anonymous namespace 36 | 37 | bool LoadRewrite::runOnFunction(Function &F) { 38 | SE = &getAnalysis(); 39 | bool Changed = false; 40 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 41 | LoadInst *I = dyn_cast(&*i); 42 | if (I && !I->isVolatile()) 43 | Changed |= hoist(I); 44 | } 45 | return Changed; 46 | } 47 | 48 | static std::pair 49 | extractPointerBaseAndOffset(const SCEV *S) { 50 | Value *V = NULL; 51 | const SCEVConstant *Offset = NULL; 52 | if (const SCEVUnknown *Unknown = dyn_cast(S)) { 53 | // p + 0. 54 | V = Unknown->getValue(); 55 | } else if (const SCEVAddExpr *Add = dyn_cast(S)) { 56 | // p + offset. 57 | if (Add->getNumOperands() == 2) { 58 | const SCEVConstant *L = dyn_cast(Add->getOperand(0)); 59 | const SCEVUnknown *R = dyn_cast(Add->getOperand(1)); 60 | if (L && R) { 61 | V = R->getValue(); 62 | Offset = L; 63 | } 64 | } 65 | } 66 | // In some special case (e.g., null pointer dereference), 67 | // S is a pure integer expression. 68 | if (V && !V->getType()->isPointerTy()) 69 | V = NULL; 70 | return std::make_pair(V, Offset); 71 | } 72 | 73 | bool LoadRewrite::hoist(LoadInst *I) { 74 | if (I->use_empty()) 75 | return false; 76 | const SCEV *S = SE->getSCEV(I->getPointerOperand()); 77 | Value *BaseV; 78 | const SCEVConstant *Offset; 79 | tie(BaseV, Offset) = extractPointerBaseAndOffset(S); 80 | if (!BaseV) 81 | return false; 82 | 83 | Function *F = I->getParent()->getParent(); 84 | // Insert a load to the earliest point: 85 | // 1) right after Base's definition, if Base is an instruction; 86 | // 2) in the entry block, if Base is an argument or a global variable. 87 | Instruction *IP; 88 | if (Instruction *BaseI = dyn_cast(BaseV)) 89 | IP = ++BasicBlock::iterator(BaseI); 90 | else 91 | IP = F->getEntryBlock().begin(); 92 | // Skip phi nodes, if any. 93 | if (isa(IP)) 94 | IP = IP->getParent()->getFirstInsertionPt(); 95 | IRBuilder<> Builder(IP); 96 | Value *AddrV = BaseV; 97 | // Offset is based on the type of char *. 98 | if (Offset) { 99 | PointerType *PT = cast(BaseV->getType()); 100 | Type *Int8Ty = Type::getInt8PtrTy(PT->getContext(), PT->getAddressSpace()); 101 | AddrV = Builder.CreatePointerCast(AddrV, Int8Ty); 102 | AddrV = Builder.CreateGEP(AddrV, Offset->getValue()); 103 | } 104 | AddrV = Builder.CreatePointerCast(AddrV, I->getPointerOperand()->getType()); 105 | SSAUpdater SSA; 106 | Type *T = I->getType(); 107 | SSA.Initialize(T, I->getPointerOperand()->getName()); 108 | // Insert load. 109 | LoadInst *LoadV = Builder.CreateLoad(AddrV, true); 110 | // Update all loads with the new inserted one. 111 | for (Function::iterator bi = F->begin(), be = F->end(); bi != be; ++bi) { 112 | BasicBlock *BB = bi; 113 | Value *V = NULL; 114 | for (BasicBlock::iterator i = BB->begin(), e = BB->end(); i != e; ++i) { 115 | Instruction *I = i; 116 | if (StoreInst *SI = dyn_cast(I)) { 117 | Value *StoreV = SI->getValueOperand(); 118 | if (StoreV->getType() != T) 119 | continue; 120 | if (S != SE->getSCEV(SI->getPointerOperand())) 121 | continue; 122 | V = StoreV; 123 | continue; 124 | } 125 | if (!V) { 126 | if (I == LoadV) 127 | V = LoadV; 128 | continue; 129 | } 130 | // Rewrite loads in the same bb of an earlier store. 131 | if (LoadInst *LI = dyn_cast(I)) { 132 | if (LI->isVolatile()) 133 | continue; 134 | if (LI->getType() != T) 135 | continue; 136 | if (S != SE->getSCEV(LI->getPointerOperand())) 137 | continue; 138 | I->replaceAllUsesWith(V); 139 | continue; 140 | } 141 | } 142 | if (V) 143 | SSA.AddAvailableValue(BB, V); 144 | } 145 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 146 | LoadInst *LI = dyn_cast(&*i); 147 | if (!LI || LI->isVolatile() || LI->use_empty()) 148 | continue; 149 | if (LI->getType() != T) 150 | continue; 151 | if (S != SE->getSCEV(LI->getPointerOperand())) 152 | continue; 153 | for (Value::use_iterator ui = LI->use_begin(), ue = LI->use_end(); ui != ue; ) { 154 | Use &U = ui.getUse(); 155 | ui++; 156 | SSA.RewriteUse(U); 157 | } 158 | } 159 | 160 | return true; 161 | } 162 | 163 | char LoadRewrite::ID; 164 | 165 | static RegisterPass 166 | X("load-rewrite", "Rewrite load instructions"); 167 | -------------------------------------------------------------------------------- /src/Makefile.am: -------------------------------------------------------------------------------- 1 | AM_CXXFLAGS = `llvm-config --cxxflags` -Werror -Wall 2 | 3 | noinst_LTLIBRARIES = libsat.la 4 | lib_LTLIBRARIES = libintck.la libcmpck.la 5 | bin_PROGRAMS = intglobal 6 | EXTRA_DIST = intck cmpck llvm/DataLayout.h llvm/DebugInfo.h llvm/IRBuilder.h 7 | 8 | all-local: libintck.la libcmpck.la 9 | @cd $(top_builddir)/lib && $(LN_S) -f ../src/.libs/libintck.so 10 | @cd $(top_builddir)/lib && $(LN_S) -f ../src/.libs/libcmpck.so 11 | @cd $(top_builddir)/bin && $(LN_S) -f ../src/intglobal 12 | 13 | libsat_la_CPPFLAGS = -I$(top_builddir)/lib 14 | libsat_la_SOURCES = ValueGen.cc PathGen.cc Diagnostic.cc SMTSolver.cc 15 | libsat_la_SOURCES += ValueGen.h PathGen.h Diagnostic.h SMTSolver.h 16 | libsat_la_SOURCES += SMTBoolector.cc 17 | libsat_la_LIBADD = -lboolector -llgl 18 | #libsat_la_SOURCES += SMTSonolar.cc 19 | #libsat_la_LIBADD = -lsonolar 20 | #libsat_la_SOURCES += SMTZ3.cc 21 | #libsat_la_LIBADD = -lz3 -lgomp 22 | libsat_la_LDFLAGS = -L$(top_builddir)/lib 23 | 24 | libintck_la_SOURCES = IntRewrite.cc IntLibcalls.cc IntSat.cc \ 25 | OverflowIdiom.cc OverflowSimplify.cc \ 26 | LoadRewrite.cc 27 | libintck_la_LIBADD = libsat.la 28 | libintck_la_LDFLAGS = -module 29 | 30 | libcmpck_la_SOURCES = CmpTautology.cc CmpOverflow.cc CmpSat.cc 31 | libcmpck_la_LIBADD = libsat.la 32 | libcmpck_la_LDFLAGS = -module 33 | 34 | intglobal_LDFLAGS = `llvm-config --ldflags` -lLLVM-`llvm-config --version` 35 | intglobal_SOURCES = IntGlobal.cc Annotation.cc CallGraph.cc Taint.cc Range.cc \ 36 | IntGlobal.h Annotation.h CRange.h 37 | -------------------------------------------------------------------------------- /src/OverflowIdiom.cc: -------------------------------------------------------------------------------- 1 | // This pass recognizes overflow checking idioms and rewrites them 2 | // with overflow intrinsics. 3 | 4 | #define DEBUG_TYPE "overflow-idiom" 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | using namespace llvm; 18 | using namespace llvm::PatternMatch; 19 | 20 | namespace { 21 | 22 | struct OverflowIdiom : FunctionPass { 23 | static char ID; 24 | OverflowIdiom() : FunctionPass(ID) {} 25 | 26 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 27 | AU.setPreservesCFG(); 28 | } 29 | 30 | virtual bool runOnFunction(Function &); 31 | 32 | private: 33 | typedef IRBuilder<> BuilderTy; 34 | BuilderTy *Builder; 35 | 36 | Value *createOverflowBit(Intrinsic::ID ID, Value *L, Value *R) { 37 | Module *M = Builder->GetInsertBlock()->getParent()->getParent(); 38 | Function *F = Intrinsic::getDeclaration(M, ID, L->getType()); 39 | CallInst *CI = Builder->CreateCall2(F, L, R); 40 | return Builder->CreateExtractValue(CI, 1); 41 | } 42 | 43 | Value *matchCmpWithSwappedAndInverse(CmpInst::Predicate Pred, Value *L, Value *R) { 44 | // Try match comparision and the swapped form. 45 | if (Value *V = matchCmpWithInverse(Pred, L, R)) 46 | return V; 47 | Pred = CmpInst::getSwappedPredicate(Pred); 48 | if (Value *V = matchCmpWithInverse(Pred, R, L)) 49 | return V; 50 | return NULL; 51 | } 52 | 53 | Value *matchCmpWithInverse(CmpInst::Predicate Pred, Value *L, Value *R) { 54 | // Try match comparision and the inverse form. 55 | if (Value *V = matchCmp(Pred, L, R)) 56 | return V; 57 | Pred = CmpInst::getInversePredicate(Pred); 58 | if (Value *V = matchCmp(Pred, L, R)) 59 | return Builder->CreateXor(V, 1); 60 | return NULL; 61 | } 62 | 63 | Value *matchCmp(CmpInst::Predicate, Value *, Value *); 64 | 65 | bool removeRedundantZeroCheck(BasicBlock *); 66 | }; 67 | 68 | } // anonymous namespace 69 | 70 | bool OverflowIdiom::runOnFunction(Function &F) { 71 | BuilderTy TheBuilder(F.getContext()); 72 | Builder = &TheBuilder; 73 | bool Changed = false; 74 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ) { 75 | ICmpInst *I = dyn_cast(&*i); 76 | ++i; 77 | if (!I) 78 | continue; 79 | Value *L = I->getOperand(0), *R = I->getOperand(1); 80 | if (!L->getType()->isIntegerTy()) 81 | continue; 82 | Builder->SetInsertPoint(I); 83 | Value *V = matchCmpWithSwappedAndInverse(I->getPredicate(), L, R); 84 | if (!V) 85 | continue; 86 | I->replaceAllUsesWith(V); 87 | if (I->hasName()) 88 | V->takeName(I); 89 | RecursivelyDeleteTriviallyDeadInstructions(I); 90 | Changed = true; 91 | } 92 | return Changed; 93 | } 94 | 95 | Value *OverflowIdiom::matchCmp(CmpInst::Predicate Pred, Value *L, Value *R) { 96 | Value *X, *Y, *A, *B; 97 | ConstantInt *C; 98 | 99 | // x != (x * y) /u y => umul.overflow(x, y) 100 | // x != (y * x) /u y => umul.overflow(x, y) 101 | if (Pred == CmpInst::ICMP_NE 102 | && match(L, m_Value(X)) 103 | && match(R, m_UDiv(m_Mul(m_Value(A), m_Value(B)), m_Value(Y))) 104 | && ((A == X && B == Y) || (A == Y && B == X))) 105 | return createOverflowBit(Intrinsic::umul_with_overflow, X, Y); 106 | 107 | // x >u C /u y => 108 | // umul.overflow(x, y), if C == UMAX 109 | // x >u C || y >u C || umul.overflow_k(x, y), if C == UMAX_k 110 | // (zext x) * (zext y) > (zext N), otherwise. 111 | if (Pred == CmpInst::ICMP_UGT 112 | && match(L, m_Value(X)) 113 | && match(R, m_UDiv(m_ConstantInt(C), m_Value(Y)))) { 114 | const APInt &Val = C->getValue(); 115 | if (Val.isMaxValue()) 116 | return createOverflowBit(Intrinsic::umul_with_overflow, X, Y); 117 | if ((Val + 1).isPowerOf2()) { 118 | unsigned N = Val.countTrailingOnes(); 119 | IntegerType *T = IntegerType::get(Builder->getContext(), N); 120 | return Builder->CreateOr( 121 | Builder->CreateOr( 122 | Builder->CreateICmpUGT(X, C), 123 | Builder->CreateICmpUGT(Y, C) 124 | ), 125 | createOverflowBit(Intrinsic::umul_with_overflow, 126 | Builder->CreateTrunc(X, T), 127 | Builder->CreateTrunc(Y, T) 128 | ) 129 | ); 130 | } 131 | unsigned N = X->getType()->getIntegerBitWidth() * 2; 132 | IntegerType *T = IntegerType::get(Builder->getContext(), N); 133 | return Builder->CreateICmpUGT( 134 | Builder->CreateMul( 135 | Builder->CreateZExt(X, T), 136 | Builder->CreateZExt(Y, T) 137 | ), 138 | Builder->CreateZExt(C, T) 139 | ); 140 | } 141 | 142 | return NULL; 143 | } 144 | 145 | char OverflowIdiom::ID; 146 | 147 | static RegisterPass 148 | X("overflow-idiom", "Rewrite overflow checking idioms using intrinsics"); 149 | -------------------------------------------------------------------------------- /src/OverflowSimplify.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "overflow-simplify" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | using namespace llvm; 15 | 16 | namespace { 17 | 18 | struct OverflowSimplify : FunctionPass { 19 | static char ID; 20 | OverflowSimplify() : FunctionPass(ID) {} 21 | 22 | virtual void getAnalysisUsage(AnalysisUsage &AU) const { 23 | AU.setPreservesCFG(); 24 | } 25 | 26 | virtual bool runOnFunction(Function &); 27 | 28 | private: 29 | typedef IRBuilder<> BuilderTy; 30 | BuilderTy *Builder; 31 | 32 | void replace(IntrinsicInst *I, Value *Res, Value *Cmp); 33 | 34 | bool simplifySAdd(IntrinsicInst *); 35 | bool simplifyUAdd(IntrinsicInst *); 36 | bool simplifySSub(IntrinsicInst *); 37 | bool simplifyUSub(IntrinsicInst *); 38 | bool simplifySMul(IntrinsicInst *); 39 | bool simplifyUMul(IntrinsicInst *); 40 | }; 41 | 42 | } // anonymous namespace 43 | 44 | bool OverflowSimplify::runOnFunction(Function &F) { 45 | BuilderTy TheBuilder(F.getContext()); 46 | Builder = &TheBuilder; 47 | bool Changed = false; 48 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ) { 49 | IntrinsicInst *I = dyn_cast(&*i); 50 | ++i; 51 | if (!I || I->getNumArgOperands() != 2) 52 | continue; 53 | Builder->SetInsertPoint(I); 54 | switch (I->getIntrinsicID()) { 55 | default: break; 56 | case Intrinsic::sadd_with_overflow: 57 | Changed |= simplifySAdd(I); 58 | break; 59 | case Intrinsic::uadd_with_overflow: 60 | Changed |= simplifyUAdd(I); 61 | break; 62 | case Intrinsic::ssub_with_overflow: 63 | Changed |= simplifySSub(I); 64 | break; 65 | case Intrinsic::usub_with_overflow: 66 | Changed |= simplifyUSub(I); 67 | break; 68 | case Intrinsic::smul_with_overflow: 69 | Changed |= simplifySMul(I); 70 | break; 71 | case Intrinsic::umul_with_overflow: 72 | Changed |= simplifyUMul(I); 73 | break; 74 | } 75 | } 76 | return Changed; 77 | } 78 | 79 | static bool canonicalize(IntrinsicInst *I, Value **X, ConstantInt **C) { 80 | Value *L = I->getArgOperand(0), *R = I->getArgOperand(1); 81 | // We need a "stable" order of commutative operations. 82 | // Order based on their names. If a variable doesn't have a name, 83 | // use its slot index. 84 | if (ConstantInt *CI = dyn_cast(R)) { 85 | *X = L; 86 | *C = CI; 87 | return false; 88 | } 89 | if (ConstantInt *CI = dyn_cast(L)) { 90 | *X = R; 91 | *C = CI; 92 | return false; 93 | } 94 | *X = NULL; 95 | *C = NULL; 96 | SmallString<16> LS, RS; 97 | { 98 | raw_svector_ostream OS(LS); 99 | WriteAsOperand(OS, L, false); 100 | } 101 | { 102 | raw_svector_ostream OS(RS); 103 | WriteAsOperand(OS, R, false); 104 | } 105 | if (LS <= RS) 106 | return false; 107 | I->setArgOperand(0, R); 108 | I->setArgOperand(1, L); 109 | return true; 110 | } 111 | 112 | void OverflowSimplify::replace(IntrinsicInst *I, Value *Res, Value *Cmp) { 113 | StructType *T = StructType::get(Res->getType(), Cmp->getType(), NULL); 114 | Value *V = UndefValue::get(T); 115 | V = Builder->CreateInsertValue(V, Res, 0); 116 | V = Builder->CreateInsertValue(V, Cmp, 1); 117 | I->replaceAllUsesWith(V); 118 | if (I->hasName()) 119 | V->takeName(I); 120 | I->eraseFromParent(); 121 | } 122 | 123 | bool OverflowSimplify::simplifySAdd(IntrinsicInst *I) { 124 | Value *X; 125 | ConstantInt *C; 126 | bool Changed = canonicalize(I, &X, &C); 127 | if (!C) 128 | return Changed; 129 | unsigned N = C->getBitWidth(); 130 | Value *Res = Builder->CreateAdd(X, C); 131 | // sadd.overflow(X, C) => 132 | // X < SMIN - C, if C < 0 133 | // X > SMAX - C, otherwise. 134 | Value *Cmp; 135 | if (C->isNegative()) 136 | Cmp = Builder->CreateICmpSLT(X, Builder->getInt( 137 | APInt::getSignedMinValue(N) - C->getValue())); 138 | else 139 | Cmp = Builder->CreateICmpSGT(X, Builder->getInt( 140 | APInt::getSignedMaxValue(N) - C->getValue())); 141 | replace(I, Res, Cmp); 142 | return true; 143 | } 144 | 145 | bool OverflowSimplify::simplifyUAdd(IntrinsicInst *I) { 146 | Value *X; 147 | ConstantInt *C; 148 | bool Changed = canonicalize(I, &X, &C); 149 | if (!C) 150 | return Changed; 151 | // uadd.overflow(X, C) => X > UMAX - C. 152 | Value *Res = Builder->CreateAdd(X, C); 153 | Value *Cmp = Builder->CreateICmpUGT(X, Builder->getInt( 154 | APInt::getMaxValue(C->getBitWidth()) - C->getValue())); 155 | replace(I, Res, Cmp); 156 | return true; 157 | } 158 | 159 | bool OverflowSimplify::simplifySSub(IntrinsicInst *I) { 160 | Value *L = I->getArgOperand(0), *R = I->getArgOperand(1); 161 | Value *Res, *Cmp; 162 | unsigned N = L->getType()->getIntegerBitWidth(); 163 | if (ConstantInt *C = dyn_cast(R)) { 164 | Res = Builder->CreateSub(L, R); 165 | // ssub.overflow(L, C) => 166 | // L > SMAX + C, if C < 0 167 | // L < SMIN + C, otherwise. 168 | if (C->isNegative()) 169 | Cmp = Builder->CreateICmpSGT(L, Builder->getInt( 170 | APInt::getSignedMaxValue(N) + C->getValue())); 171 | else 172 | Cmp = Builder->CreateICmpSLT(L, Builder->getInt( 173 | APInt::getSignedMinValue(N) + C->getValue())); 174 | } else if (ConstantInt *C = dyn_cast(L)) { 175 | Res = Builder->CreateSub(L, R); 176 | // ssub.overflow(C, R) => 177 | // R > C - SMIN, if C < 0 178 | // R < C - SMAX, otherwise. 179 | if (C->isNegative()) 180 | Cmp = Builder->CreateICmpSGT(L, Builder->getInt( 181 | C->getValue() - APInt::getSignedMinValue(N))); 182 | else 183 | Cmp = Builder->CreateICmpSLT(L, Builder->getInt( 184 | C->getValue() - APInt::getSignedMaxValue(N))); 185 | } else { 186 | return false; 187 | } 188 | replace(I, Res, Cmp); 189 | return true; 190 | } 191 | 192 | bool OverflowSimplify::simplifyUSub(IntrinsicInst *I) { 193 | // usub.overflow(L, R) => L < R. 194 | Value *L = I->getArgOperand(0), *R = I->getArgOperand(1); 195 | Value *Res = Builder->CreateSub(L, R); 196 | Value *Cmp; 197 | if (isa(L)) 198 | Cmp = Builder->CreateICmpUGT(R, L); 199 | else 200 | Cmp = Builder->CreateICmpULT(L, R); 201 | replace(I, Res, Cmp); 202 | return true; 203 | } 204 | 205 | bool OverflowSimplify::simplifySMul(IntrinsicInst *I) { 206 | Value *X; 207 | ConstantInt *C; 208 | bool Changed = canonicalize(I, &X, &C); 209 | if (!C) 210 | return Changed; 211 | Value *Res = Builder->CreateMul(X, C); 212 | Value *Cmp; 213 | // smul.overflow(X, C) => 214 | // false, if C == 0 215 | // X < SMAX / C || X > SMIN / C, if C < 0 216 | // X > SMAX / C || X < SMIN / C, otherwise 217 | if (C->isZero()) { 218 | Cmp = Builder->getFalse(); 219 | } else { 220 | unsigned N = C->getBitWidth(); 221 | Value *Max, *Min; 222 | Max = Builder->getInt(APInt::getSignedMaxValue(N).sdiv(C->getValue())); 223 | Min = Builder->getInt(APInt::getSignedMinValue(N).sdiv(C->getValue())); 224 | if (C->isNegative()) 225 | Cmp = Builder->CreateOr( 226 | Builder->CreateICmpSLT(X, Max), 227 | Builder->CreateICmpSGT(X, Min) 228 | ); 229 | else 230 | Cmp = Builder->CreateOr( 231 | Builder->CreateICmpSGT(X, Max), 232 | Builder->CreateICmpSLT(X, Min) 233 | ); 234 | } 235 | replace(I, Res, Cmp); 236 | return true; 237 | } 238 | 239 | bool OverflowSimplify::simplifyUMul(IntrinsicInst *I) { 240 | Value *X; 241 | ConstantInt *C; 242 | bool Changed = canonicalize(I, &X, &C); 243 | if (!C) 244 | return Changed; 245 | // umul.overflow(X, C) => 246 | // false, if C == 0 247 | // X > UMAX / C, otherwise. 248 | Value *Res = Builder->CreateMul(X, C); 249 | Value *Cmp; 250 | if (C->isZero()) 251 | Cmp = Builder->getFalse(); 252 | else 253 | Cmp = Builder->CreateICmpUGT(X, Builder->getInt( 254 | APInt::getMaxValue(C->getBitWidth()).udiv(C->getValue()))); 255 | replace(I, Res, Cmp); 256 | return true; 257 | } 258 | 259 | char OverflowSimplify::ID; 260 | 261 | static RegisterPass 262 | X("overflow-simplify", "Canonicalize overflow intrinsics"); 263 | -------------------------------------------------------------------------------- /src/PathGen.cc: -------------------------------------------------------------------------------- 1 | #include "PathGen.h" 2 | #include "ValueGen.h" 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace llvm; 9 | 10 | #define SMT VG.SMT 11 | 12 | PathGen::PathGen(ValueGen &VG, const EdgeVec &BE) 13 | : VG(VG), Backedges(BE), DT(NULL) {} 14 | 15 | PathGen::PathGen(ValueGen &VG, const EdgeVec &Backedges, DominatorTree &DT) 16 | : VG(VG), Backedges(Backedges), DT(&DT) {} 17 | 18 | PathGen::~PathGen() { 19 | for (iterator i = Cache.begin(), e = Cache.end(); i != e; ++i) 20 | SMT.decref(i->second); 21 | } 22 | 23 | static BasicBlock *findCommonDominator(BasicBlock *BB, DominatorTree *DT) { 24 | pred_iterator i = pred_begin(BB), e = pred_end(BB); 25 | BasicBlock *Dom = *i; 26 | for (++i; i != e; ++i) 27 | Dom = DT->findNearestCommonDominator(Dom, *i); 28 | return Dom; 29 | } 30 | 31 | SMTExpr PathGen::get(BasicBlock *BB) { 32 | SMTExpr G = Cache.lookup(BB); 33 | if (G) 34 | return G; 35 | // Entry block has true guard. 36 | if (BB == &BB->getParent()->getEntryBlock()) { 37 | G = SMT.bvtrue(); 38 | Cache[BB] = G; 39 | return G; 40 | } 41 | pred_iterator i, e = pred_end(BB); 42 | if (DT) { 43 | // Fall back to common ancestors if any back edges. 44 | for (i = pred_begin(BB); i != e; ++i) { 45 | if (isBackedge(*i, BB)) 46 | return get(findCommonDominator(BB, DT)); 47 | } 48 | } 49 | // The guard is the disjunction of predecessors' guards. 50 | // Initialize to false. 51 | G = SMT.bvfalse(); 52 | for (i = pred_begin(BB); i != e; ++i) { 53 | BasicBlock *Pred = *i; 54 | // Skip back edges. 55 | if (!DT && isBackedge(Pred, BB)) 56 | continue; 57 | SMTExpr Term = getTermGuard(Pred->getTerminator(), BB); 58 | SMTExpr PN = getPHIGuard(BB, Pred); 59 | SMTExpr TermWithPN = SMT.bvand(Term, PN); 60 | SMT.decref(Term); 61 | SMT.decref(PN); 62 | SMTExpr Br = SMT.bvand(TermWithPN, get(Pred)); 63 | SMT.decref(TermWithPN); 64 | SMTExpr Tmp = SMT.bvor(G, Br); 65 | SMT.decref(G); 66 | SMT.decref(Br); 67 | G = Tmp; 68 | } 69 | Cache[BB] = G; 70 | return G; 71 | } 72 | 73 | bool PathGen::isBackedge(llvm::BasicBlock *From, llvm::BasicBlock *To) { 74 | return std::find(Backedges.begin(), Backedges.end(), Edge(From, To)) 75 | != Backedges.end(); 76 | } 77 | 78 | SMTExpr PathGen::getPHIGuard(BasicBlock *BB, BasicBlock *Pred) { 79 | SMTExpr E = SMT.bvtrue(); 80 | BasicBlock::iterator i = BB->begin(), e = BB->end(); 81 | for (; i != e; ++i) { 82 | PHINode *I = dyn_cast(i); 83 | if (!I) 84 | break; 85 | Value *V = I->getIncomingValueForBlock(Pred); 86 | // Skip undef. 87 | if (isa(V)) 88 | continue; 89 | // Skip non-integral types. 90 | if (!ValueGen::isAnalyzable(V)) 91 | continue; 92 | // Generate I == V. 93 | SMTExpr PN = SMT.eq(VG.get(I), VG.get(V)); 94 | SMTExpr Tmp = SMT.bvand(E, PN); 95 | SMT.decref(E); 96 | SMT.decref(PN); 97 | E = Tmp; 98 | } 99 | return E; 100 | } 101 | 102 | SMTExpr PathGen::getTermGuard(TerminatorInst *I, BasicBlock *BB) { 103 | switch (I->getOpcode()) { 104 | default: I->dump(); llvm_unreachable("Unknown terminator!"); 105 | case Instruction::Br: 106 | return getTermGuard(cast(I), BB); 107 | case Instruction::Switch: 108 | return getTermGuard(cast(I), BB); 109 | case Instruction::IndirectBr: 110 | case Instruction::Invoke: 111 | return SMT.bvtrue(); 112 | } 113 | } 114 | 115 | SMTExpr PathGen::getTermGuard(BranchInst *I, BasicBlock *BB) { 116 | if (I->isUnconditional()) 117 | return SMT.bvtrue(); 118 | // Conditional branch. 119 | Value *V = I->getCondition(); 120 | SMTExpr E = VG.get(V); 121 | SMT.incref(E); 122 | // True or false branch. 123 | if (I->getSuccessor(0) != BB) { 124 | assert(I->getSuccessor(1) == BB); 125 | SMTExpr Tmp = SMT.bvnot(E); 126 | SMT.decref(E); 127 | E = Tmp; 128 | } 129 | return E; 130 | } 131 | 132 | SMTExpr PathGen::getTermGuard(SwitchInst *I, BasicBlock *BB) { 133 | Value *V = I->getCondition(); 134 | SMTExpr L = VG.get(V); 135 | SwitchInst::CaseIt i = I->case_begin(), e = I->case_end(); 136 | if (I->getDefaultDest() != BB) { 137 | // Find all x = C_i for BB. 138 | SMTExpr E = SMT.bvfalse(); 139 | for (; i != e; ++i) { 140 | if (i.getCaseSuccessor() == BB) { 141 | ConstantInt *CI = i.getCaseValue(); 142 | SMTExpr Cond = SMT.eq(L, VG.get(CI)); 143 | SMTExpr Tmp = SMT.bvor(E, Cond); 144 | SMT.decref(Cond); 145 | SMT.decref(E); 146 | E = Tmp; 147 | } 148 | } 149 | return E; 150 | } 151 | // Compute guard for the default case. 152 | // i starts from 1; 0 is reserved for the default. 153 | SMTExpr E = SMT.bvfalse(); 154 | for (; i != e; ++i) { 155 | ConstantInt *CI = i.getCaseValue(); 156 | SMTExpr Cond = SMT.eq(L, VG.get(CI)); 157 | SMTExpr Tmp = SMT.bvor(E, Cond); 158 | SMT.decref(Cond); 159 | SMT.decref(E); 160 | E = Tmp; 161 | } 162 | SMTExpr NotE = SMT.bvnot(E); 163 | SMT.decref(E); 164 | return NotE; 165 | } 166 | -------------------------------------------------------------------------------- /src/PathGen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "SMTSolver.h" 6 | 7 | namespace llvm { 8 | class BasicBlock; 9 | class BranchInst; 10 | class DominatorTree; 11 | class SwitchInst; 12 | class TerminatorInst; 13 | } // namespace llvm 14 | 15 | class ValueGen; 16 | 17 | class PathGen { 18 | public: 19 | typedef llvm::DenseMap BBExprMap; 20 | typedef BBExprMap::iterator iterator; 21 | typedef std::pair Edge; 22 | typedef llvm::SmallVectorImpl EdgeVec; 23 | 24 | PathGen(ValueGen &, const EdgeVec &); 25 | PathGen(ValueGen &, const EdgeVec &, llvm::DominatorTree &DT); 26 | ~PathGen(); 27 | 28 | SMTExpr get(llvm::BasicBlock *); 29 | 30 | private: 31 | ValueGen &VG; 32 | const EdgeVec &Backedges; 33 | llvm::DominatorTree *DT; 34 | BBExprMap Cache; 35 | 36 | bool isBackedge(llvm::BasicBlock *, llvm::BasicBlock *); 37 | SMTExpr getTermGuard(llvm::TerminatorInst *I, llvm::BasicBlock *BB); 38 | SMTExpr getTermGuard(llvm::BranchInst *I, llvm::BasicBlock *BB); 39 | SMTExpr getTermGuard(llvm::SwitchInst *I, llvm::BasicBlock *BB); 40 | SMTExpr getPHIGuard(llvm::BasicBlock *BB, llvm::BasicBlock *Pred); 41 | }; 42 | -------------------------------------------------------------------------------- /src/Range.cc: -------------------------------------------------------------------------------- 1 | #define DEBUG_TYPE "ranges" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include "llvm/Support/CommandLine.h" 17 | 18 | #include "Annotation.h" 19 | #include "IntGlobal.h" 20 | 21 | using namespace llvm; 22 | 23 | static cl::opt 24 | WatchID("w", cl::desc("Watch sID"), 25 | cl::value_desc("sID")); 26 | 27 | bool RangePass::unionRange(StringRef sID, const CRange &R, 28 | Value *V = NULL) 29 | { 30 | if (R.isEmptySet()) 31 | return false; 32 | 33 | if (WatchID == sID && V) { 34 | if (Instruction *I = dyn_cast(V)) 35 | dbgs() << I->getParent()->getParent()->getName() << "(): "; 36 | V->print(dbgs()); 37 | dbgs() << "\n"; 38 | } 39 | 40 | bool changed = true; 41 | RangeMap::iterator it = Ctx->IntRanges.find(sID); 42 | if (it != Ctx->IntRanges.end()) { 43 | changed = it->second.safeUnion(R); 44 | if (changed && sID == WatchID) 45 | dbgs() << sID << " + " << R << " = " << it->second << "\n"; 46 | } else { 47 | Ctx->IntRanges.insert(std::make_pair(sID, R)); 48 | if (sID == WatchID) 49 | dbgs() << sID << " = " << R << "\n"; 50 | } 51 | if (changed) 52 | Changes.insert(sID); 53 | return changed; 54 | } 55 | 56 | bool RangePass::unionRange(BasicBlock *BB, Value *V, 57 | const CRange &R) 58 | { 59 | if (R.isEmptySet()) 60 | return false; 61 | 62 | bool changed = true; 63 | ValueRangeMap &VRM = FuncVRMs[BB]; 64 | ValueRangeMap::iterator it = VRM.find(V); 65 | if (it != VRM.end()) 66 | changed = it->second.safeUnion(R); 67 | else 68 | VRM.insert(std::make_pair(V, R)); 69 | return changed; 70 | } 71 | 72 | CRange RangePass::getRange(BasicBlock *BB, Value *V) 73 | { 74 | // constants 75 | if (ConstantInt *C = dyn_cast(V)) 76 | return CRange(C->getValue()); 77 | 78 | ValueRangeMap &VRM = FuncVRMs[BB]; 79 | ValueRangeMap::iterator invrm = VRM.find(V); 80 | 81 | if (invrm != VRM.end()) 82 | return invrm->second; 83 | 84 | // V must be integer or pointer to integer 85 | IntegerType *Ty = dyn_cast(V->getType()); 86 | if (PointerType *PTy = dyn_cast(V->getType())) 87 | Ty = dyn_cast(PTy->getElementType()); 88 | assert(Ty != NULL); 89 | 90 | // not found in VRM, lookup global range, return empty set by default 91 | CRange CR(Ty->getBitWidth(), false); 92 | CRange Fullset(Ty->getBitWidth(), true); 93 | 94 | RangeMap &IRM = Ctx->IntRanges; 95 | TaintPass TI(Ctx); 96 | 97 | if (CallInst *CI = dyn_cast(V)) { 98 | // calculate union of values ranges returned by all possible callees 99 | if (!CI->isInlineAsm() && Ctx->Callees.count(CI)) { 100 | FuncSet &CEEs = Ctx->Callees[CI]; 101 | for (FuncSet::iterator i = CEEs.begin(), e = CEEs.end(); 102 | i != e; ++i) { 103 | std::string sID = getRetId(*i); 104 | if (sID != "" && TI.isTaintSource(sID)) { 105 | CR = Fullset; 106 | break; 107 | } 108 | RangeMap::iterator it; 109 | if ((it = IRM.find(sID)) != IRM.end()) 110 | CR.safeUnion(it->second); 111 | } 112 | } 113 | } else { 114 | // arguments & loads 115 | std::string sID = getValueId(V); 116 | if (sID != "") { 117 | RangeMap::iterator it; 118 | if (TI.isTaintSource(sID)) 119 | CR = Fullset; 120 | else if ((it = IRM.find(sID)) != IRM.end()) 121 | CR = it->second; 122 | } 123 | // might load part of a struct field 124 | CR = CR.zextOrTrunc(Ty->getBitWidth()); 125 | } 126 | if (!CR.isEmptySet()) 127 | VRM.insert(std::make_pair(V, CR)); 128 | return CR; 129 | } 130 | 131 | void RangePass::collectInitializers(GlobalVariable *GV, Constant *I) 132 | { 133 | // global var 134 | if (ConstantInt *CI = dyn_cast(I)) { 135 | unionRange(getVarId(GV), CI->getValue(), GV); 136 | } 137 | 138 | // structs 139 | if (ConstantStruct *CS = dyn_cast(I)) { 140 | // Find integer fields in the struct 141 | StructType *ST = CS->getType(); 142 | // Skip anonymous structs 143 | if (!ST->hasName() || ST->getName() == "struct.anon" 144 | || ST->getName().startswith("struct.anon.")) 145 | return; 146 | 147 | for (unsigned i = 0; i != ST->getNumElements(); ++i) { 148 | Type *Ty = ST->getElementType(i); 149 | if (Ty->isStructTy()) { 150 | // nested struct 151 | // TODO: handle nested arrays 152 | collectInitializers(GV, CS->getOperand(i)); 153 | } else if (Ty->isIntegerTy()) { 154 | ConstantInt *CI = 155 | dyn_cast(I->getOperand(i)); 156 | StringRef sID = getStructId(ST, GV->getParent(), i); 157 | if (!sID.empty() && CI) 158 | unionRange(sID, CI->getValue(), GV); 159 | } 160 | } 161 | } 162 | 163 | // arrays 164 | if (ConstantArray *CA = dyn_cast(I)) { 165 | Type *Ty = CA->getType()->getElementType(); 166 | if (Ty->isStructTy() || Ty->isIntegerTy()) { 167 | for (unsigned i = 0; i != CA->getNumOperands(); ++i) 168 | collectInitializers(GV, CA->getOperand(i)); 169 | } 170 | } 171 | } 172 | 173 | // 174 | // Handle integer assignments in global initializers 175 | // 176 | bool RangePass::doInitialization(Module *M) 177 | { 178 | // Looking for global variables 179 | for (Module::global_iterator i = M->global_begin(), 180 | e = M->global_end(); i != e; ++i) { 181 | 182 | // skip strings literals 183 | if (i->hasInitializer() && !i->getName().startswith(".")) 184 | collectInitializers(&*i, i->getInitializer()); 185 | } 186 | return true; 187 | } 188 | 189 | 190 | CRange RangePass::visitBinaryOp(BinaryOperator *BO) 191 | { 192 | CRange L = getRange(BO->getParent(), BO->getOperand(0)); 193 | CRange R = getRange(BO->getParent(), BO->getOperand(1)); 194 | R.match(L); 195 | switch (BO->getOpcode()) { 196 | default: BO->dump(); llvm_unreachable("Unknown binary operator!"); 197 | case Instruction::Add: return L.add(R); 198 | case Instruction::Sub: return L.sub(R); 199 | case Instruction::Mul: return L.multiply(R); 200 | case Instruction::UDiv: return L.udiv(R); 201 | case Instruction::SDiv: return L.sdiv(R); 202 | case Instruction::URem: return R; // FIXME 203 | case Instruction::SRem: return R; // FIXME 204 | case Instruction::Shl: return L.shl(R); 205 | case Instruction::LShr: return L.lshr(R); 206 | case Instruction::AShr: return L; // FIXME 207 | case Instruction::And: return L.binaryAnd(R); 208 | case Instruction::Or: return L.binaryOr(R); 209 | case Instruction::Xor: return L; // FIXME 210 | } 211 | } 212 | 213 | 214 | CRange RangePass::visitCastInst(CastInst *CI) 215 | { 216 | unsigned bits = dyn_cast( 217 | CI->getDestTy())->getBitWidth(); 218 | 219 | BasicBlock *BB = CI->getParent(); 220 | Value *V = CI->getOperand(0); 221 | switch (CI->getOpcode()) { 222 | case CastInst::Trunc: return getRange(BB, V).zextOrTrunc(bits); 223 | case CastInst::ZExt: return getRange(BB, V).zextOrTrunc(bits); 224 | case CastInst::SExt: return getRange(BB, V).signExtend(bits); 225 | case CastInst::BitCast: return getRange(BB, V); 226 | default: return CRange(bits, true); 227 | } 228 | } 229 | 230 | CRange RangePass::visitSelectInst(SelectInst *SI) 231 | { 232 | CRange T = getRange(SI->getParent(), SI->getTrueValue()); 233 | CRange F = getRange(SI->getParent(), SI->getFalseValue()); 234 | T.safeUnion(F); 235 | return T; 236 | } 237 | 238 | CRange RangePass::visitPHINode(PHINode *PHI) 239 | { 240 | IntegerType *Ty = cast(PHI->getType()); 241 | CRange CR(Ty->getBitWidth(), false); 242 | 243 | for (unsigned i = 0, n = PHI->getNumIncomingValues(); i < n; ++i) { 244 | BasicBlock *Pred = PHI->getIncomingBlock(i); 245 | // skip back edges 246 | if (isBackEdge(Edge(Pred, PHI->getParent()))) 247 | continue; 248 | CR.safeUnion(getRange(Pred, PHI->getIncomingValue(i))); 249 | } 250 | return CR; 251 | } 252 | 253 | bool RangePass::visitCallInst(CallInst *CI) 254 | { 255 | bool changed = false; 256 | if (CI->isInlineAsm() || Ctx->Callees.count(CI) == 0) 257 | return false; 258 | 259 | // update arguments of all possible callees 260 | FuncSet &CEEs = Ctx->Callees[CI]; 261 | for (FuncSet::iterator i = CEEs.begin(), e = CEEs.end(); i != e; ++i) { 262 | // skip vaarg and builtin functions 263 | if ((*i)->isVarArg() 264 | || (*i)->getName().find('.') != StringRef::npos) 265 | continue; 266 | 267 | for (unsigned j = 0; j < CI->getNumArgOperands(); ++j) { 268 | Value *V = CI->getArgOperand(j); 269 | // skip non-integer arguments 270 | if (!V->getType()->isIntegerTy()) 271 | continue; 272 | std::string sID = getArgId(*i, j); 273 | changed |= unionRange(sID, getRange(CI->getParent(), V), CI); 274 | } 275 | } 276 | // range for the return value of this call site 277 | if (CI->getType()->isIntegerTy()) 278 | changed |= unionRange(getRetId(CI), getRange(CI->getParent(), CI), CI); 279 | return changed; 280 | } 281 | 282 | bool RangePass::visitStoreInst(StoreInst *SI) 283 | { 284 | std::string sID = getValueId(SI); 285 | Value *V = SI->getValueOperand(); 286 | if (V->getType()->isIntegerTy() && sID != "") { 287 | CRange CR = getRange(SI->getParent(), V); 288 | unionRange(SI->getParent(), SI->getPointerOperand(), CR); 289 | return unionRange(sID, CR, SI); 290 | } 291 | return false; 292 | } 293 | 294 | bool RangePass::visitReturnInst(ReturnInst *RI) 295 | { 296 | Value *V = RI->getReturnValue(); 297 | if (!V || !V->getType()->isIntegerTy()) 298 | return false; 299 | 300 | std::string sID = getRetId(RI->getParent()->getParent()); 301 | return unionRange(sID, getRange(RI->getParent(), V), RI); 302 | } 303 | 304 | bool RangePass::updateRangeFor(Instruction *I) 305 | { 306 | bool changed = false; 307 | 308 | // store, return and call might update global range 309 | if (StoreInst *SI = dyn_cast(I)) { 310 | changed |= visitStoreInst(SI); 311 | } else if (ReturnInst *RI = dyn_cast(I)) { 312 | changed |= visitReturnInst(RI); 313 | } else if (CallInst *CI = dyn_cast(I)) { 314 | changed |= visitCallInst(CI); 315 | } 316 | 317 | IntegerType *Ty = dyn_cast(I->getType()); 318 | if (!Ty) 319 | return changed; 320 | 321 | CRange CR(Ty->getBitWidth(), true); 322 | if (BinaryOperator *BO = dyn_cast(I)) { 323 | CR = visitBinaryOp(BO); 324 | } else if (CastInst *CI = dyn_cast(I)) { 325 | CR = visitCastInst(CI); 326 | } else if (SelectInst *SI = dyn_cast(I)) { 327 | CR = visitSelectInst(SI); 328 | } else if (PHINode *PHI = dyn_cast(I)) { 329 | CR = visitPHINode(PHI); 330 | } else if (LoadInst *LI = dyn_cast(I)) { 331 | CR = getRange(LI->getParent(), LI); 332 | } else if (CallInst *CI = dyn_cast(I)) { 333 | CR = getRange(CI->getParent(), CI); 334 | } 335 | unionRange(I->getParent(), I, CR); 336 | 337 | return changed; 338 | } 339 | 340 | bool RangePass::isBackEdge(const Edge &E) 341 | { 342 | return std::find(BackEdges.begin(), BackEdges.end(), E) != BackEdges.end(); 343 | } 344 | 345 | void RangePass::visitBranchInst(BranchInst *BI, BasicBlock *BB, 346 | ValueRangeMap &VRM) 347 | { 348 | if (!BI->isConditional()) 349 | return; 350 | 351 | ICmpInst *ICI = dyn_cast(BI->getCondition()); 352 | if (ICI == NULL) 353 | return; 354 | 355 | Value *LHS = ICI->getOperand(0); 356 | Value *RHS = ICI->getOperand(1); 357 | 358 | if (!LHS->getType()->isIntegerTy() || !RHS->getType()->isIntegerTy()) 359 | return; 360 | 361 | CRange LCR = getRange(ICI->getParent(), LHS); 362 | CRange RCR = getRange(ICI->getParent(), RHS); 363 | RCR.match(LCR); 364 | 365 | if (BI->getSuccessor(0) == BB) { 366 | // true target 367 | CRange PLCR = CRange::makeICmpRegion( 368 | ICI->getSwappedPredicate(), LCR); 369 | CRange PRCR = CRange::makeICmpRegion( 370 | ICI->getPredicate(), RCR); 371 | VRM.insert(std::make_pair(LHS, LCR.intersectWith(PRCR))); 372 | VRM.insert(std::make_pair(RHS, LCR.intersectWith(PLCR))); 373 | } else { 374 | // false target, use inverse predicate 375 | // N.B. why there's no getSwappedInversePredicate()... 376 | ICI->swapOperands(); 377 | CRange PLCR = CRange::makeICmpRegion( 378 | ICI->getInversePredicate(), RCR); 379 | ICI->swapOperands(); 380 | CRange PRCR = CRange::makeICmpRegion( 381 | ICI->getInversePredicate(), RCR); 382 | VRM.insert(std::make_pair(LHS, LCR.intersectWith(PRCR))); 383 | VRM.insert(std::make_pair(RHS, LCR.intersectWith(PLCR))); 384 | } 385 | } 386 | 387 | void RangePass::visitSwitchInst(SwitchInst *SI, BasicBlock *BB, 388 | ValueRangeMap &VRM) 389 | { 390 | Value *V = SI->getCondition(); 391 | IntegerType *Ty = dyn_cast(V->getType()); 392 | if (!Ty) 393 | return; 394 | 395 | CRange VCR = getRange(SI->getParent(), V); 396 | CRange CR(Ty->getBitWidth(), false); 397 | 398 | if (SI->getDefaultDest() != BB) { 399 | // union all values that goes to BB 400 | for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); 401 | i != e; ++i) { 402 | if (i.getCaseSuccessor() == BB) 403 | CR.safeUnion(i.getCaseValue()->getValue()); 404 | } 405 | } else { 406 | // default case 407 | for (SwitchInst::CaseIt i = SI->case_begin(), e = SI->case_end(); 408 | i != e; ++i) 409 | CR.safeUnion(i.getCaseValue()->getValue()); 410 | CR = CR.inverse(); 411 | } 412 | VRM.insert(std::make_pair(V, VCR.intersectWith(CR))); 413 | } 414 | 415 | void RangePass::visitTerminator(TerminatorInst *I, BasicBlock *BB, 416 | ValueRangeMap &VRM) { 417 | if (BranchInst *BI = dyn_cast(I)) 418 | visitBranchInst(BI, BB, VRM); 419 | else if (SwitchInst *SI = dyn_cast(I)) 420 | visitSwitchInst(SI, BB, VRM); 421 | else { 422 | // ignore: I->dump(); llvm_unreachable("Unknown terminator!"); 423 | } 424 | } 425 | 426 | 427 | bool RangePass::updateRangeFor(BasicBlock *BB) 428 | { 429 | bool changed = false; 430 | 431 | // propagate value ranges from pred BBs, ranges in BB are union of ranges 432 | // in pred BBs, constrained by each terminator. 433 | for (pred_iterator i = pred_begin(BB), e = pred_end(BB); 434 | i != e; ++i) { 435 | BasicBlock *Pred = *i; 436 | if (isBackEdge(Edge(Pred, BB))) 437 | continue; 438 | 439 | ValueRangeMap &PredVRM = FuncVRMs[Pred]; 440 | ValueRangeMap &BBVRM = FuncVRMs[BB]; 441 | 442 | // Copy from its predecessor 443 | ValueRangeMap VRM(PredVRM.begin(), PredVRM.end()); 444 | // Refine according to the terminator 445 | visitTerminator(Pred->getTerminator(), BB, VRM); 446 | 447 | // union with other predecessors 448 | for (ValueRangeMap::iterator j = VRM.begin(), je = VRM.end(); 449 | j != je; ++j) { 450 | ValueRangeMap::iterator it = BBVRM.find(j->first); 451 | if (it != BBVRM.end()) 452 | it->second.safeUnion(j->second); 453 | else 454 | BBVRM.insert(*j); 455 | } 456 | } 457 | 458 | // Now run through instructions 459 | for (BasicBlock::iterator i = BB->begin(), e = BB->end(); 460 | i != e; ++i) { 461 | changed |= updateRangeFor(&*i); 462 | } 463 | 464 | return changed; 465 | } 466 | 467 | bool RangePass::updateRangeFor(Function *F) 468 | { 469 | bool changed = false; 470 | 471 | FuncVRMs.clear(); 472 | BackEdges.clear(); 473 | FindFunctionBackedges(*F, BackEdges); 474 | 475 | for (Function::iterator b = F->begin(), be = F->end(); b != be; ++b) 476 | changed |= updateRangeFor(&*b); 477 | 478 | return changed; 479 | } 480 | 481 | bool RangePass::doModulePass(Module *M) 482 | { 483 | unsigned itr = 0; 484 | bool changed = true, ret = false; 485 | 486 | while (changed) { 487 | // if some values converge too slowly, expand them to full-set 488 | if (++itr > MaxIterations) { 489 | for (ChangeSet::iterator it = Changes.begin(), ie = Changes.end(); 490 | it != ie; ++it) { 491 | RangeMap::iterator i = Ctx->IntRanges.find(*it); 492 | i->second = CRange(i->second.getBitWidth(), true); 493 | } 494 | } 495 | changed = false; 496 | Changes.clear(); 497 | for (Module::iterator i = M->begin(), e = M->end(); i != e; ++i) 498 | if (!i->empty()) 499 | changed |= updateRangeFor(&*i); 500 | ret |= changed; 501 | } 502 | return ret; 503 | } 504 | 505 | // write back 506 | bool RangePass::doFinalization(Module *M) { 507 | LLVMContext &VMCtx = M->getContext(); 508 | for (Module::iterator f = M->begin(), fe = M->end(); f != fe; ++f) { 509 | Function *F = &*f; 510 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 511 | Instruction *I = &*i; 512 | if (!isa(I) && !isa(I)) 513 | continue; 514 | I->setMetadata("intrange", NULL); 515 | std::string id = getValueId(I); 516 | if (id == "") 517 | continue; 518 | RangeMap &IRM = Ctx->IntRanges; 519 | RangeMap::iterator it = IRM.find(id); 520 | if (it == IRM.end()) 521 | continue; 522 | CRange &R = it->second; 523 | if (R.isEmptySet() || R.isFullSet()) 524 | continue; 525 | 526 | ConstantInt *Lo = ConstantInt::get(VMCtx, R.getLower()); 527 | ConstantInt *Hi = ConstantInt::get(VMCtx, R.getUpper()); 528 | Value *RL[] = { Lo, Hi }; 529 | MDNode *MD = MDNode::get(VMCtx, RL); 530 | I->setMetadata("intrange", MD); 531 | } 532 | } 533 | return true; 534 | } 535 | 536 | 537 | void RangePass::dumpRange() 538 | { 539 | raw_ostream &OS = dbgs(); 540 | for (RangeMap::iterator i = Ctx->IntRanges.begin(), 541 | e = Ctx->IntRanges.end(); i != e; ++i) { 542 | OS << i->first << " " << i->second << "\n"; 543 | } 544 | } 545 | 546 | -------------------------------------------------------------------------------- /src/SMTBoolector.cc: -------------------------------------------------------------------------------- 1 | #include "SMTSolver.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | extern "C" { 12 | #include 13 | } 14 | 15 | using namespace llvm; 16 | 17 | #define ctx ((Btor *)ctx_) 18 | #define m ((Btor *)m_) 19 | #define e ((BtorNode *)e_) 20 | #define lhs ((BtorNode *)lhs_) 21 | #define rhs ((BtorNode *)rhs_) 22 | 23 | // Boolector 1.5 is much slower due to the new SAT backend. 24 | // Use the workaround to disable preprocessing for performance. 25 | namespace { 26 | struct SMTWorkaround { 27 | SMTWorkaround() { ::setenv("LGLPLAIN", "1", 1); } 28 | }; 29 | } 30 | 31 | static SMTWorkaround X; 32 | 33 | SMTSolver::SMTSolver(bool modelgen) { 34 | ctx_ = boolector_new(); 35 | if (modelgen) 36 | boolector_enable_model_gen(ctx); 37 | boolector_enable_inc_usage(ctx); 38 | } 39 | 40 | SMTSolver::~SMTSolver() { 41 | assert(boolector_get_refs(ctx) == 0); 42 | boolector_delete(ctx); 43 | } 44 | 45 | void SMTSolver::assume(SMTExpr e_) { 46 | boolector_assert(ctx, e); 47 | } 48 | 49 | SMTStatus SMTSolver::query(SMTExpr e_, SMTModel *m_) { 50 | boolector_assume(ctx, e); 51 | switch (boolector_sat(ctx)) { 52 | default: return SMT_UNDEF; 53 | case BOOLECTOR_UNSAT: return SMT_UNSAT; 54 | case BOOLECTOR_SAT: break; 55 | } 56 | if (m_) 57 | *m_ = ctx_; 58 | return SMT_SAT; 59 | } 60 | 61 | void SMTSolver::eval(SMTModel m_, SMTExpr e_, APInt &v) { 62 | char *s = boolector_bv_assignment(ctx, e); 63 | std::string str(s); 64 | boolector_free_bv_assignment(ctx, s); 65 | std::replace(str.begin(), str.end(), 'x', '0'); 66 | v = APInt(bvwidth(e), str.c_str(), 2); 67 | } 68 | 69 | void SMTSolver::release(SMTModel m_) {} 70 | 71 | void SMTSolver::dump(SMTExpr e_) { 72 | print(e, dbgs()); 73 | dbgs() << "\n"; 74 | } 75 | 76 | void SMTSolver::print(SMTExpr e_, raw_ostream &OS) { 77 | FILE *fp = tmpfile(); 78 | assert(fp && "tmpfile"); 79 | boolector_dump_smt(ctx, fp, e); 80 | long n = ftell(fp); 81 | fseek(fp, 0, SEEK_SET); 82 | char *s = (char *)malloc(n + 1); 83 | n = fread(s, 1, n, fp); 84 | assert(n > 0); 85 | s[n] = 0; 86 | OS << s; 87 | free(s); 88 | fclose(fp); 89 | } 90 | 91 | void SMTSolver::incref(SMTExpr e_) { 92 | boolector_copy(ctx, e); 93 | } 94 | 95 | void SMTSolver::decref(SMTExpr e_) { 96 | boolector_release(ctx, e); 97 | } 98 | 99 | unsigned SMTSolver::bvwidth(SMTExpr e_) { 100 | return boolector_get_width(ctx, e); 101 | } 102 | 103 | SMTExpr SMTSolver::bvfalse() { 104 | return boolector_false(ctx); 105 | } 106 | 107 | SMTExpr SMTSolver::bvtrue() { 108 | return boolector_true(ctx); 109 | } 110 | 111 | SMTExpr SMTSolver::bvconst(const APInt &Val) { 112 | unsigned intbits = sizeof(unsigned) * CHAR_BIT; 113 | unsigned width = Val.getBitWidth(); 114 | if (width <= intbits) 115 | return boolector_unsigned_int(ctx, Val.getZExtValue(), width); 116 | SmallString<32> Str, FullStr; 117 | Val.toStringUnsigned(Str, 2); 118 | assert(Str.size() <= width); 119 | FullStr.assign(width - Str.size(), '0'); 120 | FullStr += Str; 121 | return boolector_const(ctx, FullStr.c_str()); 122 | } 123 | 124 | SMTExpr SMTSolver::bvvar(unsigned width, const char *name) { 125 | return boolector_var(ctx, width, name); 126 | } 127 | 128 | SMTExpr SMTSolver::ite(SMTExpr e_, SMTExpr lhs_, SMTExpr rhs_) { 129 | return boolector_cond(ctx, e, lhs, rhs); 130 | } 131 | 132 | SMTExpr SMTSolver::eq(SMTExpr lhs_, SMTExpr rhs_) { 133 | return boolector_eq(ctx, lhs, rhs); 134 | } 135 | 136 | SMTExpr SMTSolver::ne(SMTExpr lhs_, SMTExpr rhs_) { 137 | return boolector_ne(ctx, lhs, rhs); 138 | } 139 | 140 | SMTExpr SMTSolver::bvslt(SMTExpr lhs_, SMTExpr rhs_) { 141 | return boolector_slt(ctx, lhs, rhs); 142 | } 143 | 144 | SMTExpr SMTSolver::bvsle(SMTExpr lhs_, SMTExpr rhs_) { 145 | return boolector_slte(ctx, lhs, rhs); 146 | } 147 | 148 | SMTExpr SMTSolver::bvsgt(SMTExpr lhs_, SMTExpr rhs_) { 149 | return boolector_sgt(ctx, lhs, rhs); 150 | } 151 | 152 | SMTExpr SMTSolver::bvsge(SMTExpr lhs_, SMTExpr rhs_) { 153 | return boolector_sgte(ctx, lhs, rhs); 154 | } 155 | 156 | SMTExpr SMTSolver::bvult(SMTExpr lhs_, SMTExpr rhs_) { 157 | return boolector_ult(ctx, lhs, rhs); 158 | } 159 | 160 | SMTExpr SMTSolver::bvule(SMTExpr lhs_, SMTExpr rhs_) { 161 | return boolector_ulte(ctx, lhs, rhs); 162 | } 163 | 164 | SMTExpr SMTSolver::bvugt(SMTExpr lhs_, SMTExpr rhs_) { 165 | return boolector_ugt(ctx, lhs, rhs); 166 | } 167 | 168 | SMTExpr SMTSolver::bvuge(SMTExpr lhs_, SMTExpr rhs_) { 169 | return boolector_ugte(ctx, lhs, rhs); 170 | } 171 | 172 | SMTExpr SMTSolver::extract(unsigned high, unsigned low, SMTExpr e_) { 173 | return boolector_slice(ctx, e, high, low); 174 | } 175 | 176 | SMTExpr SMTSolver::zero_extend(unsigned i, SMTExpr e_) { 177 | return boolector_uext(ctx, e, i); 178 | } 179 | 180 | SMTExpr SMTSolver::sign_extend(unsigned i, SMTExpr e_) { 181 | return boolector_sext(ctx, e, i); 182 | } 183 | 184 | SMTExpr SMTSolver::bvredand(SMTExpr e_) { 185 | return boolector_redand(ctx, e); 186 | } 187 | 188 | SMTExpr SMTSolver::bvredor(SMTExpr e_) { 189 | return boolector_redor(ctx, e); 190 | } 191 | 192 | SMTExpr SMTSolver::bvnot(SMTExpr e_) { 193 | return boolector_not(ctx, e); 194 | } 195 | 196 | SMTExpr SMTSolver::bvneg(SMTExpr e_) { 197 | return boolector_neg(ctx, e); 198 | } 199 | 200 | SMTExpr SMTSolver::bvadd(SMTExpr lhs_, SMTExpr rhs_) { 201 | return boolector_add(ctx, lhs, rhs); 202 | } 203 | 204 | SMTExpr SMTSolver::bvsub(SMTExpr lhs_, SMTExpr rhs_) { 205 | return boolector_sub(ctx, lhs, rhs); 206 | } 207 | 208 | SMTExpr SMTSolver::bvmul(SMTExpr lhs_, SMTExpr rhs_) { 209 | return boolector_mul(ctx, lhs, rhs); 210 | } 211 | 212 | SMTExpr SMTSolver::bvsdiv(SMTExpr lhs_, SMTExpr rhs_) { 213 | return boolector_sdiv(ctx, lhs, rhs); 214 | } 215 | 216 | SMTExpr SMTSolver::bvudiv(SMTExpr lhs_, SMTExpr rhs_) { 217 | return boolector_udiv(ctx, lhs, rhs); 218 | } 219 | 220 | SMTExpr SMTSolver::bvsrem(SMTExpr lhs_, SMTExpr rhs_) { 221 | return boolector_srem(ctx, lhs, rhs); 222 | } 223 | 224 | SMTExpr SMTSolver::bvurem(SMTExpr lhs_, SMTExpr rhs_) { 225 | return boolector_urem(ctx, lhs, rhs); 226 | } 227 | 228 | // Shift operations use log2n bits for shifting amount. 229 | template 230 | static inline SMTExpr shift(Btor *btor, BtorNode *e0, BtorNode *e1) { 231 | unsigned n = boolector_get_width(btor, e1); 232 | // Round up to nearest power of 2. 233 | unsigned amount = (sizeof(n) * CHAR_BIT - __builtin_clz(n - 1)); 234 | unsigned power2 = 1U << amount; 235 | // Extend e0 to power2 bits. 236 | if (power2 != n) 237 | e0 = boolector_uext(btor, e0, power2 - n); 238 | BtorNode *log2w = boolector_slice(btor, e1, amount - 1, 0); 239 | BtorNode *result = F(btor, e0, log2w); 240 | boolector_release(btor, log2w); 241 | if (power2 != n) { 242 | boolector_release(btor, e0); 243 | // Truncate result back to n bits. 244 | BtorNode *tmp = boolector_slice(btor, result, n - 1, 0); 245 | boolector_release(btor, result); 246 | result = tmp; 247 | } 248 | return result; 249 | } 250 | 251 | SMTExpr SMTSolver::bvshl(SMTExpr lhs_, SMTExpr rhs_) { 252 | return shift(ctx, lhs, rhs); 253 | } 254 | 255 | SMTExpr SMTSolver::bvlshr(SMTExpr lhs_, SMTExpr rhs_) { 256 | return shift(ctx, lhs, rhs); 257 | } 258 | 259 | SMTExpr SMTSolver::bvashr(SMTExpr lhs_, SMTExpr rhs_) { 260 | return shift(ctx, lhs, rhs); 261 | } 262 | 263 | SMTExpr SMTSolver::bvand(SMTExpr lhs_, SMTExpr rhs_) { 264 | return boolector_and(ctx, lhs, rhs); 265 | } 266 | 267 | SMTExpr SMTSolver::bvor(SMTExpr lhs_, SMTExpr rhs_) { 268 | return boolector_or(ctx, lhs, rhs); 269 | } 270 | 271 | SMTExpr SMTSolver::bvxor(SMTExpr lhs_, SMTExpr rhs_) { 272 | return boolector_xor(ctx, lhs, rhs); 273 | } 274 | 275 | SMTExpr SMTSolver::bvneg_overflow(SMTExpr e_) { 276 | SMTExpr zero = boolector_zero(ctx, bvwidth(e)); 277 | SMTExpr tmp = bvssub_overflow(zero, e); 278 | decref(zero); 279 | return tmp; 280 | } 281 | 282 | SMTExpr SMTSolver::bvsadd_overflow(SMTExpr lhs_, SMTExpr rhs_) { 283 | return boolector_saddo(ctx, lhs, rhs); 284 | } 285 | 286 | SMTExpr SMTSolver::bvuadd_overflow(SMTExpr lhs_, SMTExpr rhs_) { 287 | return boolector_uaddo(ctx, lhs, rhs); 288 | } 289 | 290 | SMTExpr SMTSolver::bvssub_overflow(SMTExpr lhs_, SMTExpr rhs_) { 291 | return boolector_ssubo(ctx, lhs, rhs); 292 | } 293 | 294 | SMTExpr SMTSolver::bvusub_overflow(SMTExpr lhs_, SMTExpr rhs_) { 295 | return boolector_usubo(ctx, lhs, rhs); 296 | } 297 | 298 | SMTExpr SMTSolver::bvsmul_overflow(SMTExpr lhs_, SMTExpr rhs_) { 299 | return boolector_smulo(ctx, lhs, rhs); 300 | } 301 | 302 | SMTExpr SMTSolver::bvumul_overflow(SMTExpr lhs_, SMTExpr rhs_) { 303 | return boolector_umulo(ctx, lhs, rhs); 304 | } 305 | 306 | SMTExpr SMTSolver::bvsdiv_overflow(SMTExpr lhs_, SMTExpr rhs_) { 307 | return boolector_sdivo(ctx, lhs, rhs); 308 | } 309 | -------------------------------------------------------------------------------- /src/SMTSolver.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | using namespace llvm; 8 | 9 | static cl::opt 10 | SMTTimeoutOpt("smt-timeout", 11 | cl::desc("Specify a timeout for SMT solver"), 12 | cl::value_desc("milliseconds")); 13 | 14 | static pid_t pid; 15 | 16 | int SMTFork() 17 | { 18 | if (!SMTTimeoutOpt) 19 | return 0; 20 | pid = fork(); 21 | if (pid < 0) 22 | err(1, "fork"); 23 | // Parent process. 24 | if (pid) 25 | return 1; 26 | // Child process. 27 | struct itimerval itv = {{0, 0}, {SMTTimeoutOpt / 1000, SMTTimeoutOpt % 1000 * 1000}}; 28 | setitimer(ITIMER_VIRTUAL, &itv, NULL); 29 | return 0; 30 | } 31 | 32 | void SMTJoin(int *status) 33 | { 34 | if (!SMTTimeoutOpt) 35 | return; 36 | // Child process. 37 | if (pid == 0) 38 | _exit(*status); 39 | // Parent process. 40 | waitpid(pid, status, 0); 41 | if (WIFEXITED(*status)) 42 | *status = WEXITSTATUS(*status); 43 | else 44 | *status = -1; 45 | } 46 | -------------------------------------------------------------------------------- /src/SMTSolver.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | namespace llvm { 4 | class APInt; 5 | class raw_ostream; 6 | } // namespace llvm 7 | 8 | enum SMTStatus { 9 | SMT_TIMEOUT = -1, 10 | SMT_UNDEF, 11 | SMT_UNSAT, 12 | SMT_SAT, 13 | }; 14 | 15 | typedef void *SMTContext; 16 | typedef void *SMTExpr; 17 | typedef void *SMTModel; 18 | 19 | int SMTFork(); 20 | void SMTJoin(int *); 21 | 22 | class SMTSolver { 23 | public: 24 | SMTSolver(bool modelgen); 25 | ~SMTSolver(); 26 | 27 | void assume(SMTExpr); 28 | 29 | SMTStatus query(SMTExpr, SMTModel * = 0); 30 | void eval(SMTModel, SMTExpr, llvm::APInt &); 31 | void release(SMTModel); 32 | 33 | void dump(SMTExpr); 34 | void print(SMTExpr, llvm::raw_ostream &); 35 | 36 | void incref(SMTExpr); 37 | void decref(SMTExpr); 38 | 39 | unsigned bvwidth(SMTExpr); 40 | 41 | SMTExpr bvfalse(); 42 | SMTExpr bvtrue(); 43 | SMTExpr bvconst(const llvm::APInt &); 44 | SMTExpr bvvar(unsigned width, const char *name); 45 | 46 | // If-else-then. 47 | SMTExpr ite(SMTExpr, SMTExpr, SMTExpr); 48 | 49 | // Comparison. 50 | SMTExpr eq(SMTExpr, SMTExpr); 51 | SMTExpr ne(SMTExpr, SMTExpr); 52 | SMTExpr bvslt(SMTExpr, SMTExpr); 53 | SMTExpr bvsle(SMTExpr, SMTExpr); 54 | SMTExpr bvsgt(SMTExpr, SMTExpr); 55 | SMTExpr bvsge(SMTExpr, SMTExpr); 56 | SMTExpr bvult(SMTExpr, SMTExpr); 57 | SMTExpr bvule(SMTExpr, SMTExpr); 58 | SMTExpr bvugt(SMTExpr, SMTExpr); 59 | SMTExpr bvuge(SMTExpr, SMTExpr); 60 | 61 | SMTExpr extract(unsigned high, unsigned low, SMTExpr); 62 | SMTExpr zero_extend(unsigned i, SMTExpr); 63 | SMTExpr sign_extend(unsigned i, SMTExpr); 64 | 65 | SMTExpr bvredand(SMTExpr); 66 | SMTExpr bvredor(SMTExpr); 67 | SMTExpr bvnot(SMTExpr); 68 | SMTExpr bvneg(SMTExpr); 69 | 70 | // Arithmetic operations. 71 | SMTExpr bvadd(SMTExpr, SMTExpr); 72 | SMTExpr bvsub(SMTExpr, SMTExpr); 73 | SMTExpr bvmul(SMTExpr, SMTExpr); 74 | SMTExpr bvsdiv(SMTExpr, SMTExpr); 75 | SMTExpr bvudiv(SMTExpr, SMTExpr); 76 | SMTExpr bvsrem(SMTExpr, SMTExpr); 77 | SMTExpr bvurem(SMTExpr, SMTExpr); 78 | SMTExpr bvshl(SMTExpr, SMTExpr); 79 | SMTExpr bvlshr(SMTExpr, SMTExpr); 80 | SMTExpr bvashr(SMTExpr, SMTExpr); 81 | SMTExpr bvand(SMTExpr, SMTExpr); 82 | SMTExpr bvor(SMTExpr, SMTExpr); 83 | SMTExpr bvxor(SMTExpr, SMTExpr); 84 | 85 | // Overflow detection. 86 | SMTExpr bvneg_overflow(SMTExpr); 87 | SMTExpr bvsadd_overflow(SMTExpr, SMTExpr); 88 | SMTExpr bvuadd_overflow(SMTExpr, SMTExpr); 89 | SMTExpr bvssub_overflow(SMTExpr, SMTExpr); 90 | SMTExpr bvusub_overflow(SMTExpr, SMTExpr); 91 | SMTExpr bvsmul_overflow(SMTExpr, SMTExpr); 92 | SMTExpr bvumul_overflow(SMTExpr, SMTExpr); 93 | SMTExpr bvsdiv_overflow(SMTExpr, SMTExpr); 94 | 95 | private: 96 | SMTContext ctx_; 97 | }; 98 | -------------------------------------------------------------------------------- /src/SMTSonolar.cc: -------------------------------------------------------------------------------- 1 | #include "SMTSolver.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | 8 | using namespace llvm; 9 | 10 | #define ctx ((sonolar_t)ctx_) 11 | #define m ((sonolar_t *)m_) 12 | #define e ((sonolar_term_t *)e_) 13 | #define lhs ((sonolar_term_t *)lhs_) 14 | #define rhs ((sonolar_term_t *)rhs_) 15 | 16 | SMTSolver::SMTSolver(bool /*modelgen*/) { 17 | ctx_ = sonolar_create(); 18 | if (sonolar_set_sat_solver(ctx, SONOLAR_SAT_SOLVER_MINISAT)) 19 | assert(0 && "sonolar_set_sat_solver"); 20 | } 21 | 22 | SMTSolver::~SMTSolver() { 23 | sonolar_destroy(ctx); 24 | } 25 | 26 | void SMTSolver::assume(SMTExpr e_) { 27 | sonolar_assert_formula(ctx, e); 28 | } 29 | 30 | SMTStatus SMTSolver::query(SMTExpr e_, SMTModel *m_) { 31 | if (sonolar_assume_formula(ctx, e)) 32 | assert(0 && "sonolar_assume_formula"); 33 | switch (sonolar_solve(ctx)) { 34 | default: return SMT_UNDEF; 35 | case SONOLAR_SOLVE_RESULT_UNSAT: return SMT_UNSAT; 36 | case SONOLAR_SOLVE_RESULT_SAT: break; 37 | } 38 | if (m_) 39 | *m_ = ctx; 40 | return SMT_SAT; 41 | } 42 | 43 | void SMTSolver::eval(SMTModel m_, SMTExpr e_, APInt &) { 44 | assert(0 && "NOT SUPPORTED"); 45 | } 46 | 47 | void SMTSolver::release(SMTModel m_) {} 48 | 49 | void SMTSolver::dump(SMTExpr e_) { 50 | print(e, dbgs()); 51 | dbgs() << "\n"; 52 | } 53 | 54 | void SMTSolver::print(SMTExpr e_, raw_ostream &OS) { 55 | OS << "NOT SUPPORTED"; 56 | } 57 | 58 | void SMTSolver::incref(SMTExpr e_) { 59 | sonolar_add_reference(ctx, e); 60 | } 61 | 62 | void SMTSolver::decref(SMTExpr e_) { 63 | sonolar_remove_reference(ctx, e); 64 | } 65 | 66 | unsigned SMTSolver::bvwidth(SMTExpr e_) { 67 | size_t width; 68 | if (sonolar_get_bitwidth(ctx, e, &width)) 69 | assert(0 && "sonolar_get_bitwidth"); 70 | return (unsigned)width; 71 | } 72 | 73 | SMTExpr SMTSolver::bvfalse() { 74 | return sonolar_make_constant_false(ctx); 75 | } 76 | 77 | SMTExpr SMTSolver::bvtrue() { 78 | return sonolar_make_constant_true(ctx); 79 | } 80 | 81 | SMTExpr SMTSolver::bvconst(const APInt &Val) { 82 | const void *data = Val.getRawData(); 83 | unsigned width = Val.getBitWidth(); 84 | return sonolar_make_constant_bytes(ctx, data, width, SONOLAR_BYTE_ORDER_NATIVE); 85 | } 86 | 87 | SMTExpr SMTSolver::bvvar(unsigned width, const char *name) { 88 | return sonolar_make_variable(ctx, width, name); 89 | } 90 | 91 | SMTExpr SMTSolver::ite(SMTExpr e_, SMTExpr lhs_, SMTExpr rhs_) { 92 | return sonolar_make_ite(ctx, e, lhs, rhs); 93 | } 94 | 95 | SMTExpr SMTSolver::eq(SMTExpr lhs_, SMTExpr rhs_) { 96 | return sonolar_make_equal(ctx, lhs, rhs); 97 | } 98 | 99 | SMTExpr SMTSolver::ne(SMTExpr lhs_, SMTExpr rhs_) { 100 | return sonolar_make_distinct(ctx, lhs, rhs); 101 | } 102 | 103 | SMTExpr SMTSolver::bvslt(SMTExpr lhs_, SMTExpr rhs_) { 104 | return sonolar_make_bv_slt(ctx, lhs, rhs); 105 | } 106 | 107 | SMTExpr SMTSolver::bvsle(SMTExpr lhs_, SMTExpr rhs_) { 108 | return sonolar_make_bv_sle(ctx, lhs, rhs); 109 | } 110 | 111 | SMTExpr SMTSolver::bvsgt(SMTExpr lhs_, SMTExpr rhs_) { 112 | return sonolar_make_bv_sgt(ctx, lhs, rhs); 113 | } 114 | 115 | SMTExpr SMTSolver::bvsge(SMTExpr lhs_, SMTExpr rhs_) { 116 | return sonolar_make_bv_sge(ctx, lhs, rhs); 117 | } 118 | 119 | SMTExpr SMTSolver::bvult(SMTExpr lhs_, SMTExpr rhs_) { 120 | return sonolar_make_bv_ult(ctx, lhs, rhs); 121 | } 122 | 123 | SMTExpr SMTSolver::bvule(SMTExpr lhs_, SMTExpr rhs_) { 124 | return sonolar_make_bv_ule(ctx, lhs, rhs); 125 | } 126 | 127 | SMTExpr SMTSolver::bvugt(SMTExpr lhs_, SMTExpr rhs_) { 128 | return sonolar_make_bv_ugt(ctx, lhs, rhs); 129 | } 130 | 131 | SMTExpr SMTSolver::bvuge(SMTExpr lhs_, SMTExpr rhs_) { 132 | return sonolar_make_bv_uge(ctx, lhs, rhs); 133 | } 134 | 135 | SMTExpr SMTSolver::extract(unsigned high, unsigned low, SMTExpr e_) { 136 | return sonolar_make_bv_extract(ctx, e, high, low); 137 | } 138 | 139 | SMTExpr SMTSolver::zero_extend(unsigned i, SMTExpr e_) { 140 | return sonolar_make_bv_zero_extend(ctx, e, i); 141 | } 142 | 143 | SMTExpr SMTSolver::sign_extend(unsigned i, SMTExpr e_) { 144 | return sonolar_make_bv_sign_extend(ctx, e, i); 145 | } 146 | 147 | SMTExpr SMTSolver::bvredand(SMTExpr e_) { 148 | SMTExpr neg = bvnot(e); 149 | SMTExpr tmp = sonolar_make_is_zero(ctx, neg); 150 | decref(neg); 151 | return tmp; 152 | } 153 | 154 | SMTExpr SMTSolver::bvredor(SMTExpr e_) { 155 | SMTExpr z = sonolar_make_is_zero(ctx, e); 156 | SMTExpr nz = sonolar_make_not(ctx, z); 157 | decref(z); 158 | return nz; 159 | } 160 | 161 | SMTExpr SMTSolver::bvnot(SMTExpr e_) { 162 | return sonolar_make_bv_not(ctx, e); 163 | } 164 | 165 | SMTExpr SMTSolver::bvneg(SMTExpr e_) { 166 | return sonolar_make_bv_neg(ctx, e); 167 | } 168 | 169 | SMTExpr SMTSolver::bvadd(SMTExpr lhs_, SMTExpr rhs_) { 170 | return sonolar_make_bv_add(ctx, lhs, rhs); 171 | } 172 | 173 | SMTExpr SMTSolver::bvsub(SMTExpr lhs_, SMTExpr rhs_) { 174 | return sonolar_make_bv_sub(ctx, lhs, rhs); 175 | } 176 | 177 | SMTExpr SMTSolver::bvmul(SMTExpr lhs_, SMTExpr rhs_) { 178 | return sonolar_make_bv_mul(ctx, lhs, rhs); 179 | } 180 | 181 | SMTExpr SMTSolver::bvsdiv(SMTExpr lhs_, SMTExpr rhs_) { 182 | return sonolar_make_bv_sdiv(ctx, lhs, rhs); 183 | } 184 | 185 | SMTExpr SMTSolver::bvudiv(SMTExpr lhs_, SMTExpr rhs_) { 186 | return sonolar_make_bv_udiv(ctx, lhs, rhs); 187 | } 188 | 189 | SMTExpr SMTSolver::bvsrem(SMTExpr lhs_, SMTExpr rhs_) { 190 | return sonolar_make_bv_srem(ctx, lhs, rhs); 191 | } 192 | 193 | SMTExpr SMTSolver::bvurem(SMTExpr lhs_, SMTExpr rhs_) { 194 | return sonolar_make_bv_urem(ctx, lhs, rhs); 195 | } 196 | 197 | SMTExpr SMTSolver::bvshl(SMTExpr lhs_, SMTExpr rhs_) { 198 | return sonolar_make_bv_shl(ctx, lhs, rhs); 199 | } 200 | 201 | SMTExpr SMTSolver::bvlshr(SMTExpr lhs_, SMTExpr rhs_) { 202 | return sonolar_make_bv_lshr(ctx, lhs, rhs); 203 | } 204 | 205 | SMTExpr SMTSolver::bvashr(SMTExpr lhs_, SMTExpr rhs_) { 206 | return sonolar_make_bv_ashr(ctx, lhs, rhs); 207 | } 208 | 209 | SMTExpr SMTSolver::bvand(SMTExpr lhs_, SMTExpr rhs_) { 210 | return sonolar_make_bv_and(ctx, lhs, rhs); 211 | } 212 | 213 | SMTExpr SMTSolver::bvor(SMTExpr lhs_, SMTExpr rhs_) { 214 | return sonolar_make_bv_or(ctx, lhs, rhs); 215 | } 216 | 217 | SMTExpr SMTSolver::bvxor(SMTExpr lhs_, SMTExpr rhs_) { 218 | return sonolar_make_bv_xor(ctx, lhs, rhs); 219 | } 220 | 221 | SMTExpr SMTSolver::bvneg_overflow(SMTExpr e_) { 222 | SMTExpr zero = sonolar_make_constant_0_bits(ctx, bvwidth(e)); 223 | SMTExpr tmp = bvssub_overflow(zero, e); 224 | decref(zero); 225 | return tmp; 226 | } 227 | 228 | SMTExpr SMTSolver::bvsadd_overflow(SMTExpr lhs_, SMTExpr rhs_) { 229 | return sonolar_make_bv_sadd_ovfl(ctx, lhs, rhs); 230 | } 231 | 232 | SMTExpr SMTSolver::bvuadd_overflow(SMTExpr lhs_, SMTExpr rhs_) { 233 | return sonolar_make_bv_uadd_ovfl(ctx, lhs, rhs); 234 | } 235 | 236 | SMTExpr SMTSolver::bvssub_overflow(SMTExpr lhs_, SMTExpr rhs_) { 237 | return sonolar_make_bv_ssub_ovfl(ctx, lhs, rhs); 238 | } 239 | 240 | SMTExpr SMTSolver::bvusub_overflow(SMTExpr lhs_, SMTExpr rhs_) { 241 | return sonolar_make_bv_usub_ovfl(ctx, lhs, rhs); 242 | } 243 | 244 | SMTExpr SMTSolver::bvsmul_overflow(SMTExpr lhs_, SMTExpr rhs_) { 245 | return sonolar_make_bv_smul_ovfl(ctx, lhs, rhs); 246 | } 247 | 248 | SMTExpr SMTSolver::bvumul_overflow(SMTExpr lhs_, SMTExpr rhs_) { 249 | return sonolar_make_bv_umul_ovfl(ctx, lhs, rhs); 250 | } 251 | 252 | SMTExpr SMTSolver::bvsdiv_overflow(SMTExpr lhs_, SMTExpr rhs_) { 253 | return sonolar_make_bv_sdiv_ovfl(ctx, lhs, rhs); 254 | } 255 | -------------------------------------------------------------------------------- /src/SMTZ3.cc: -------------------------------------------------------------------------------- 1 | #include "SMTSolver.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | using namespace llvm; 10 | 11 | struct SMTContextImpl { 12 | Z3_context c; 13 | Z3_ast bvfalse; 14 | Z3_ast bvtrue; 15 | }; 16 | 17 | #define imp ((SMTContextImpl *)ctx_) 18 | #define ctx (imp->c) 19 | #define m ((Z3_model)m_) 20 | #define e ((Z3_ast)e_) 21 | #define lhs ((Z3_ast)lhs_) 22 | #define rhs ((Z3_ast)rhs_) 23 | 24 | static inline Z3_ast bv2bool_(SMTContextImpl *ctx_, Z3_ast e0) { 25 | return Z3_mk_eq(ctx, e0, ctx_->bvtrue); 26 | } 27 | 28 | static inline Z3_ast bool2bv_(SMTContextImpl *ctx_, Z3_ast e0) { 29 | return Z3_mk_ite(ctx, e0, ctx_->bvtrue, ctx_->bvfalse); 30 | } 31 | 32 | #define bv2bool(x) bv2bool_(imp, x) 33 | #define bool2bv(x) bool2bv_(imp, x) 34 | 35 | SMTSolver::SMTSolver(bool modelgen) { 36 | ctx_ = new SMTContextImpl; 37 | Z3_config cfg = Z3_mk_config(); 38 | // Enable model construction. 39 | if (modelgen) 40 | Z3_set_param_value(cfg, "MODEL", "true"); 41 | ctx = Z3_mk_context(cfg); 42 | Z3_del_config(cfg); 43 | // Set up constants. 44 | Z3_sort sort = Z3_mk_bv_sort(ctx, 1); 45 | imp->bvfalse = Z3_mk_int(ctx, 0, sort); 46 | imp->bvtrue = Z3_mk_int(ctx, 1, sort); 47 | } 48 | 49 | SMTSolver::~SMTSolver() { 50 | Z3_del_context(ctx); 51 | delete imp; 52 | } 53 | 54 | void SMTSolver::assume(SMTExpr e_) { 55 | Z3_assert_cnstr(ctx, bv2bool(e)); 56 | } 57 | 58 | SMTStatus SMTSolver::query(SMTExpr e_, SMTModel *m_) { 59 | Z3_push(ctx); 60 | Z3_assert_cnstr(ctx, bv2bool(e)); 61 | Z3_lbool res = Z3_check_and_get_model(ctx, (Z3_model *)m_); 62 | Z3_pop(ctx, 1); 63 | switch (res) { 64 | default: return SMT_UNDEF; 65 | case Z3_L_FALSE: return SMT_UNSAT; 66 | case Z3_L_TRUE: return SMT_SAT; 67 | } 68 | } 69 | 70 | void SMTSolver::eval(SMTModel m_, SMTExpr e_, APInt &r) { 71 | Z3_ast v = 0; 72 | Z3_bool ret = Z3_model_eval(ctx, m, e, Z3_TRUE, &v); 73 | assert(ret); 74 | assert(v); 75 | if (Z3_is_numeral_ast(ctx, v)) { 76 | r = APInt(bvwidth(v), Z3_get_numeral_string(ctx, v), 10); 77 | return; 78 | } 79 | if (bvwidth(v) == 1 && Z3_is_app(ctx, v)) { 80 | Z3_push(ctx); 81 | Z3_assert_cnstr(ctx, Z3_mk_eq(ctx, v, imp->bvtrue)); 82 | switch (Z3_check(ctx)) { 83 | default: assert(0); 84 | case Z3_L_FALSE: r = APInt(1, 0); break; 85 | case Z3_L_TRUE: r = APInt(1, 1); break; 86 | } 87 | Z3_pop(ctx, 1); 88 | return; 89 | } 90 | assert(0); 91 | } 92 | 93 | void SMTSolver::release(SMTModel m_) { 94 | Z3_del_model(ctx, m); 95 | } 96 | 97 | void SMTSolver::dump(SMTExpr e_) { 98 | print(e, dbgs()); 99 | dbgs() << "\n"; 100 | } 101 | 102 | void SMTSolver::print(SMTExpr e_, raw_ostream &OS) { 103 | OS << Z3_ast_to_string(ctx, Z3_simplify(ctx, e)); 104 | } 105 | 106 | // Managed by Z3, no reference counting. 107 | void SMTSolver::incref(SMTExpr) { } 108 | void SMTSolver::decref(SMTExpr) { } 109 | 110 | unsigned SMTSolver::bvwidth(SMTExpr e_) { 111 | return Z3_get_bv_sort_size(ctx, Z3_get_sort(ctx, e)); 112 | } 113 | 114 | SMTExpr SMTSolver::bvfalse() { 115 | return imp->bvfalse; 116 | } 117 | 118 | SMTExpr SMTSolver::bvtrue() { 119 | return imp->bvtrue; 120 | } 121 | 122 | SMTExpr SMTSolver::bvconst(const APInt &Val) { 123 | unsigned width = Val.getBitWidth(); 124 | Z3_sort t = Z3_mk_bv_sort(ctx, width); 125 | if (width <= 64) 126 | return Z3_mk_unsigned_int64(ctx, Val.getZExtValue(), t); 127 | SmallString<32> s; 128 | Val.toStringUnsigned(s); 129 | return Z3_mk_numeral(ctx, s.c_str(), t); 130 | } 131 | 132 | SMTExpr SMTSolver::bvvar(unsigned width, const char *name) { 133 | return Z3_mk_const(ctx, Z3_mk_string_symbol(ctx, name), Z3_mk_bv_sort(ctx, width)); 134 | } 135 | 136 | SMTExpr SMTSolver::ite(SMTExpr e_, SMTExpr lhs_, SMTExpr rhs_) { 137 | return Z3_mk_ite(ctx, bv2bool(e), lhs, rhs); 138 | } 139 | 140 | SMTExpr SMTSolver::eq(SMTExpr lhs_, SMTExpr rhs_) { 141 | return bool2bv(Z3_mk_eq(ctx, lhs, rhs)); 142 | } 143 | 144 | SMTExpr SMTSolver::ne(SMTExpr lhs_, SMTExpr rhs_) { 145 | return bvnot(eq(lhs_, rhs_)); 146 | } 147 | 148 | SMTExpr SMTSolver::bvslt(SMTExpr lhs_, SMTExpr rhs_) { 149 | return bool2bv(Z3_mk_bvslt(ctx, lhs, rhs)); 150 | } 151 | 152 | SMTExpr SMTSolver::bvsle(SMTExpr lhs_, SMTExpr rhs_) { 153 | return bool2bv(Z3_mk_bvsle(ctx, lhs, rhs)); 154 | } 155 | 156 | SMTExpr SMTSolver::bvsgt(SMTExpr lhs_, SMTExpr rhs_) { 157 | return bool2bv(Z3_mk_bvsgt(ctx, lhs, rhs)); 158 | } 159 | 160 | SMTExpr SMTSolver::bvsge(SMTExpr lhs_, SMTExpr rhs_) { 161 | return bool2bv(Z3_mk_bvsge(ctx, lhs, rhs)); 162 | } 163 | 164 | SMTExpr SMTSolver::bvult(SMTExpr lhs_, SMTExpr rhs_) { 165 | return bool2bv(Z3_mk_bvult(ctx, lhs, rhs)); 166 | } 167 | 168 | SMTExpr SMTSolver::bvule(SMTExpr lhs_, SMTExpr rhs_) { 169 | return bool2bv(Z3_mk_bvule(ctx, lhs, rhs)); 170 | } 171 | 172 | SMTExpr SMTSolver::bvugt(SMTExpr lhs_, SMTExpr rhs_) { 173 | return bool2bv(Z3_mk_bvugt(ctx, lhs, rhs)); 174 | } 175 | 176 | SMTExpr SMTSolver::bvuge(SMTExpr lhs_, SMTExpr rhs_) { 177 | return bool2bv(Z3_mk_bvuge(ctx, lhs, rhs)); 178 | } 179 | 180 | SMTExpr SMTSolver::extract(unsigned high, unsigned low, SMTExpr e_) { 181 | return Z3_mk_extract(ctx, high, low, e); 182 | } 183 | 184 | SMTExpr SMTSolver::zero_extend(unsigned i, SMTExpr e_) { 185 | return Z3_mk_zero_ext(ctx, i, e); 186 | } 187 | 188 | SMTExpr SMTSolver::sign_extend(unsigned i, SMTExpr e_) { 189 | return Z3_mk_sign_ext(ctx, i, e); 190 | } 191 | 192 | SMTExpr SMTSolver::bvredand(SMTExpr e_) { 193 | return Z3_mk_bvredand(ctx, e); 194 | } 195 | 196 | SMTExpr SMTSolver::bvredor(SMTExpr e_) { 197 | return Z3_mk_bvredor(ctx, e); 198 | } 199 | 200 | SMTExpr SMTSolver::bvnot(SMTExpr e_) { 201 | return Z3_mk_bvnot(ctx, e); 202 | } 203 | 204 | SMTExpr SMTSolver::bvneg(SMTExpr e_) { 205 | return Z3_mk_bvneg(ctx, e); 206 | } 207 | 208 | SMTExpr SMTSolver::bvadd(SMTExpr lhs_, SMTExpr rhs_) { 209 | return Z3_mk_bvadd(ctx, lhs, rhs); 210 | } 211 | 212 | SMTExpr SMTSolver::bvsub(SMTExpr lhs_, SMTExpr rhs_) { 213 | return Z3_mk_bvsub(ctx, lhs, rhs); 214 | } 215 | 216 | SMTExpr SMTSolver::bvmul(SMTExpr lhs_, SMTExpr rhs_) { 217 | return Z3_mk_bvmul(ctx, lhs, rhs); 218 | } 219 | 220 | SMTExpr SMTSolver::bvsdiv(SMTExpr lhs_, SMTExpr rhs_) { 221 | return Z3_mk_bvsdiv(ctx, lhs, rhs); 222 | } 223 | 224 | SMTExpr SMTSolver::bvudiv(SMTExpr lhs_, SMTExpr rhs_) { 225 | return Z3_mk_bvudiv(ctx, lhs, rhs); 226 | } 227 | 228 | SMTExpr SMTSolver::bvsrem(SMTExpr lhs_, SMTExpr rhs_) { 229 | return Z3_mk_bvsrem(ctx, lhs, rhs); 230 | } 231 | 232 | SMTExpr SMTSolver::bvurem(SMTExpr lhs_, SMTExpr rhs_) { 233 | return Z3_mk_bvurem(ctx, lhs, rhs); 234 | } 235 | 236 | SMTExpr SMTSolver::bvshl(SMTExpr lhs_, SMTExpr rhs_) { 237 | return Z3_mk_bvshl(ctx, lhs, rhs); 238 | } 239 | 240 | SMTExpr SMTSolver::bvlshr(SMTExpr lhs_, SMTExpr rhs_) { 241 | return Z3_mk_bvlshr(ctx, lhs, rhs); 242 | } 243 | 244 | SMTExpr SMTSolver::bvashr(SMTExpr lhs_, SMTExpr rhs_) { 245 | return Z3_mk_bvashr(ctx, lhs, rhs); 246 | } 247 | 248 | SMTExpr SMTSolver::bvand(SMTExpr lhs_, SMTExpr rhs_) { 249 | return Z3_mk_bvand(ctx, lhs, rhs); 250 | } 251 | 252 | SMTExpr SMTSolver::bvor(SMTExpr lhs_, SMTExpr rhs_) { 253 | return Z3_mk_bvor(ctx, lhs, rhs); 254 | } 255 | 256 | SMTExpr SMTSolver::bvxor(SMTExpr lhs_, SMTExpr rhs_) { 257 | return Z3_mk_bvxor(ctx, lhs, rhs); 258 | } 259 | 260 | SMTExpr SMTSolver::bvneg_overflow(SMTExpr e_) { 261 | return bvnot(bool2bv(Z3_mk_bvneg_no_overflow(ctx, e))); 262 | } 263 | 264 | SMTExpr SMTSolver::bvsadd_overflow(SMTExpr lhs_, SMTExpr rhs_) { 265 | return bvor( 266 | bvnot(bool2bv(Z3_mk_bvadd_no_overflow(ctx, lhs, rhs, Z3_TRUE))), 267 | bvnot(bool2bv(Z3_mk_bvadd_no_underflow(ctx, lhs, rhs))) 268 | ); 269 | } 270 | 271 | SMTExpr SMTSolver::bvuadd_overflow(SMTExpr lhs_, SMTExpr rhs_) { 272 | return bvnot(bool2bv(Z3_mk_bvadd_no_overflow(ctx, lhs, rhs, Z3_FALSE))); 273 | } 274 | 275 | SMTExpr SMTSolver::bvssub_overflow(SMTExpr lhs_, SMTExpr rhs_) { 276 | return bvor( 277 | bvnot(bool2bv(Z3_mk_bvsub_no_overflow(ctx, lhs, rhs))), 278 | bvnot(bool2bv(Z3_mk_bvsub_no_underflow(ctx, lhs, rhs, Z3_TRUE))) 279 | ); 280 | } 281 | 282 | SMTExpr SMTSolver::bvusub_overflow(SMTExpr lhs_, SMTExpr rhs_) { 283 | return bvnot(bool2bv(Z3_mk_bvsub_no_underflow(ctx, lhs, rhs, Z3_FALSE))); 284 | } 285 | 286 | SMTExpr SMTSolver::bvsmul_overflow(SMTExpr lhs_, SMTExpr rhs_) { 287 | return bvor( 288 | bvnot(bool2bv(Z3_mk_bvmul_no_overflow(ctx, lhs, rhs, Z3_TRUE))), 289 | bvnot(bool2bv(Z3_mk_bvmul_no_underflow(ctx, lhs, rhs))) 290 | ); 291 | } 292 | 293 | SMTExpr SMTSolver::bvumul_overflow(SMTExpr lhs_, SMTExpr rhs_) { 294 | return bvnot(bool2bv(Z3_mk_bvmul_no_overflow(ctx, lhs, rhs, Z3_FALSE))); 295 | } 296 | 297 | SMTExpr SMTSolver::bvsdiv_overflow(SMTExpr lhs_, SMTExpr rhs_) { 298 | return bvnot(bool2bv(Z3_mk_bvsdiv_no_overflow(ctx, lhs, rhs))); 299 | } 300 | -------------------------------------------------------------------------------- /src/Taint.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "Annotation.h" 14 | #include "IntGlobal.h" 15 | 16 | using namespace llvm; 17 | 18 | #define TM (Ctx->Taints) 19 | 20 | static inline StringRef asString(MDNode *MD) { 21 | if (MDString *S = dyn_cast_or_null(MD->getOperand(0))) 22 | return S->getString(); 23 | return ""; 24 | } 25 | 26 | static inline MDString *toMDString(LLVMContext &VMCtx, DescSet *D) { 27 | std::string s; 28 | for (DescSet::iterator i = D->begin(), e = D->end(); i != e; ++i) { 29 | if (i != D->begin()) 30 | s += ", "; 31 | s += (*i).str(); 32 | } 33 | return MDString::get(VMCtx, s); 34 | } 35 | 36 | // Check both local taint and global sources 37 | DescSet * TaintPass::getTaint(Value *V) { 38 | if (DescSet *DS = TM.get(V)) 39 | return DS; 40 | if (DescSet *DS = TM.get(V->stripPointerCasts())) 41 | return DS; 42 | 43 | // if value is not taint, check global taint. 44 | // For call, taint if any possible callee could return taint 45 | if (CallInst *CI = dyn_cast(V)) { 46 | if (!CI->isInlineAsm() && Ctx->Callees.count(CI)) { 47 | FuncSet &CEEs = Ctx->Callees[CI]; 48 | for (FuncSet::iterator i = CEEs.begin(), e = CEEs.end(); 49 | i != e; ++i) { 50 | if (DescSet *DS = TM.get(getRetId(*i))) 51 | TM.add(CI, *DS); 52 | } 53 | } 54 | } 55 | // For arguments and loads 56 | if (DescSet *DS = TM.get(getValueId(V))) 57 | TM.add(V, *DS); 58 | return TM.get(V); 59 | } 60 | 61 | bool TaintPass::isTaintSource(const std::string &sID) { 62 | return TM.isSource(sID); 63 | } 64 | 65 | // find and mark taint source 66 | bool TaintPass::checkTaintSource(Instruction *I) 67 | { 68 | Module *M = I->getParent()->getParent()->getParent(); 69 | bool changed = false; 70 | 71 | if (MDNode *MD = I->getMetadata(MD_TaintSrc)) { 72 | TM.add(I, asString(MD)); 73 | DescSet &D = *TM.get(I); 74 | changed |= TM.add(getValueId(I), D, true); 75 | // mark all struct members as taint 76 | if (PointerType *PTy = dyn_cast(I->getType())) { 77 | if (StructType *STy = dyn_cast(PTy->getElementType())) { 78 | for (unsigned i = 0; i < STy->getNumElements(); ++i) 79 | changed |= TM.add(getStructId(STy, M, i), D, true); 80 | } 81 | } 82 | } 83 | return changed; 84 | } 85 | 86 | // Propagate taint within a function 87 | bool TaintPass::runOnFunction(Function *F) 88 | { 89 | bool changed = false; 90 | 91 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 92 | Instruction *I = &*i; 93 | 94 | // find and mark taint sources 95 | changed |= checkTaintSource(I); 96 | 97 | // for call instruction, propagate taint to arguments instead 98 | // of from arguments 99 | if (CallInst *CI = dyn_cast(I)) { 100 | if (CI->isInlineAsm() || !Ctx->Callees.count(CI)) 101 | continue; 102 | 103 | FuncSet &CEEs = Ctx->Callees[CI]; 104 | for (FuncSet::iterator j = CEEs.begin(), je = CEEs.end(); 105 | j != je; ++j) { 106 | // skip vaarg and builtin functions 107 | if ((*j)->isVarArg() 108 | || (*j)->getName().find('.') != StringRef::npos) 109 | continue; 110 | 111 | // mark corresponding args tainted on all possible callees 112 | for (unsigned a = 0; a < CI->getNumArgOperands(); ++a) { 113 | if (DescSet *DS = getTaint(CI->getArgOperand(a))) 114 | changed |= TM.add(getArgId(*j, a), *DS); 115 | } 116 | } 117 | continue; 118 | } 119 | 120 | // check if any operand is taint 121 | DescSet D; 122 | for (unsigned j = 0; j < I->getNumOperands(); ++j) 123 | if (DescSet *DS = getTaint(I->getOperand(j))) 124 | D.insert(DS->begin(), DS->end()); 125 | if (D.empty()) 126 | continue; 127 | 128 | // propagate value and global taint 129 | TM.add(I, D); 130 | if (StoreInst *SI = dyn_cast(I)) { 131 | if (MDNode *ID = SI->getMetadata(MD_ID)) 132 | changed |= TM.add(asString(ID), D); 133 | } else if (isa(I)) { 134 | changed |= TM.add(getRetId(F), D); 135 | } 136 | } 137 | return changed; 138 | } 139 | 140 | // write back 141 | bool TaintPass::doFinalization(Module *M) { 142 | LLVMContext &VMCtx = M->getContext(); 143 | for (Module::iterator f = M->begin(), fe = M->end(); f != fe; ++f) { 144 | Function *F = &*f; 145 | for (inst_iterator i = inst_begin(F), e = inst_end(F); i != e; ++i) { 146 | Instruction *I = &*i; 147 | if (DescSet *DS = getTaint(I)) { 148 | MDNode *MD = MDNode::get(VMCtx, toMDString(VMCtx, DS)); 149 | I->setMetadata(MD_Taint, MD); 150 | } else 151 | I->setMetadata(MD_Taint, NULL); 152 | } 153 | } 154 | return true; 155 | } 156 | 157 | bool TaintPass::doModulePass(Module *M) { 158 | bool changed = true, ret = false; 159 | 160 | while (changed) { 161 | changed = false; 162 | for (Module::iterator i = M->begin(), e = M->end(); i != e; ++i) 163 | changed |= runOnFunction(&*i); 164 | ret |= changed; 165 | } 166 | return ret; 167 | } 168 | 169 | // debug 170 | void TaintPass::dumpTaints() { 171 | raw_ostream &OS = dbgs(); 172 | for (TaintMap::GlobalMap::iterator i = TM.GTS.begin(), 173 | e = TM.GTS.end(); i != e; ++i) { 174 | OS << (i->second.second ? "S " : " ") << i->first << "\t"; 175 | for (DescSet::iterator j = i->second.first.begin(), 176 | je = i->second.first.end(); j != je; ++j) 177 | OS << *j << " "; 178 | OS << "\n"; 179 | } 180 | } 181 | 182 | #undef TM 183 | -------------------------------------------------------------------------------- /src/ValueGen.cc: -------------------------------------------------------------------------------- 1 | #include "ValueGen.h" 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | using namespace llvm; 13 | 14 | static void addRangeConstraints(SMTSolver &, SMTExpr, MDNode *); 15 | 16 | namespace { 17 | 18 | #define SMT VG.SMT 19 | #define TD VG.TD 20 | 21 | struct ValueVisitor : InstVisitor { 22 | ValueVisitor(ValueGen &VG) 23 | : VG(VG) {} 24 | 25 | SMTExpr analyze(Value *V) { 26 | if (!ValueGen::isAnalyzable(V)) { 27 | V->dump(); 28 | assert(0 && "Unknown type!"); 29 | } 30 | if (Instruction *I = dyn_cast(V)) 31 | return visit(I); 32 | else if (Constant *C = dyn_cast(V)) 33 | return visitConstant(C); 34 | return mk_fresh(V); 35 | } 36 | 37 | SMTExpr visitInstruction(Instruction &I) { 38 | SMTExpr E = mk_fresh(&I); 39 | // Ranges are constants, so don't worry about recursion. 40 | if (MDNode *MD = I.getMetadata("intrange")) 41 | addRangeConstraints(SMT, E, MD); 42 | return E; 43 | } 44 | 45 | SMTExpr visitConstant(Constant *C) { 46 | if (ConstantInt *CI = dyn_cast(C)) 47 | return SMT.bvconst(CI->getValue()); 48 | if (isa(C)) 49 | return SMT.bvconst(APInt::getNullValue(getBitWidth(C))); 50 | if (GEPOperator *GEP = dyn_cast(C)) 51 | return visitGEPOperator(*GEP); 52 | return mk_fresh(C); 53 | } 54 | 55 | SMTExpr visitTruncInst(TruncInst &I) { 56 | unsigned DstWidth = getBitWidth(I.getDestTy()); 57 | return SMT.extract(DstWidth - 1, 0, get(I.getOperand(0))); 58 | } 59 | 60 | SMTExpr visitZExtInst(ZExtInst &I) { 61 | unsigned DstWidth = getBitWidth(I.getDestTy()); 62 | unsigned SrcWidth = getBitWidth(I.getSrcTy()); 63 | return SMT.zero_extend(DstWidth - SrcWidth, get(I.getOperand(0))); 64 | } 65 | 66 | SMTExpr visitSExtInst(SExtInst &I) { 67 | unsigned DstWidth = getBitWidth(I.getDestTy()); 68 | unsigned SrcWidth = getBitWidth(I.getSrcTy()); 69 | return SMT.sign_extend(DstWidth - SrcWidth, get(I.getOperand(0))); 70 | } 71 | 72 | SMTExpr visitBinaryOperator(BinaryOperator &I) { 73 | SMTExpr L = get(I.getOperand(0)), R = get(I.getOperand(1)); 74 | switch (I.getOpcode()) { 75 | default: assert(0); 76 | case Instruction::Add: return SMT.bvadd(L, R); 77 | case Instruction::Sub: return SMT.bvsub(L, R); 78 | case Instruction::Mul: return SMT.bvmul(L, R); 79 | case Instruction::UDiv: return SMT.bvudiv(L, R); 80 | case Instruction::SDiv: return SMT.bvsdiv(L, R); 81 | case Instruction::URem: return SMT.bvurem(L, R); 82 | case Instruction::SRem: return SMT.bvsrem(L, R); 83 | case Instruction::Shl: return SMT.bvshl(L, R); 84 | case Instruction::LShr: return SMT.bvlshr(L, R); 85 | case Instruction::AShr: return SMT.bvashr(L, R); 86 | case Instruction::And: return SMT.bvand(L, R); 87 | case Instruction::Or: return SMT.bvor(L, R); 88 | case Instruction::Xor: return SMT.bvxor(L, R); 89 | } 90 | } 91 | 92 | SMTExpr visitICmpInst(ICmpInst &I) { 93 | SMTExpr L = get(I.getOperand(0)), R = get(I.getOperand(1)); 94 | switch (I.getPredicate()) { 95 | default: assert(0); 96 | case CmpInst::ICMP_EQ: return SMT.eq(L, R); break; 97 | case CmpInst::ICMP_NE: return SMT.ne(L, R); break; 98 | case CmpInst::ICMP_SGE: return SMT.bvsge(L, R); break; 99 | case CmpInst::ICMP_SGT: return SMT.bvsgt(L, R); break; 100 | case CmpInst::ICMP_SLE: return SMT.bvsle(L, R); break; 101 | case CmpInst::ICMP_SLT: return SMT.bvslt(L, R); break; 102 | case CmpInst::ICMP_UGE: return SMT.bvuge(L, R); break; 103 | case CmpInst::ICMP_UGT: return SMT.bvugt(L, R); break; 104 | case CmpInst::ICMP_ULE: return SMT.bvule(L, R); break; 105 | case CmpInst::ICMP_ULT: return SMT.bvult(L, R); break; 106 | } 107 | } 108 | 109 | SMTExpr visitSelectInst(SelectInst &I) { 110 | return SMT.ite( 111 | get(I.getCondition()), 112 | get(I.getTrueValue()), 113 | get(I.getFalseValue()) 114 | ); 115 | } 116 | 117 | SMTExpr visitExtractValueInst(ExtractValueInst &I) { 118 | IntrinsicInst *II = dyn_cast(I.getAggregateOperand()); 119 | if (!II || II->getCalledFunction()->getName().find(".with.overflow.") 120 | == StringRef::npos) 121 | return mk_fresh(&I); 122 | SMTExpr L = get(II->getArgOperand(0)); 123 | SMTExpr R = get(II->getArgOperand(1)); 124 | assert(I.getNumIndices() == 1); 125 | switch (I.getIndices()[0]) { 126 | default: II->dump(); assert(0 && "Unknown overflow!"); 127 | case 0: 128 | switch (II->getIntrinsicID()) { 129 | default: II->dump(); assert(0 && "Unknown overflow!"); 130 | case Intrinsic::sadd_with_overflow: 131 | case Intrinsic::uadd_with_overflow: 132 | return SMT.bvadd(L, R); 133 | case Intrinsic::ssub_with_overflow: 134 | case Intrinsic::usub_with_overflow: 135 | return SMT.bvsub(L, R); 136 | case Intrinsic::smul_with_overflow: 137 | case Intrinsic::umul_with_overflow: 138 | return SMT.bvmul(L, R); 139 | } 140 | case 1: 141 | switch (II->getIntrinsicID()) { 142 | default: II->dump(); assert(0 && "Unknown overflow!"); 143 | case Intrinsic::sadd_with_overflow: 144 | return SMT.bvsadd_overflow(L, R); 145 | case Intrinsic::uadd_with_overflow: 146 | return SMT.bvuadd_overflow(L, R); 147 | case Intrinsic::ssub_with_overflow: 148 | return SMT.bvssub_overflow(L, R); 149 | case Intrinsic::usub_with_overflow: 150 | return SMT.bvusub_overflow(L, R); 151 | case Intrinsic::smul_with_overflow: 152 | return SMT.bvsmul_overflow(L, R); 153 | case Intrinsic::umul_with_overflow: 154 | return SMT.bvumul_overflow(L, R); 155 | } 156 | } 157 | assert(I.getIndices()[0] == 1 && "FIXME!"); 158 | 159 | } 160 | 161 | SMTExpr visitGetElementPtrInst(GetElementPtrInst &I) { 162 | return visitGEPOperator(cast(I)); 163 | } 164 | 165 | SMTExpr visitGEPOperator(GEPOperator &GEP) { 166 | unsigned PtrSize = TD.getPointerSizeInBits(/*GEP.getPointerAddressSpace()*/); 167 | // Start from base. 168 | SMTExpr Offset = get(GEP.getPointerOperand()); 169 | // Increase refcnt. 170 | SMT.incref(Offset); 171 | APInt ConstOffset = APInt::getNullValue(PtrSize); 172 | 173 | gep_type_iterator GTI = gep_type_begin(GEP); 174 | for (GEPOperator::op_iterator i = GEP.idx_begin(), 175 | e = GEP.idx_end(); i != e; ++i, ++GTI) { 176 | Value *V = *i; 177 | // Skip zero index. 178 | ConstantInt *C = dyn_cast(V); 179 | if (C && C->isZero()) 180 | continue; 181 | // For a struct, add the member offset. 182 | if (StructType *ST = dyn_cast(*GTI)) { 183 | assert(C); 184 | unsigned FieldNo = C->getZExtValue(); 185 | ConstOffset = ConstOffset + TD.getStructLayout(ST)->getElementOffset(FieldNo); 186 | continue; 187 | } 188 | // For an array, add the scaled element offset. 189 | APInt ElemSize(PtrSize, TD.getTypeAllocSize(GTI.getIndexedType())); 190 | if (C) { 191 | // GEP index can be sign-extended. 192 | ConstOffset += ElemSize * C->getValue().sextOrTrunc(PtrSize); 193 | continue; 194 | } 195 | SMTExpr SIdx = get(V); 196 | unsigned IdxSize = SMT.bvwidth(SIdx); 197 | // Sometimes a 64-bit GEP's index is 32-bit. 198 | if (IdxSize != PtrSize) { 199 | SMTExpr Tmp; 200 | if (IdxSize < PtrSize) 201 | Tmp = SMT.sign_extend(PtrSize - IdxSize, SIdx); 202 | else 203 | Tmp = SMT.extract(PtrSize - 1, 0, SIdx); 204 | SIdx = Tmp; 205 | } else { 206 | SMT.incref(SIdx); 207 | } 208 | SMTExpr SElemSize = SMT.bvconst(ElemSize); 209 | SMTExpr LocalOffset = SMT.bvmul(SIdx, SElemSize); 210 | SMTExpr Tmp = SMT.bvadd(Offset, LocalOffset); 211 | SMT.decref(SIdx); 212 | SMT.decref(SElemSize); 213 | SMT.decref(Offset); 214 | SMT.decref(LocalOffset); 215 | Offset = Tmp; 216 | } 217 | 218 | if (!ConstOffset) 219 | return Offset; 220 | 221 | // Merge constant offset. 222 | SMTExpr SConstOffset = SMT.bvconst(ConstOffset); 223 | SMTExpr Tmp = SMT.bvadd(Offset, SConstOffset); 224 | SMT.decref(Offset); 225 | SMT.decref(SConstOffset); 226 | return Tmp; 227 | } 228 | 229 | SMTExpr visitBitCastInst(BitCastInst &I) { 230 | Value *V = I.getOperand(0); 231 | // V can be floating point. 232 | if (!VG.isAnalyzable(V)) 233 | return mk_fresh(&I); 234 | SMTExpr E = get(V); 235 | SMT.incref(E); 236 | return E; 237 | } 238 | 239 | SMTExpr visitPtrToIntInst(PtrToIntInst &I) { 240 | Value *V = I.getOperand(0); 241 | SMTExpr E = get(V); 242 | unsigned PtrSize = getBitWidth(V); 243 | unsigned IntSize = getBitWidth(&I); 244 | if (IntSize > PtrSize) 245 | return SMT.zero_extend(IntSize - PtrSize, E); 246 | if (IntSize < PtrSize) 247 | return SMT.extract(IntSize - 1, 0, E); 248 | // IntSize == PtrSize. 249 | SMT.incref(E); 250 | return E; 251 | } 252 | 253 | private: 254 | ValueGen &VG; 255 | 256 | SMTExpr get(Value *V) { 257 | return VG.get(V); 258 | } 259 | 260 | unsigned getBitWidth(Type *T) const { 261 | return TD.getTypeSizeInBits(T); 262 | } 263 | 264 | unsigned getBitWidth(Value *V) const { 265 | return getBitWidth(V->getType()); 266 | } 267 | 268 | SMTExpr mk_fresh(Value *V) { 269 | std::string Name; 270 | { 271 | raw_string_ostream OS(Name); 272 | WriteAsOperand(OS, V, false); 273 | // Make name unique, e.g., undef. 274 | OS << "@" << V; 275 | } 276 | return SMT.bvvar(getBitWidth(V), Name.c_str()); 277 | } 278 | 279 | }; 280 | 281 | #undef SMT 282 | #undef TD 283 | 284 | } // anonymous namespace 285 | 286 | ValueGen::ValueGen(DataLayout &TD, SMTSolver &SMT) 287 | : TD(TD), SMT(SMT) {} 288 | 289 | ValueGen::~ValueGen() { 290 | for (iterator i = Cache.begin(), e = Cache.end(); i != e; ++i) 291 | SMT.decref(i->second); 292 | } 293 | 294 | bool ValueGen::isAnalyzable(Value *V) { 295 | return isAnalyzable(V->getType()); 296 | } 297 | 298 | bool ValueGen::isAnalyzable(Type *T) { 299 | return T->isIntegerTy() 300 | || T->isPointerTy() 301 | || T->isFunctionTy(); 302 | } 303 | 304 | SMTExpr ValueGen::get(Value *V) { 305 | // Don't use something like 306 | // SMTExpr &E = ValueCache[S] 307 | // to update (S, E). During visit the location may become invalid. 308 | SMTExpr E = Cache.lookup(V); 309 | if (!E) { 310 | E = ValueVisitor(*this).analyze(V); 311 | Cache[V] = E; 312 | } 313 | assert(E); 314 | return E; 315 | } 316 | 317 | void addRangeConstraints(SMTSolver &SMT, SMTExpr E, MDNode *MD) { 318 | // !range comes in pairs. 319 | unsigned n = MD->getNumOperands(); 320 | assert(n % 2 == 0); 321 | for (unsigned i = 0; i != n; i += 2) { 322 | const APInt &Lo = cast(MD->getOperand(i))->getValue(); 323 | const APInt &Hi = cast(MD->getOperand(i + 1))->getValue(); 324 | // Ignore empty or full set. 325 | if (Lo == Hi) 326 | continue; 327 | SMTExpr Cmp0 = NULL, Cmp1 = NULL, Cond; 328 | // Ignore >= 0. 329 | if (!!Lo) { 330 | SMTExpr Tmp = SMT.bvconst(Lo); 331 | Cmp0 = SMT.bvuge(E, Tmp); 332 | SMT.decref(Tmp); 333 | } 334 | // Note that (< Hi) is not always correct. Need to 335 | // ignore Hi == 0 (i.e., <= UMAX) or use (<= Hi - 1). 336 | if (!!Hi) { 337 | SMTExpr Tmp = SMT.bvconst(Hi); 338 | Cmp1 = SMT.bvult(E, Tmp); 339 | SMT.decref(Tmp); 340 | } 341 | if (!Cmp0) { 342 | Cond = Cmp1; 343 | } else if (!Cmp1) { 344 | Cond = Cmp0; 345 | } else { 346 | if (Lo.ule(Hi)) // [Lo, Hi). 347 | Cond = SMT.bvand(Cmp0, Cmp1); 348 | else // Wrap: [Lo, UMAX] union [0, Hi). 349 | Cond = SMT.bvor(Cmp0, Cmp1); 350 | SMT.decref(Cmp0); 351 | SMT.decref(Cmp1); 352 | } 353 | SMT.assume(Cond); 354 | SMT.decref(Cond); 355 | } 356 | } 357 | -------------------------------------------------------------------------------- /src/ValueGen.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | #include 5 | #include "SMTSolver.h" 6 | 7 | class ValueGen { 8 | public: 9 | llvm::DataLayout &TD; 10 | SMTSolver &SMT; 11 | 12 | typedef llvm::DenseMap ValueExprMap; 13 | typedef ValueExprMap::iterator iterator; 14 | ValueExprMap Cache; 15 | 16 | ValueGen(llvm::DataLayout &, SMTSolver &); 17 | ~ValueGen(); 18 | 19 | static bool isAnalyzable(llvm::Value *); 20 | static bool isAnalyzable(llvm::Type *); 21 | SMTExpr get(llvm::Value *); 22 | 23 | iterator begin() { return Cache.begin(); } 24 | iterator end() { return Cache.end(); } 25 | }; 26 | -------------------------------------------------------------------------------- /src/cmpck: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$(dirname "${BASH_SOURCE[0]}") 4 | OPT="`llvm-config --bindir`/opt" 5 | exec ${OPT} -disable-output -load=${DIR}/../lib/libcmpck.so \ 6 | -cmp-tautology $@ 2>&1 7 | -------------------------------------------------------------------------------- /src/intck: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$(dirname "${BASH_SOURCE[0]}") 4 | OPT="`llvm-config --bindir`/opt" 5 | exec ${OPT} -disable-output -load=${DIR}/../lib/libintck.so \ 6 | -targetlibinfo -tbaa -basicaa -globalopt -ipsccp -deadargelim \ 7 | -simplifycfg -basiccg -prune-eh -inline -functionattrs -argpromotion \ 8 | -scalarrepl-ssa -early-cse -simplify-libcalls -lazy-value-info \ 9 | -jump-threading -correlated-propagation -simplifycfg \ 10 | -strip-dead-prototypes -globaldce -constmerge \ 11 | -overflow-idiom -adce -simplifycfg \ 12 | -int-rewrite -overflow-simplify -int-libcalls \ 13 | -std-compile-opts \ 14 | -overflow-simplify -adce -simplifycfg \ 15 | -load-rewrite \ 16 | -O2 \ 17 | -int-sat $@ 2>&1 18 | -------------------------------------------------------------------------------- /src/llvm/DataLayout.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 2 6 | #include 7 | #define DataLayout TargetData 8 | #define initializeDataLayoutPass initializeTargetDataPass 9 | #else 10 | #include_next 11 | #endif 12 | -------------------------------------------------------------------------------- /src/llvm/DebugInfo.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 2 6 | #include 7 | #else 8 | #include_next 9 | #endif 10 | -------------------------------------------------------------------------------- /src/llvm/IRBuilder.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 2 6 | #include 7 | #else 8 | #include_next 9 | #endif 10 | -------------------------------------------------------------------------------- /src/llvm/InstVisitor.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #include 4 | 5 | #if LLVM_VERSION_MAJOR == 3 && LLVM_VERSION_MINOR < 3 6 | #include 7 | #else 8 | #include_next 9 | #endif 10 | -------------------------------------------------------------------------------- /src/ncpu: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import multiprocessing 4 | 5 | print(multiprocessing.cpu_count()) 6 | -------------------------------------------------------------------------------- /src/pcmpck: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$(dirname "${BASH_SOURCE[0]}") 4 | NCPU=`${DIR}/ncpu` 5 | OUT='pcmpck.txt' 6 | TIMEOUT=500 7 | find . -name '*.ll' -type f -print0 | xargs -0 -P ${NCPU} -I{} -t bash -c "${DIR}/cmpck -smt-timeout=${TIMEOUT} '{}' > '{}.out'" 8 | rm -f ${OUT} 9 | find . -name '*.ll.out' -type f -print0 | xargs -0 -I{} bash -c "cat '{}' >> ${OUT}" 10 | -------------------------------------------------------------------------------- /src/pintck: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$(dirname "${BASH_SOURCE[0]}") 4 | NCPU=`${DIR}/ncpu` 5 | OUT='pintck.txt' 6 | TIMEOUT=500 7 | find . -name '*.ll' -type f -print0 | xargs -0 -P ${NCPU} -I{} -t bash -c "${DIR}/intck -smt-timeout=${TIMEOUT} '{}' > '{}.out'" 8 | rm -f ${OUT} 9 | find . -name '*.ll.out' -type f -print0 | xargs -0 -I{} bash -c "cat '{}' >> ${OUT}" 10 | -------------------------------------------------------------------------------- /test/Makefile.am: -------------------------------------------------------------------------------- 1 | EXTRA_DIST = lit.cfg.in kint-cc1 kint-gcc kint-g++ diagdiff 2 | 3 | LITFLAGS ?= -v 4 | LITTESTS ?= $(builddir) 5 | check-local: lit.cfg 6 | @`llvm-config --src-root`/utils/lit/lit.py $(LITFLAGS) $(LITTESTS) 7 | -------------------------------------------------------------------------------- /test/cmp/nouveau_dp.c: -------------------------------------------------------------------------------- 1 | // RUN: %cc %s | cmpck | diagdiff %s 2 | // http://git.kernel.org/linus/44ab8cc56c45ca781371a4a77f35da19cf5db028 3 | 4 | #define DP_TRAIN_PRE_EMPHASIS_9_5 (3 << 3) 5 | #define DP_TRAIN_VOLTAGE_SWING_1200 (3 << 0) 6 | 7 | typedef unsigned char u8; 8 | 9 | int foo(u8 lane) 10 | { 11 | u8 lpre = (lane & 0x0c) >> 2; 12 | u8 lvsw = (lane & 0x03) >> 0; 13 | if (lpre == DP_TRAIN_PRE_EMPHASIS_9_5) // CHECK: {{comparison always false}} 14 | return -1; 15 | if ((lpre << 3) == DP_TRAIN_PRE_EMPHASIS_9_5) 16 | return -2; 17 | if (lvsw == DP_TRAIN_VOLTAGE_SWING_1200) 18 | return -3; 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /test/cmp/pch_can.c: -------------------------------------------------------------------------------- 1 | // RUN: %cc %s | cmpck | diagdiff %s 2 | // http://git.kernel.org/linus/44b0052c5cb4e75389ed3eb9e98c29295a7dadfb 3 | 4 | #define BIT(n) (1UL << (n)) 5 | 6 | #define PCH_EPASSIVE BIT(5) 7 | #define PCH_EWARN BIT(6) 8 | 9 | #define PCH_REC 0x00007f00 10 | #define PCH_TEC 0x000000ff 11 | 12 | typedef unsigned int u32; 13 | 14 | int foo(u32 status, u32 errc) 15 | { 16 | if (status & PCH_EWARN) { 17 | if (((errc & PCH_REC) >> 8) > 96) 18 | return -1; 19 | if ((errc & PCH_TEC) > 96) 20 | return -2; 21 | } 22 | if (status & PCH_EPASSIVE) { 23 | if (((errc & PCH_REC) >> 8) > 127) // CHECK: {{comparison always false}} 24 | return -3; 25 | if ((errc & PCH_TEC) > 127) 26 | return -4; 27 | } 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /test/diagdiff: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env ruby 2 | 3 | require 'getoptlong' 4 | require 'set' 5 | require 'yaml' 6 | 7 | opts = GetoptLong.new( 8 | ['--prefix', GetoptLong::REQUIRED_ARGUMENT] 9 | ) 10 | 11 | prefix = 'CHECK' 12 | opts.each do |opt, arg| 13 | case opt 14 | when '--prefix' 15 | prefix = arg 16 | end 17 | end 18 | 19 | # extract expected output 20 | exp = Set.new 21 | lineno = 1 22 | file = ARGV.shift 23 | path = File.expand_path file 24 | File.open(file).each_line do |line| 25 | if /\/\/\s*#{prefix}:(.*)$/ =~ line 26 | $~[1].scan(/\{\{([^\}]+)\}\}/) do |bug| 27 | exp << [file, lineno, bug[0]] 28 | end 29 | end 30 | # bump lineno if not ending with a backslash 31 | lineno = $. + 1 if not /\\\s*$/ =~ line 32 | end 33 | 34 | # parse actual output 35 | act = Set.new 36 | docs = YAML.load_stream STDIN 37 | docs.each do |doc| 38 | next if doc['status'] == 'unsat' 39 | act_file, act_lineno = doc['stack'][0].split(':')[0, 2] 40 | act_file = file if path == act_file 41 | act_lineno = Integer act_lineno 42 | act << [act_file, act_lineno, doc['bug']] 43 | end 44 | 45 | exit 0 if exp == act 46 | 47 | # missing 48 | (exp - act).each { |e| puts "- #{e.join(':')}" } 49 | 50 | # superfluous 51 | (act - exp).each { |e| puts "+ #{e.join(':')}" } 52 | 53 | exit 1 54 | -------------------------------------------------------------------------------- /test/int/camel-2005-0102.c: -------------------------------------------------------------------------------- 1 | // RUN: %cc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %cc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %cc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %cc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // 6 | // http://git.gnome.org/browse/evolution-data-server/commit/camel/camel-lock-helper.c?id=0d1d403fab78b869867d50fcc6ee95f503925318 7 | 8 | #include 9 | #include 10 | #include 11 | 12 | typedef unsigned int guint32; 13 | typedef int gint; 14 | typedef char gchar; 15 | 16 | struct _CamelLockHelperMsg { 17 | guint32 magic; 18 | guint32 seq; 19 | guint32 id; 20 | guint32 data; 21 | }; 22 | 23 | /* magic values */ 24 | enum { 25 | CAMEL_LOCK_HELPER_MAGIC = 0xABADF00D, 26 | }; 27 | 28 | /* return status */ 29 | enum { 30 | CAMEL_LOCK_HELPER_STATUS_OK = 0, 31 | CAMEL_LOCK_HELPER_STATUS_PROTOCOL, 32 | CAMEL_LOCK_HELPER_STATUS_NOMEM, 33 | }; 34 | 35 | /* commands */ 36 | enum { 37 | CAMEL_LOCK_HELPER_LOCK = 0xf0f, 38 | CAMEL_LOCK_HELPER_UNLOCK = 0xf0f0 39 | }; 40 | 41 | int read_n(int fd, void *buf, size_t len); 42 | 43 | gint lock_path (const gchar *path, guint32 *lockid); 44 | 45 | int main() 46 | { 47 | struct _CamelLockHelperMsg msg; 48 | gint len; 49 | gint res; 50 | gchar *path; 51 | 52 | len = read_n(STDIN_FILENO, &msg, sizeof(msg)); 53 | if (len == 0) 54 | return 0; 55 | 56 | res = CAMEL_LOCK_HELPER_STATUS_PROTOCOL; 57 | if (len == sizeof (msg) && msg.magic == CAMEL_LOCK_HELPER_MAGIC) { 58 | switch(msg.id) { 59 | case CAMEL_LOCK_HELPER_LOCK: 60 | res = CAMEL_LOCK_HELPER_STATUS_NOMEM; 61 | #ifndef __PATCH__ 62 | path = malloc(msg.data+1); // exp: {{uadd}} 63 | if (path != NULL) { 64 | #else 65 | if (msg.data > 0xffff) { 66 | res = CAMEL_LOCK_HELPER_STATUS_PROTOCOL; 67 | } else if ((path = malloc(msg.data+1)) != NULL) { 68 | #endif 69 | res = CAMEL_LOCK_HELPER_STATUS_PROTOCOL; 70 | len = read_n(STDIN_FILENO, path, msg.data); 71 | if (len == msg.data) { 72 | path[len] = 0; 73 | lock_path(path, &msg.data); 74 | } 75 | free(path); 76 | } 77 | } 78 | } 79 | } -------------------------------------------------------------------------------- /test/int/chromium-gpu-117656.c: -------------------------------------------------------------------------------- 1 | // RUN: %cc %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %cc -D__PATCH__ %s | intck | diagdiff %s 3 | // http://code.google.com/p/chromium/issues/detail?id=117656 4 | 5 | #include 6 | 7 | typedef unsigned int u32; 8 | typedef unsigned int T; 9 | 10 | static u32 ComputeMaxResults(size_t size_of_buffer) { 11 | #ifndef __PATCH__ 12 | return (size_of_buffer - sizeof(u32)) / sizeof(T); // exp: {{usub}} 13 | #else 14 | return (size_of_buffer >= sizeof(u32)) ? 15 | ((size_of_buffer - sizeof(u32)) / sizeof(T)) : 0; 16 | #endif 17 | } 18 | 19 | size_t ComputeSize(size_t num_results); 20 | 21 | void *GetAddressAndCheckSize(u32); 22 | 23 | void *HandleGetAttachedShaders(u32 result_size) 24 | { 25 | u32 max_count = ComputeMaxResults(result_size); 26 | return GetAddressAndCheckSize(ComputeSize(max_count)); 27 | } 28 | -------------------------------------------------------------------------------- /test/int/gocr-2005-1141.c: -------------------------------------------------------------------------------- 1 | // RUN: %cc %s | intck | diagdiff %s --prefix=exp 2 | // 3 | // http://www.overflow.pl/adv/gocr.txt 4 | // http://jocr.cvs.sourceforge.net/viewvc/jocr/jocr/src/pnm.c?r1=1.22&r2=1.23 5 | // 6 | // The unusual fix uses floating point to detect integer overflow. 7 | // It also invokes undefined behavior (signed integer overflow). 8 | 9 | #include 10 | #include 11 | 12 | #define EE() fprintf(stderr,"\nERROR "__FILE__" L%d: ",__LINE__) 13 | #define F0(x0) {EE();fprintf(stderr,x0 "\n"); exit(1);} 14 | #define F1(x0,x1) {EE();fprintf(stderr,x0 "\n",x1); exit(1);} 15 | 16 | typedef struct pixmap { 17 | unsigned char *p; /* pointer of image buffer (pixmap) */ 18 | int x; /* xsize */ 19 | int y; /* ysize */ 20 | int bpp; /* bytes per pixel: 1=gray 3=rgb */ 21 | } pix; 22 | 23 | struct pam { 24 | int height; 25 | int width; 26 | }; 27 | 28 | void readpgm(pix *p, struct pam *inpam) 29 | { 30 | p->x = inpam->width; 31 | p->y = inpam->height; 32 | #ifdef __PATCH__ 33 | if ( (1.*(p->x*p->y))!=((1.*p->x)*p->y) ) 34 | F0("Error integer overflow"); 35 | #endif 36 | if ( !(p->p = (unsigned char *)malloc(p->x*p->y)) ) // exp: {{smul}} 37 | F1("Error at malloc: p->p: %d bytes", p->x*p->y); 38 | } 39 | -------------------------------------------------------------------------------- /test/int/linux.h: -------------------------------------------------------------------------------- 1 | ../linux/linux.h -------------------------------------------------------------------------------- /test/int/malloc_array.c: -------------------------------------------------------------------------------- 1 | // RUN: %cc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %cc -m64 %s | intck | diagdiff %s --prefix=exp 3 | 4 | #include 5 | #include 6 | 7 | void *malloc_array_nc(size_t n, size_t size) 8 | { 9 | return malloc(n * size); // exp: {{umul}} 10 | } 11 | 12 | void *malloc_array_0(size_t n, size_t size) 13 | { 14 | // need -overflow to recognize the idiom. 15 | if (size && n > SIZE_MAX / size) 16 | return NULL; 17 | return malloc(n * size); 18 | } 19 | 20 | void *malloc_array_1(size_t n, size_t size) 21 | { 22 | // swap n and size; need -overflow-simplify to merge the two 23 | // overflow builtins (OOB and path predicates). 24 | if (n && size > SIZE_MAX / n) 25 | return NULL; 26 | return malloc(n * size); 27 | } 28 | 29 | void *malloc_array_2(size_t n, size_t size) 30 | { 31 | // need -overflow to recognize the idiom. 32 | // need to sink the multiplication after the check. 33 | size_t bytes = n * size; 34 | if (size && n != bytes / size) 35 | return NULL; 36 | return malloc(bytes); 37 | } 38 | -------------------------------------------------------------------------------- /test/int/openssh-2002-0639.c: -------------------------------------------------------------------------------- 1 | // RUN: %cc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %cc -D__PATCH__ %s | intck | diagdiff %s 3 | // 4 | // http://www.openssh.com/txt/preauth.adv 5 | 6 | #include 7 | #include 8 | 9 | void fatal(const char *, ...) __attribute__((format(printf, 1, 2))) __attribute__((noreturn)); 10 | u_int packet_get_int(void); 11 | void *packet_get_string(u_int *length_ptr); 12 | void *xmalloc(size_t); 13 | 14 | char **input_userauth_info_response() 15 | { 16 | int i; 17 | u_int nresp; 18 | char **response = NULL; 19 | nresp = packet_get_int(); 20 | #ifdef __PATCH__ 21 | if (nresp > 100) 22 | fatal("input_userauth_info_response: nresp too big %u", nresp); 23 | #endif 24 | if (nresp > 0) { 25 | response = xmalloc(nresp * sizeof(char*)); // exp: {{umul}} 26 | for (i = 0; i < nresp; i++) 27 | response[i] = packet_get_string(NULL); 28 | } 29 | return response; 30 | } 31 | -------------------------------------------------------------------------------- /test/int/rpc-2002-0391.c: -------------------------------------------------------------------------------- 1 | // RUN: %cc %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %cc -D__PATCH__ %s | intck | diagdiff %s 3 | // 4 | // http://www.kb.cert.org/vuls/id/192995 5 | 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | bool_t 15 | xdr_array(XDR *xdrs, 16 | caddr_t *addrp, /* array pointer */ 17 | u_int *sizep, /* number of elements */ 18 | u_int maxsize, /* max numberof elements */ 19 | u_int elsize, /* size in bytes of each element */ 20 | xdrproc_t elproc) /* xdr routine to handle each element */ 21 | { 22 | u_int i; 23 | caddr_t target = *addrp; 24 | u_int c; /* the actual element count */ 25 | bool_t stat = TRUE; 26 | u_int nodesize; 27 | 28 | assert(elsize); 29 | /* like strings, arrays are really counted arrays */ 30 | if (!xdr_u_int(xdrs, sizep)) { 31 | return (FALSE); 32 | } 33 | c = *sizep; 34 | #ifdef __PATCH__ 35 | if ((c > maxsize || c > UINT_MAX / elsize) 36 | && (xdrs->x_op != XDR_FREE)) { 37 | #else 38 | if ((c > maxsize) && (xdrs->x_op != XDR_FREE)) { 39 | #endif 40 | return (FALSE); 41 | } 42 | 43 | nodesize = c * elsize; // exp: {{umul}} 44 | 45 | /* 46 | * if we are deserializing, we may need to allocate an array. 47 | * We also save time by checking for a null array if we are freeing. 48 | */ 49 | if (target == NULL) 50 | switch (xdrs->x_op) { 51 | case XDR_DECODE: 52 | if (c == 0) 53 | return (TRUE); 54 | *addrp = target = mem_alloc(nodesize); 55 | if (target == NULL) { 56 | (void) fprintf(stderr, 57 | "xdr_array: out of memory\n"); 58 | return (FALSE); 59 | } 60 | bzero(target, nodesize); 61 | break; 62 | 63 | case XDR_FREE: 64 | return (TRUE); 65 | 66 | default: break; 67 | } 68 | 69 | /* 70 | * now we xdr each element of array 71 | */ 72 | for (i = 0; (i < c) && stat; i++) { 73 | stat = (*elproc)(xdrs, target); 74 | target += elsize; 75 | } 76 | 77 | /* 78 | * the array may need freeing 79 | */ 80 | if (xdrs->x_op == XDR_FREE) { 81 | mem_free(*addrp, nodesize); 82 | *addrp = NULL; 83 | } 84 | return (stat); 85 | } 86 | -------------------------------------------------------------------------------- /test/int/sctp-2004-2013.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // 6 | // http://www.securityfocus.com/archive/1/362953 7 | 8 | #include "linux.h" 9 | 10 | #define sctp_sk(sk) ((struct sctp_sock *)(sk)) 11 | 12 | struct sctp_endpoint { 13 | char *debug_name; 14 | }; 15 | 16 | struct sctp_sock { 17 | struct sctp_endpoint *ep; 18 | }; 19 | 20 | int sctp_setsockopt(struct sock *sk, char *optval, int optlen) 21 | { 22 | #ifndef __PATCH__ 23 | char *tmp; 24 | 25 | if (NULL == (tmp = kmalloc(optlen + 1, GFP_KERNEL))) // exp: {{sadd}} 26 | return -ENOMEM; 27 | if (copy_from_user(tmp, optval, optlen)) // exp: {{size}} 28 | return -EFAULT; 29 | tmp[optlen] = '\000'; 30 | sctp_sk(sk)->ep->debug_name = tmp; 31 | #else 32 | /* There is no patch; the option was removed. */ 33 | #endif 34 | 35 | return 0; 36 | } 37 | -------------------------------------------------------------------------------- /test/kint-build: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | DIR=$(dirname "${BASH_SOURCE[0]}") 4 | ABS_DIR=$(cd "${DIR}"; pwd) 5 | 6 | if [ "$1" = "make" ] || [ "$1" = "gmake" ] ; then 7 | "$@" CC="${ABS_DIR}/kint-gcc" CXX="${ABS_DIR}/kint-g++" 8 | exit 9 | fi 10 | 11 | CC="${ABS_DIR}/kint-gcc" CXX="${ABS_DIR}/kint-g++" "$@" 12 | -------------------------------------------------------------------------------- /test/kint-cc1: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | import os 4 | import subprocess 5 | import sys 6 | 7 | def cc(llvmcc, src, argv): 8 | out = [i for i, x in enumerate(argv) if x == '-o'] 9 | if not out: 10 | out = src 11 | else: 12 | out = argv[out[-1] + 1] 13 | if out != '-': 14 | out = os.path.splitext(out)[0] + '.ll' 15 | argv += ['-o', '-'] 16 | # Remove profiling flags. 17 | argv = [x for x in argv if x not in ['-pg', '-fprofile-arcs', '-ftest-coverage']] 18 | # Remove warning flags. 19 | argv = [x for x in argv if not x.startswith('-W')] 20 | # Linux kernel hack: disable asm goto. 21 | argv = [x for x in argv if x != '-DCC_HAVE_ASM_GOTO'] 22 | # Use -fstrict-overflow to distinguish signed/unsigned integers. 23 | more = ['-S', '-flto', '-fstrict-overflow', '-O0', '-g'] 24 | p1 = subprocess.Popen(llvmcc + argv + more + [src], stdout=subprocess.PIPE) 25 | # Don't invoke -early-cse, which may hide undefined behavior bugs. 26 | opts = ['-strip-debug-declare', '-simplifycfg', '-scalarrepl', '-lower-expect'] 27 | p2 = subprocess.Popen(['opt', '-S', '-o', out] + opts, stdin=p1.stdout) 28 | p1.stdout.close() 29 | p2.communicate() 30 | return p1.returncode 31 | 32 | def main(): 33 | llvmcc = os.getenv('LLVMCC', 'clang -no-integrated-as').split(' ', 1) 34 | argv = sys.argv[1:] 35 | exts = ['.c', '.cc', '.cpp', '.cxx', '.C'] 36 | # Keep silence for preprocesssing and make depend. 37 | if any(a in argv for a in ['-E', '-M', '-MM']): 38 | return 39 | # Extrace input source files. 40 | srcs = [a for a in argv if os.path.splitext(a)[1] in exts] 41 | # Keep silence if only '-' is given; otherwise we need to duplicate 42 | # data from stdin for the next consumer (e.g., gcc). 43 | if not srcs: 44 | return 45 | # Remove source files froma args. 46 | argv = [x for x in argv if x not in srcs] 47 | for s in srcs: 48 | rc = cc(llvmcc, s, list(argv)) 49 | sys.exit(rc) 50 | 51 | if __name__ == '__main__': 52 | main() 53 | -------------------------------------------------------------------------------- /test/kint-g++: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DIR=$(dirname "${BASH_SOURCE[0]}") 3 | "$DIR/kint-cc1" "$@" > /dev/null 4 | g++ "$@" 5 | -------------------------------------------------------------------------------- /test/kint-gcc: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | DIR=$(dirname "${BASH_SOURCE[0]}") 3 | "$DIR/kint-cc1" "$@" > /dev/null 4 | gcc "$@" 5 | -------------------------------------------------------------------------------- /test/linux/agp-2011-1745.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/194b3da873fd334ef183806db751473512af29ce 6 | 7 | #include "linux.h" 8 | 9 | struct agp_memory { 10 | size_t page_count; 11 | }; 12 | 13 | int __get_num_entries(void); 14 | int __page_empty(off_t); 15 | 16 | int agp_generic_insert_memory(struct agp_memory * mem, off_t pg_start) 17 | { 18 | int num_entries = __get_num_entries(); 19 | off_t j; 20 | 21 | if (mem->page_count == 0) 22 | return 0; 23 | 24 | if (num_entries < 0) num_entries = 0; 25 | 26 | #ifndef __PATCH__ 27 | /* AK: could wrap */ 28 | if ((pg_start + mem->page_count) > num_entries) 29 | #else 30 | if (((pg_start + mem->page_count) > num_entries) || 31 | ((pg_start + mem->page_count) < pg_start)) 32 | #endif 33 | return -EINVAL; 34 | 35 | j = pg_start; 36 | 37 | while (j < (pg_start + mem->page_count)) { // exp: {{uadd}} 38 | if (!__page_empty(j)) 39 | return -EBUSY; 40 | j++; 41 | } 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /test/linux/agp-2011-1746.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/b522f02184b413955f3bc952e3776ce41edc6355 6 | 7 | #include "linux.h" 8 | 9 | #ifdef __LP64__ 10 | #define SIZE_OF_AGP_MEMORY 104 11 | #else 12 | #define SIZE_OF_AGP_MEMORY 60 13 | #endif 14 | 15 | struct agp_memory { 16 | char ph[SIZE_OF_AGP_MEMORY]; 17 | }; 18 | 19 | void agp_alloc_page_array(size_t size, struct agp_memory *mem); 20 | 21 | struct agp_memory *agp_create_user_memory(unsigned long num_agp_pages) 22 | { 23 | struct agp_memory *new; 24 | unsigned long alloc_size = num_agp_pages*sizeof(struct page *); // exp: {{umul}} 25 | 26 | #ifdef __PATCH__ 27 | if (INT_MAX/sizeof(struct page *) < num_agp_pages) 28 | return NULL; 29 | #endif 30 | new = kzalloc(sizeof(struct agp_memory), GFP_KERNEL); 31 | if (new == NULL) 32 | return NULL; 33 | 34 | agp_alloc_page_array(alloc_size, new); 35 | 36 | return new; 37 | } 38 | -------------------------------------------------------------------------------- /test/linux/agp-2011-2022.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/194b3da873fd334ef183806db751473512af29ce 6 | 7 | #include "linux.h" 8 | 9 | struct agp_memory { 10 | size_t page_count; 11 | }; 12 | 13 | int __get_num_entries(void); 14 | int __agp_type_to_mask_type(int); 15 | void __writel(size_t); 16 | int agp_num_entries(void); 17 | 18 | int agp_generic_remove_memory(struct agp_memory *mem, off_t pg_start, int type) 19 | { 20 | size_t i; 21 | int mask_type, num_entries = __get_num_entries(); 22 | 23 | if (mem->page_count == 0) 24 | return 0; 25 | 26 | #ifdef __PATCH__ 27 | num_entries = agp_num_entries(); 28 | if (((pg_start + mem->page_count) > num_entries) || 29 | ((pg_start + mem->page_count) < pg_start)) 30 | return -EINVAL; 31 | #endif 32 | mask_type = __agp_type_to_mask_type(type); 33 | if (mask_type != 0) { 34 | /* The generic routines know nothing of memory types */ 35 | return -EINVAL; 36 | } 37 | 38 | /* AK: bogus, should encode addresses > 4GB */ 39 | for (i = pg_start; i < (mem->page_count + pg_start); i++) { // exp: {{uadd}} 40 | __writel(i); 41 | } 42 | 43 | return 0; 44 | } 45 | -------------------------------------------------------------------------------- /test/linux/aio-2010-3067.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/75e1c70fc31490ef8a373ea2a4bea2524099b478 6 | 7 | #include "linux.h" 8 | 9 | struct iocb; 10 | 11 | long do_io_submit(long nr, struct iocb __user *__user *iocbpp) 12 | { 13 | long ret = 0; 14 | 15 | if (unlikely(nr < 0)) 16 | return -EINVAL; 17 | #ifdef __PATCH__ 18 | if (unlikely(nr > LONG_MAX/sizeof(*iocbpp))) 19 | nr = LONG_MAX/sizeof(*iocbpp); 20 | #endif 21 | if (unlikely(!access_ok(VERIFY_READ, iocbpp, (nr*sizeof(*iocbpp))))) // exp: {{umul}} 22 | return -EFAULT; 23 | 24 | return ret; 25 | } 26 | -------------------------------------------------------------------------------- /test/linux/av7110-2011-0521.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/cb26a24ee9706473f31d34cc259f4dcf45cd0644 6 | 7 | #include "linux.h" 8 | 9 | #define CA_CI 1 10 | #define CA_CI_LINK 2 11 | #define FW_CI_LL_SUPPORT(arm_app) ((arm_app) & 0x80000000) 12 | 13 | typedef struct ca_slot_info_t { 14 | int num; 15 | int type; 16 | unsigned int flags; 17 | } ca_slot_info_t; 18 | 19 | struct av7110 { 20 | u32 arm_app; 21 | ca_slot_info_t ci_slot[2]; 22 | }; 23 | 24 | int dvb_ca_ioctl(struct av7110 *av7110, void *parg) 25 | { 26 | ca_slot_info_t *info = (ca_slot_info_t *)parg; 27 | 28 | #ifndef __PATCH__ 29 | if (info->num > 1) 30 | return -EINVAL; 31 | #else 32 | if (info->num < 0 || info->num > 1) 33 | return -EINVAL; 34 | #endif 35 | av7110->ci_slot[info->num].num = info->num; // exp: {{array}} 36 | av7110->ci_slot[info->num].type = FW_CI_LL_SUPPORT(av7110->arm_app) ? 37 | CA_CI_LINK : CA_CI; 38 | memcpy(info, &av7110->ci_slot[info->num], sizeof(ca_slot_info_t)); 39 | return 0; 40 | } 41 | -------------------------------------------------------------------------------- /test/linux/ax25-2009-2909.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/b7058842c940ad2c08dd829b21e5c92ebe3b8758 6 | 7 | #include "linux.h" 8 | 9 | #define IFNAMSIZ 16 10 | #define SO_BINDTODEVICE 25 11 | 12 | int ax25_setsockopt(struct socket *sock, int level, int optname, 13 | #ifndef __PATCH__ 14 | char __user *optval, int optlen) 15 | #else 16 | char __user *optval, unsigned int optlen) 17 | #endif 18 | { 19 | char devname[IFNAMSIZ]; 20 | int res = 0; 21 | 22 | if (optlen < sizeof(int)) 23 | return -EINVAL; 24 | 25 | switch (optname) { 26 | case SO_BINDTODEVICE: 27 | if (optlen > IFNAMSIZ) 28 | optlen = IFNAMSIZ; 29 | if (copy_from_user(devname, optval, optlen)) { // exp: {{size}} 30 | res = -EFAULT; 31 | break; 32 | } 33 | default: 34 | res = -ENOPROTOOPT; 35 | } 36 | return res; 37 | } 38 | -------------------------------------------------------------------------------- /test/linux/bcm-2010-2959.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp32 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/5b75c4973ce779520b9d1e392483207d6f842cde 6 | 7 | #include "linux.h" 8 | 9 | #define MAX_NFRAMES 256 10 | #define CFSIZ sizeof(struct can_frame) 11 | #define MHSIZ sizeof(struct bcm_msg_head) 12 | 13 | struct bcm_msg_head { 14 | u32 nframes; 15 | }; 16 | 17 | struct can_frame { char dummy[6]; }; 18 | 19 | struct bcm_op { 20 | struct can_frame *frames; 21 | }; 22 | 23 | int bcm_tx_setup(struct bcm_msg_head *msg_head, struct bcm_op *op) 24 | { 25 | #ifndef __PATCH__ 26 | if (msg_head->nframes < 1) 27 | return -EINVAL; 28 | #else 29 | /* check nframes boundaries - we need at least one can_frame */ 30 | if (msg_head->nframes < 1 || msg_head->nframes > MAX_NFRAMES) 31 | return -EINVAL; 32 | #endif 33 | 34 | if (msg_head->nframes > 1) { 35 | op->frames = kmalloc(msg_head->nframes * CFSIZ, GFP_KERNEL); // exp32: {{umul}} 36 | if (!op->frames) { 37 | kfree(op); 38 | return -ENOMEM; 39 | } 40 | } 41 | 42 | return 0; 43 | } 44 | -------------------------------------------------------------------------------- /test/linux/btrfs-2010-2538.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/2ebc3464781ad24474abcbd2274e6254689853b5 6 | 7 | #include "linux.h" 8 | 9 | struct inode { 10 | loff_t i_size; 11 | }; 12 | 13 | #define BTRFS_MAX_METADATA_BLOCKSIZE 65536 14 | 15 | void btrfs_lookup_first_ordered_extent(struct inode * inode, u64 file_offset); 16 | 17 | long btrfs_ioctl_clone(struct inode *src, u64 s_blocksize, 18 | u64 off, u64 olen) 19 | { 20 | u64 len = olen; 21 | u64 bs = s_blocksize; 22 | int ret; 23 | 24 | BUG_ON(s_blocksize < 4096); 25 | BUG_ON(s_blocksize > BTRFS_MAX_METADATA_BLOCKSIZE); 26 | BUG_ON(src->i_size < 0) 27 | BUG_ON(src->i_size > OFFSET_MAX); 28 | 29 | ret = -EINVAL; 30 | #ifndef __PATCH__ 31 | if (off >= src->i_size || off + len > src->i_size) 32 | #else 33 | if (off + len > src->i_size || off + len < off) 34 | #endif 35 | goto out; 36 | if (len == 0) 37 | olen = len = src->i_size - off; 38 | /* if we extend to eof, continue to block boundary */ 39 | if (off + len == src->i_size) 40 | len = ((src->i_size + bs-1) & ~(bs-1)) 41 | -off; 42 | 43 | /* verify the end result is block aligned */ 44 | if ((off & (bs-1)) || ((off + len) & (bs-1))) // exp: {{uadd}} 45 | goto out; 46 | 47 | btrfs_lookup_first_ordered_extent(src, off + len); 48 | 49 | ret = 0; 50 | out: 51 | return ret; 52 | } 53 | -------------------------------------------------------------------------------- /test/linux/cfg80211-2009-3280.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/fcc6cb0c13555e78c2d47257b6d1b5e59b0c419a 6 | 7 | #include "linux.h" 8 | 9 | #ifndef __PATCH__ 10 | const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, size_t len) 11 | #else 12 | const u8 *cfg80211_find_ie(u8 eid, const u8 *ies, int len) 13 | #endif 14 | { 15 | while (len > 2 && ies[0] != eid) { 16 | len -= ies[1] + 2; // exp: {{usub}} 17 | ies += ies[1] + 2; 18 | } 19 | if (len < 2) 20 | return NULL; 21 | if (len < 2 + ies[1]) 22 | return NULL; 23 | return ies; 24 | } 25 | -------------------------------------------------------------------------------- /test/linux/cifs-2011-3191.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/9438fabb73eb48055b58b89fc51e0bc4db22fabd 6 | 7 | #include "linux.h" 8 | 9 | #define SMB_COM_TRANSACTION2 0x32 10 | 11 | typedef struct smb_com_transaction2_fnext_req { 12 | char ResumeFileName[1]; 13 | } __attribute__((packed)) TRANSACTION2_FNEXT_REQ; 14 | 15 | struct cifs_tcon; 16 | 17 | struct cifs_search_info { 18 | const char *presume_name; 19 | unsigned int resume_name_len; 20 | }; 21 | 22 | int smb_init(int smb_command, int wct, struct cifs_tcon *tcon, 23 | void **request_buf, void **response_buf); 24 | 25 | void cifs_buf_release(void *); 26 | 27 | int CIFSFindNext(const int xid, struct cifs_tcon *tcon, 28 | u16 searchHandle, struct cifs_search_info *psrch_inf) 29 | { 30 | TRANSACTION2_FNEXT_REQ *pSMB = NULL; 31 | int rc; 32 | #ifndef __PATCH__ 33 | int name_len; 34 | #else 35 | unsigned int name_len; 36 | #endif 37 | u16 params, byte_count; 38 | 39 | rc = smb_init(SMB_COM_TRANSACTION2, 15, tcon, (void **) &pSMB, NULL); 40 | if (rc) 41 | return rc; 42 | 43 | name_len = psrch_inf->resume_name_len; 44 | params += name_len; 45 | if (name_len < PATH_MAX) { 46 | memcpy(pSMB->ResumeFileName, psrch_inf->presume_name, name_len); // exp: {{size}} 47 | byte_count += name_len; 48 | /* 14 byte parm len above enough for 2 byte null terminator */ 49 | pSMB->ResumeFileName[name_len] = 0; 50 | pSMB->ResumeFileName[name_len+1] = 0; // exp: {{array}} 51 | } else { 52 | rc = -EINVAL; 53 | goto exit; 54 | } 55 | exit: 56 | if (rc != 0) 57 | cifs_buf_release(pSMB); 58 | return rc; 59 | } 60 | -------------------------------------------------------------------------------- /test/linux/gdth-2010-4157.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // 6 | // http://git.kernel.org/linus/f63ae56e4e97fb12053590e41a4fa59e7daa74a4 7 | 8 | #include "linux.h" 9 | 10 | typedef struct { 11 | u16 ionode; 12 | /* ... */ 13 | unsigned long data_len; 14 | unsigned long sense_len; 15 | /* ... */ 16 | } gdth_ioctl_general; 17 | 18 | typedef struct { 19 | /* ... */ 20 | } gdth_ha_str; 21 | 22 | gdth_ha_str *gdth_find_ha(int hanum); 23 | char *gdth_ioctl_alloc(gdth_ha_str *ha, int size, int scratch, u64 *paddr); 24 | void gdth_ioctl_free(gdth_ha_str *ha, int size, char *buf, u64 paddr); 25 | 26 | int ioc_general(void __user *arg, char *cmnd) 27 | { 28 | gdth_ioctl_general gen; 29 | char *buf = NULL; 30 | u64 paddr; 31 | gdth_ha_str *ha; 32 | 33 | if (copy_from_user(&gen, arg, sizeof(gdth_ioctl_general))) 34 | return -EFAULT; 35 | ha = gdth_find_ha(gen.ionode); 36 | if (!ha) 37 | return -EFAULT; 38 | #ifdef __PATCH__ 39 | if (gen.data_len > INT_MAX) 40 | return -EINVAL; 41 | if (gen.sense_len > INT_MAX) 42 | return -EINVAL; 43 | if (gen.data_len + gen.sense_len > INT_MAX) 44 | return -EINVAL; 45 | #endif 46 | if (gen.data_len + gen.sense_len != 0) { // exp: {{uadd}} 47 | if (!(buf = gdth_ioctl_alloc(ha, gen.data_len + gen.sense_len, 48 | FALSE, &paddr))) 49 | return -EFAULT; 50 | } 51 | return 0; 52 | } 53 | -------------------------------------------------------------------------------- /test/linux/kvm-2009-3638.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp32 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp64 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/6a54435560efdab1a08f429a954df4d6c740bddf 6 | 7 | #include "linux.h" 8 | 9 | #define KVM_MAX_CPUID_ENTRIES 80 10 | 11 | struct kvm_cpuid2 { 12 | u32 nent; 13 | }; 14 | 15 | struct kvm_cpuid_entry2 { 16 | u32 data[10]; 17 | }; 18 | 19 | int kvm_dev_ioctl_get_supported_cpuid(struct kvm_cpuid2 *cpuid, 20 | struct kvm_cpuid_entry2 *entries) 21 | { 22 | int r; 23 | struct kvm_cpuid_entry2 *cpuid_entries; 24 | 25 | if (cpuid->nent < 1) 26 | goto out; 27 | #ifdef __PATCH__ 28 | if (cpuid->nent > KVM_MAX_CPUID_ENTRIES) 29 | cpuid->nent = KVM_MAX_CPUID_ENTRIES; 30 | #endif 31 | r = -ENOMEM; 32 | cpuid_entries = vmalloc(sizeof(struct kvm_cpuid_entry2) * cpuid->nent); // exp32: {{umul}} 33 | if (!cpuid_entries) 34 | goto out; 35 | r = 0; 36 | vfree(cpuid_entries); 37 | out: 38 | return r; 39 | } 40 | -------------------------------------------------------------------------------- /test/linux/linux.h: -------------------------------------------------------------------------------- 1 | #pragma once 2 | 3 | #define __user 4 | 5 | #define NULL ((void *)0) 6 | #define TRUE 1 7 | #define FALSE 0 8 | 9 | #define ENOMEM 12 10 | #define EFAULT 14 11 | #define EBUSY 16 12 | #define EINVAL 22 13 | #define ERANGE 34 14 | #define EMSGSIZE 90 15 | #define ENOPROTOOPT 92 16 | #define EUCLEAN 117 17 | 18 | #define INT_MIN ((int)(1U << (sizeof(int) * 8 - 1))) 19 | #define INT_MAX (~INT_MIN) 20 | #define UINT_MAX (~0U) 21 | 22 | #define LONG_MIN ((long)(1UL << (sizeof(long) * 8 - 1))) 23 | #define LONG_MAX (~LONG_MIN) 24 | #define ULONG_MAX (~0UL) 25 | 26 | #define GFP_KERNEL (0x10u | 0x40u | 0x80u) 27 | 28 | #define BUG_ON(x) if (x) __builtin_trap(); 29 | 30 | #define likely(x) __builtin_expect(!!(x), 1) 31 | #define unlikely(x) __builtin_expect(!!(x), 0) 32 | 33 | typedef unsigned char u_char; 34 | typedef unsigned short u_short; 35 | typedef unsigned int u_int; 36 | typedef unsigned long u_long; 37 | 38 | typedef unsigned char unchar; 39 | typedef unsigned short ushort; 40 | typedef unsigned int uint; 41 | typedef unsigned long ulong; 42 | 43 | typedef signed char s8; 44 | typedef unsigned char u8; 45 | typedef s8 int8_t; 46 | typedef u8 uint8_t; 47 | 48 | typedef signed short s16; 49 | typedef unsigned short u16; 50 | typedef s16 int16_t; 51 | typedef u16 uint16_t; 52 | 53 | typedef signed int s32; 54 | typedef unsigned int u32; 55 | typedef s32 int32_t; 56 | typedef u32 uint32_t; 57 | 58 | typedef signed long long s64; 59 | typedef unsigned long long u64; 60 | typedef s64 int64_t; 61 | typedef u64 uint64_t; 62 | 63 | typedef unsigned long size_t; 64 | typedef long off_t; 65 | typedef long long loff_t; 66 | 67 | #define INT_LIMIT(x) (~((x)1 << (sizeof(x)*8 - 1))) 68 | #define OFFSET_MAX INT_LIMIT(loff_t) 69 | #define OFFT_OFFSET_MAX INT_LIMIT(off_t) 70 | 71 | #define PATH_MAX 4096 72 | 73 | #define VERIFY_READ 0 74 | #define VERIFY_WRITE 1 75 | 76 | #define ALIGN(x, a) __ALIGN_MASK(x, (typeof(x))(a) - 1) 77 | #define __ALIGN_MASK(x, mask) (((x) + (mask)) & ~(mask)) 78 | 79 | #define PAGE_SHIFT 12 80 | #define PAGE_SIZE (1UL << PAGE_SHIFT) 81 | #define PAGE_MASK (~(PAGE_SIZE-1)) 82 | 83 | #define PAGE_ALIGN(addr) ALIGN(addr, PAGE_SIZE) 84 | 85 | typedef unsigned gfp_t; 86 | 87 | void *kmalloc(size_t size, gfp_t flags); 88 | void *kzalloc(size_t size, gfp_t flags); 89 | void kfree(void *); 90 | 91 | void *vmalloc(unsigned long size); 92 | void vfree(const void *addr); 93 | 94 | void *memcpy(void *dest, const void *src, size_t count); 95 | 96 | unsigned long copy_from_user(void *to, const void __user *from, unsigned long n); 97 | 98 | #define access_ok(type, addr, size) __access_ok((unsigned long)addr,size) 99 | 100 | int __access_ok(unsigned long addr, unsigned long size); 101 | 102 | struct sock; 103 | struct socket; 104 | struct sk_buff; 105 | 106 | struct sk_buff *sock_alloc_send_skb(struct sock *sk, 107 | unsigned long size, 108 | int noblock, 109 | int *errcode); 110 | 111 | #define MINORBITS 20 112 | #define MINORMASK ((1U << MINORBITS) - 1) 113 | #define MAJOR(dev) ((unsigned int) ((dev) >> MINORBITS)) 114 | #define MINOR(dev) ((unsigned int) ((dev) & MINORMASK)) 115 | #define MKDEV(ma,mi) (((ma) << MINORBITS) | (mi)) 116 | 117 | typedef u32 dev_t; 118 | 119 | static inline u32 new_encode_dev(dev_t dev) 120 | { 121 | unsigned major = MAJOR(dev); 122 | unsigned minor = MINOR(dev); 123 | return (minor & 0xff) | (major << 8) | ((minor & ~0xff) << 12); 124 | } 125 | -------------------------------------------------------------------------------- /test/linux/mpt2sas-2011-1494.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp32 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp64 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/a1f74ae82d133ebb2aabb19d181944b4e83e9960 6 | 7 | #include "linux.h" 8 | 9 | struct MPT2SAS_ADAPTER { 10 | u16 request_sz; 11 | }; 12 | 13 | struct mpt2_ioctl_command { 14 | uint32_t data_sge_offset; 15 | }; 16 | 17 | enum block_state { NON_BLOCKING, BLOCKING }; 18 | 19 | long _ctl_do_mpt_command(struct MPT2SAS_ADAPTER *ioc, 20 | struct mpt2_ioctl_command karg, void __user *mf, enum block_state state) 21 | { 22 | void *mpi_request = NULL; 23 | long ret = 0; 24 | 25 | mpi_request = kzalloc(ioc->request_sz, GFP_KERNEL); 26 | if (!mpi_request) { 27 | ret = -ENOMEM; 28 | goto out; 29 | } 30 | #ifdef __PATCH__ 31 | /* Check for overflow and wraparound */ 32 | if (karg.data_sge_offset * 4 > ioc->request_sz || 33 | karg.data_sge_offset > (UINT_MAX / 4)) { 34 | ret = -EINVAL; 35 | goto out; 36 | } 37 | #endif 38 | /* copy in request message frame from user */ 39 | if (copy_from_user(mpi_request, mf, karg.data_sge_offset*4)) { \ 40 | // exp32: {{umul}}{{size}} \ 41 | // exp64: {{umul}} 42 | ret = -EFAULT; 43 | goto out; 44 | } 45 | out: 46 | kfree(mpi_request); 47 | return ret; 48 | } 49 | -------------------------------------------------------------------------------- /test/linux/oabi-2011-1759.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp32 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/0f22072ab50cac7983f9660d33974b45184da4f9 6 | 7 | #include "linux.h" 8 | 9 | #define SEMOPM 32 10 | 11 | struct sembuf { 12 | unsigned short sem_num; 13 | short sem_op; 14 | short sem_flg; 15 | }; 16 | 17 | long sys_oabi_semtimedop(unsigned nsops) 18 | { 19 | struct sembuf *sops; 20 | 21 | #ifndef __PATCH__ 22 | if (nsops < 1) 23 | #else 24 | if (nsops < 1 || nsops > SEMOPM) 25 | #endif 26 | return -EINVAL; 27 | sops = kmalloc(sizeof(*sops) * nsops, GFP_KERNEL); // exp32: {{umul}} 28 | if (!sops) 29 | return -ENOMEM; 30 | return 0; 31 | } 32 | -------------------------------------------------------------------------------- /test/linux/pktcdvd-2010-3437.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // 6 | // http://git.kernel.org/linus/252a52aa4fa22a668f019e55b3aac3ff71ec1c29 7 | 8 | #include "linux.h" 9 | 10 | #define MAX_WRITERS 8 11 | 12 | struct pkt_ctrl_command { 13 | u32 command; 14 | u32 dev_index; 15 | u32 dev; 16 | u32 pkt_dev; 17 | u32 num_devices; 18 | u32 padding; 19 | }; 20 | 21 | struct block_device { 22 | dev_t bd_dev; 23 | }; 24 | 25 | struct pktcdvd_device { 26 | struct block_device *bdev; 27 | dev_t pkt_dev; 28 | }; 29 | 30 | struct pktcdvd_device *pkt_devs[MAX_WRITERS]; 31 | 32 | #ifndef __PATCH__ 33 | static struct pktcdvd_device *pkt_find_dev_from_minor(int dev_minor) 34 | #else 35 | static struct pktcdvd_device *pkt_find_dev_from_minor(unsigned int dev_minor) 36 | #endif 37 | { 38 | if (dev_minor >= MAX_WRITERS) 39 | return NULL; 40 | return pkt_devs[dev_minor]; // exp: {{array}} 41 | } 42 | 43 | void pkt_get_status(struct pkt_ctrl_command *ctrl_cmd) 44 | { 45 | struct pktcdvd_device *pd; 46 | 47 | pd = pkt_find_dev_from_minor(ctrl_cmd->dev_index); 48 | if (pd) { 49 | ctrl_cmd->dev = new_encode_dev(pd->bdev->bd_dev); 50 | ctrl_cmd->pkt_dev = new_encode_dev(pd->pkt_dev); 51 | } else { 52 | ctrl_cmd->dev = 0; 53 | ctrl_cmd->pkt_dev = 0; 54 | } 55 | ctrl_cmd->num_devices = MAX_WRITERS; 56 | } 57 | -------------------------------------------------------------------------------- /test/linux/rose-2009-1265.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -D__PATCH__ %s | intck | diagdiff %s 3 | // http://git.kernel.org/linus/83e0bbcbe2145f160fbaa109b0439dae7f4a38a9 4 | 5 | #include "linux.h" 6 | 7 | #define AX25_MAX_DIGIS 8 8 | 9 | #define AX25_BPQ_HEADER_LEN 16 10 | #define AX25_KISS_HEADER_LEN 1 11 | 12 | #define AX25_HEADER_LEN 17 13 | #define AX25_ADDR_LEN 7 14 | #define AX25_DIGI_HEADER_LEN (AX25_MAX_DIGIS * AX25_ADDR_LEN) 15 | #define AX25_MAX_HEADER_LEN (AX25_HEADER_LEN + AX25_DIGI_HEADER_LEN) 16 | 17 | #define ROSE_MIN_LEN 3 18 | 19 | #define MSG_DONTWAIT 0x40 20 | 21 | struct kiocb; 22 | 23 | struct socket { 24 | struct sock *sk; 25 | }; 26 | 27 | struct msghdr { 28 | unsigned int msg_flags; 29 | }; 30 | 31 | int rose_sendmsg(struct kiocb *iocb, struct socket *sock, 32 | struct msghdr *msg, size_t len) 33 | { 34 | struct sock *sk = sock->sk; 35 | struct sk_buff *skb; 36 | int err; 37 | int size; 38 | 39 | #ifdef __PATCH__ 40 | /* Build a packet */ 41 | /* Sanity check the packet size */ 42 | if (len > 65535) 43 | return -EMSGSIZE; 44 | #endif 45 | size = len + AX25_BPQ_HEADER_LEN + AX25_MAX_HEADER_LEN + ROSE_MIN_LEN; // exp: {{uadd}} 46 | 47 | if ((skb = sock_alloc_send_skb(sk, size, msg->msg_flags & MSG_DONTWAIT, &err)) == NULL) // exp: {{size}} 48 | return err; 49 | 50 | return len; 51 | } 52 | -------------------------------------------------------------------------------- /test/linux/sctp-2008-3526.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp32 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s --prefix=exp32 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // 6 | // http://git.kernel.org/linus/30c2235cbc477d4629983d440cdc4f496fec9246 7 | 8 | #include "linux.h" 9 | 10 | struct sctp_auth_bytes { 11 | u32 len; 12 | u8 data[]; 13 | }; 14 | 15 | struct sctp_auth_bytes *sctp_auth_create_key(u32 key_len, gfp_t gfp) 16 | { 17 | struct sctp_auth_bytes *key; 18 | 19 | #ifdef __PATCH__ 20 | /* Verify that we are not going to overflow INT_MAX */ 21 | if ((INT_MAX - key_len) < sizeof(struct sctp_auth_bytes)) 22 | return NULL; 23 | #endif 24 | /* Allocate the shared key */ 25 | key = kmalloc(sizeof(struct sctp_auth_bytes) + key_len, gfp); // exp32: {{uadd}} 26 | if (!key) 27 | return NULL; 28 | 29 | key->len = key_len; 30 | 31 | return key; 32 | } 33 | -------------------------------------------------------------------------------- /test/linux/si4713-2011-2700.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/dc6b845044ccb7e9e6f3b7e71bd179b3cf0223b6 6 | 7 | #include "linux.h" 8 | 9 | #define V4L2_CTRL_CLASS_FM_TX 0x009b0000 10 | #define V4L2_CID_FM_TX_CLASS_BASE (V4L2_CTRL_CLASS_FM_TX | 0x900) 11 | #define V4L2_CID_RDS_TX_PS_NAME (V4L2_CID_FM_TX_CLASS_BASE + 5) 12 | #define V4L2_CID_RDS_TX_RADIO_TEXT (V4L2_CID_FM_TX_CLASS_BASE + 6) 13 | 14 | #define MAX_RDS_PS_NAME 96 15 | #define MAX_RDS_RADIO_TEXT 384 16 | 17 | struct si4713_device; 18 | 19 | struct v4l2_ext_control { 20 | u32 id; 21 | u32 size; 22 | u32 reserved2[1]; 23 | union { 24 | s32 value; 25 | s64 value64; 26 | char *string; 27 | }; 28 | } __attribute__ ((packed)); 29 | 30 | int si4713_set_rds_ps_name(struct si4713_device *sdev, char *ps_name); 31 | 32 | int si4713_set_rds_radio_text(struct si4713_device *sdev, char *rt); 33 | 34 | int si4713_write_econtrol_string(struct si4713_device *sdev, 35 | struct v4l2_ext_control *control) 36 | { 37 | int len; 38 | s32 rval = 0; 39 | 40 | switch (control->id) { 41 | case V4L2_CID_RDS_TX_PS_NAME: { 42 | char ps_name[MAX_RDS_PS_NAME + 1]; 43 | 44 | len = control->size - 1; // exp: {{usub}} 45 | #ifndef __PATCH__ 46 | if (len > MAX_RDS_PS_NAME) { 47 | #else 48 | if (len < 0 || len > MAX_RDS_PS_NAME) { 49 | #endif 50 | rval = -ERANGE; 51 | goto exit; 52 | } 53 | rval = copy_from_user(ps_name, control->string, len); // exp: {{size}} 54 | if (rval) { 55 | rval = -EFAULT; 56 | goto exit; 57 | } 58 | ps_name[len] = '\0'; // exp: {{array}} 59 | 60 | rval = si4713_set_rds_ps_name(sdev, ps_name); 61 | } 62 | break; 63 | 64 | case V4L2_CID_RDS_TX_RADIO_TEXT: { 65 | char radio_text[MAX_RDS_RADIO_TEXT + 1]; 66 | 67 | len = control->size - 1; // exp:: {{usub}} 68 | #ifndef __PATCH__ 69 | if (len > MAX_RDS_RADIO_TEXT) { 70 | #else 71 | if (len < 0 || len > MAX_RDS_RADIO_TEXT) { 72 | #endif 73 | rval = -ERANGE; 74 | goto exit; 75 | } 76 | rval = copy_from_user(radio_text, control->string, len); // exp: {{size}} 77 | if (rval) { 78 | rval = -EFAULT; 79 | goto exit; 80 | } 81 | radio_text[len] = '\0'; // exp:: {{array}} 82 | 83 | rval = si4713_set_rds_radio_text(sdev, radio_text); 84 | } 85 | break; 86 | 87 | default: 88 | rval = -EINVAL; 89 | break; 90 | } 91 | 92 | exit: 93 | return rval; 94 | } 95 | -------------------------------------------------------------------------------- /test/linux/snd-2010-3442.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp32 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // http://git.kernel.org/linus/5591bf07225523600450edd9e6ad258bb877b779 6 | 7 | #include "linux.h" 8 | 9 | #define MAX_CONTROL_COUNT 1028 10 | 11 | struct snd_kcontrol { 12 | unsigned int count; 13 | }; 14 | 15 | struct snd_kcontrol_volatile { 16 | struct snd_ctl_file *owner; 17 | unsigned int access; 18 | }; 19 | 20 | struct snd_kcontrol *snd_ctl_new(struct snd_kcontrol *control, 21 | unsigned int access) 22 | { 23 | struct snd_kcontrol *kctl; 24 | 25 | #ifdef __PATCH__ 26 | if (control->count > MAX_CONTROL_COUNT) 27 | return NULL; 28 | #endif 29 | kctl = kzalloc(sizeof(*kctl) + sizeof(struct snd_kcontrol_volatile) * control->count, GFP_KERNEL); // exp32: {{umul}} 30 | return kctl; 31 | } 32 | -------------------------------------------------------------------------------- /test/linux/xfs-2011-4077.c: -------------------------------------------------------------------------------- 1 | // RUN: %linuxcc -m32 %s | intck | diagdiff %s --prefix=exp 2 | // RUN: %linuxcc -m64 %s | intck | diagdiff %s --prefix=exp 3 | // RUN: %linuxcc -D__PATCH__ -m32 %s | intck | diagdiff %s 4 | // RUN: %linuxcc -D__PATCH__ -m64 %s | intck | diagdiff %s 5 | // 6 | // http://git.kernel.org/linus/b52a360b2aa1c59ba9970fb0f52bbb093fcc7a24 7 | 8 | #include "linux.h" 9 | 10 | #define XFS_ERROR(e) (e) 11 | #define XFS_IFINLINE 0x01 12 | #define XFS_ILOCK_SHARED (1<<3) 13 | #define MAXPATHLEN 1024 14 | #define EFSCORRUPTED EUCLEAN 15 | 16 | typedef int64_t xfs_fsize_t; 17 | 18 | typedef struct xfs_ifork { 19 | unsigned char if_flags; 20 | union { 21 | char *if_data; 22 | } if_u1; 23 | } xfs_ifork_t; 24 | 25 | typedef struct xfs_icdinode { 26 | xfs_fsize_t di_size; 27 | } xfs_icdinode_t; 28 | 29 | typedef struct xfs_inode { 30 | xfs_ifork_t i_df; 31 | xfs_icdinode_t i_d; 32 | } xfs_inode_t; 33 | 34 | void xfs_ilock(xfs_inode_t *, uint); 35 | void xfs_iunlock(xfs_inode_t *, uint); 36 | 37 | int xfs_readlink_bmap(xfs_inode_t *, char *); 38 | 39 | int 40 | xfs_readlink( 41 | xfs_inode_t *ip, 42 | char *link) 43 | { 44 | #ifndef __PATCH__ 45 | int pathlen; 46 | #else 47 | xfs_fsize_t pathlen; 48 | #endif 49 | int error = 0; 50 | 51 | xfs_ilock(ip, XFS_ILOCK_SHARED); 52 | 53 | pathlen = ip->i_d.di_size; 54 | if (!pathlen) 55 | goto out; 56 | 57 | #ifdef __PATCH__ 58 | if (pathlen < 0 || pathlen > MAXPATHLEN) { 59 | return XFS_ERROR(EFSCORRUPTED); 60 | } 61 | #endif 62 | 63 | if (ip->i_df.if_flags & XFS_IFINLINE) { 64 | memcpy(link, ip->i_df.if_u1.if_data, pathlen); // exp: {{size}} 65 | link[pathlen] = '\0'; 66 | } else { 67 | error = xfs_readlink_bmap(ip, link); 68 | } 69 | 70 | out: 71 | xfs_iunlock(ip, XFS_ILOCK_SHARED); 72 | return error; 73 | } 74 | -------------------------------------------------------------------------------- /test/lit.cfg.in: -------------------------------------------------------------------------------- 1 | config.name = "@PACKAGE@" 2 | config.test_format = lit.formats.ShTest() 3 | config.suffixes = ['.c'] 4 | 5 | config.target_triple = "@host@" 6 | config.test_exec_root = "@abs_builddir@" 7 | config.test_source_root = "@abs_srcdir@" 8 | 9 | import os, os.path 10 | 11 | if 'LLVMCC' in os.environ: 12 | config.environment['LLVMCC'] = os.getenv('LLVMCC') 13 | 14 | llvm_obj_root = lit.util.capture(['llvm-config', '--obj-root']).strip() 15 | llvm_build_mode = lit.util.capture(['llvm-config', '--build-mode']).strip() 16 | llvm_bindir = os.path.join(llvm_obj_root, llvm_build_mode, 'bin') 17 | kint_bindir = os.path.join("@abs_top_builddir@", 'bin') 18 | path = os.path.pathsep.join( (kint_bindir, config.test_source_root, llvm_bindir, config.environment['PATH']) ) 19 | config.environment['PATH'] = path 20 | 21 | cc = 'kint-cc1 -c -o -' 22 | linuxcc = 'kint-cc1 -nostdinc -fno-builtin -c -o -' 23 | config.substitutions.append( ('%cc', cc) ) 24 | config.substitutions.append( ('%linuxcc', linuxcc) ) 25 | -------------------------------------------------------------------------------- /web/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | KINT 4 | 5 | 6 | 7 |

8 |

Improving Integer Security for Systems with KINT

9 |
10 | 11 |

Overview

12 | 13 |

14 | KINT is a tool that uses scalable static analysis to detect integer 15 | errors in C programs. KINT generates constraints from source code 16 | and user annotations, and feeds them into a constraint solver for 17 | deciding whether an integer error can occur. KINT identified more 18 | than 100 integer errors in the Linux kernel, the lighttpd web server, 19 | and OpenSSH, which were confirmed and fixed by the developers. 20 |

21 | 22 |

Publications

23 | 24 | 34 | 35 |

Examples of vulnerabilities found using KINT

36 | 37 | 65 | 66 |

Software

67 | 68 | 94 | 95 |

People

96 | 97 | 106 | 107 | 108 | 109 | --------------------------------------------------------------------------------