Index: files/patch-llvm-2.9 =================================================================== RCS file: files/patch-llvm-2.9 diff -N files/patch-llvm-2.9 --- /dev/null 1 Jan 1970 00:00:00 -0000 +++ files/patch-llvm-2.9 19 May 2011 14:47:18 -0000 @@ -0,0 +1,995 @@ +diff --git libclamav/c++/ClamBCRTChecks.cpp libclamav/c++/ClamBCRTChecks.cpp +index a74476c..bf3992d 100644 +--- libclamav/c++/ClamBCRTChecks.cpp ++++ libclamav/c++/ClamBCRTChecks.cpp +@@ -30,8 +30,14 @@ + #include "llvm/Analysis/DebugInfo.h" + #include "llvm/Analysis/Dominators.h" + #include "llvm/Analysis/ConstantFolding.h" +-#include "llvm/Analysis/LiveValues.h" ++//#include "llvm/Analysis/LiveValues.h" ++// ++#ifdef LLVM29 ++#include "llvm/Analysis/ValueTracking.h" ++#include "PointerTracking.h" ++#else + #include "llvm/Analysis/PointerTracking.h" ++#endif + #include "llvm/Analysis/ScalarEvolution.h" + #include "llvm/Analysis/ScalarEvolutionExpressions.h" + #include "llvm/Analysis/ScalarEvolutionExpander.h" +@@ -54,13 +60,22 @@ + #include "llvm/Transforms/Utils/BasicBlockUtils.h" + #include "llvm/Support/Debug.h" + ++#ifndef LLVM28 + #define LLVM28 ++#endif + #ifdef LLVM28 + #define DEFINEPASS(passname) passname() : FunctionPass(ID) + #else + #define DEFINEPASS(passname) passname() : FunctionPass(&ID) + #endif ++ + using namespace llvm; ++#ifndef LLVM29 ++static Value *GetUnderlyingObject(Value *P, TargetData *TD) ++{ ++ return P->getUnderlyingObject(); ++} ++#endif + namespace { + + class PtrVerifier : public FunctionPass { +@@ -275,7 +290,7 @@ namespace { + if (BaseMap.count(P)) { + return BaseMap[Ptr] = BaseMap[P]; + } +- Value *P2 = P->getUnderlyingObject(); ++ Value *P2 = GetUnderlyingObject(P, TD); + if (P2 != P) { + Value *V = getPointerBase(P2); + return BaseMap[Ptr] = V; +@@ -334,7 +349,7 @@ namespace { + } + } + if (LoadInst *LI = dyn_cast(Base)) { +- Value *V = LI->getPointerOperand()->stripPointerCasts()->getUnderlyingObject(); ++ Value *V = GetUnderlyingObject(LI->getPointerOperand()->stripPointerCasts(), TD); + if (Argument *A = dyn_cast(V)) { + if (A->getArgNo() == 0) { + // pointers from hidden ctx are trusted to be at least the +diff --git libclamav/c++/Makefile.am libclamav/c++/Makefile.am +index ec42741..415a02f 100644 +--- libclamav/c++/Makefile.am ++++ libclamav/c++/Makefile.am +@@ -33,10 +33,11 @@ if BUILD_EXTERNAL_LLVM + # we know this will be built with GNU make, so its safe to use GNU make specific + # $(shell ...) + #LLVM_DEPS=$(shell $(LLVM_CONFIG) --libfiles jit nativecodegen) +-libclamavcxx_la_CXXFLAGS = $(AM_CPPFLAGS) @LLVMCONFIG_CXXFLAGS@ -fexceptions -DLLVM28 ++libclamavcxx_la_CXXFLAGS = $(AM_CPPFLAGS) @LLVMCONFIG_CXXFLAGS@ -fexceptions -DLLVM28 -DLLVM29 + libclamavcxx_la_LDFLAGS = @LLVMCONFIG_LDFLAGS@ @LLVMCONFIG_LIBS@ + libclamavcxx_la_DEPENDENCIES = @LLVMCONFIG_LIBFILES@ + noinst_LTLIBRARIES = libclamavcxx.la ++libclamavcxx_la_SOURCES += PointerTracking.cpp + + else + AM_CPPFLAGS += $(LLVM_INCLUDES) $(LLVM_DEFS) +diff --git libclamav/c++/Makefile.in libclamav/c++/Makefile.in +index e30f278..72a3a52 100644 +--- libclamav/c++/Makefile.in ++++ libclamav/c++/Makefile.in +@@ -51,14 +51,15 @@ POST_UNINSTALL = : + build_triplet = @build@ + host_triplet = @host@ + target_triplet = @target@ +-@BUILD_EXTERNAL_LLVM_FALSE@am__append_1 = $(LLVM_INCLUDES) $(LLVM_DEFS) +-@BUILD_EXTERNAL_LLVM_FALSE@@BUILD_X86_TRUE@am__append_2 = libllvmx86codegen.la ++@BUILD_EXTERNAL_LLVM_TRUE@am__append_1 = PointerTracking.cpp ++@BUILD_EXTERNAL_LLVM_FALSE@am__append_2 = $(LLVM_INCLUDES) $(LLVM_DEFS) + @BUILD_EXTERNAL_LLVM_FALSE@@BUILD_X86_TRUE@am__append_3 = libllvmx86codegen.la + @BUILD_EXTERNAL_LLVM_FALSE@@BUILD_X86_TRUE@am__append_4 = libllvmx86codegen.la +-@BUILD_EXTERNAL_LLVM_FALSE@@BUILD_PPC_TRUE@am__append_5 = libllvmpowerpccodegen.la ++@BUILD_EXTERNAL_LLVM_FALSE@@BUILD_X86_TRUE@am__append_5 = libllvmx86codegen.la + @BUILD_EXTERNAL_LLVM_FALSE@@BUILD_PPC_TRUE@am__append_6 = libllvmpowerpccodegen.la + @BUILD_EXTERNAL_LLVM_FALSE@@BUILD_PPC_TRUE@am__append_7 = libllvmpowerpccodegen.la +-@BUILD_EXTERNAL_LLVM_FALSE@@MAINTAINER_MODE_TRUE@am__append_8 = $(TBLGENFILES) ++@BUILD_EXTERNAL_LLVM_FALSE@@BUILD_PPC_TRUE@am__append_8 = libllvmpowerpccodegen.la ++@BUILD_EXTERNAL_LLVM_FALSE@@MAINTAINER_MODE_TRUE@am__append_9 = $(TBLGENFILES) + @BUILD_EXTERNAL_LLVM_FALSE@@MAINTAINER_MODE_TRUE@noinst_PROGRAMS = tblgen$(EXEEXT) + subdir = . + DIST_COMMON = $(am__configure_deps) $(srcdir)/Makefile.am \ +@@ -81,8 +82,14 @@ CONFIG_HEADER = clamavcxx-config.h + CONFIG_CLEAN_FILES = + CONFIG_CLEAN_VPATH_FILES = + LTLIBRARIES = $(noinst_LTLIBRARIES) ++am__libclamavcxx_la_SOURCES_DIST = bytecode2llvm.cpp \ ++ ClamBCRTChecks.cpp ClamBCModule.h ClamBCDiagnostics.h \ ++ detect.cpp PointerTracking.cpp ++@BUILD_EXTERNAL_LLVM_TRUE@am__objects_1 = \ ++@BUILD_EXTERNAL_LLVM_TRUE@ libclamavcxx_la-PointerTracking.lo + am_libclamavcxx_la_OBJECTS = libclamavcxx_la-bytecode2llvm.lo \ +- libclamavcxx_la-ClamBCRTChecks.lo libclamavcxx_la-detect.lo ++ libclamavcxx_la-ClamBCRTChecks.lo libclamavcxx_la-detect.lo \ ++ $(am__objects_1) + libclamavcxx_la_OBJECTS = $(am_libclamavcxx_la_OBJECTS) + AM_V_lt = $(am__v_lt_$(V)) + am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY)) +@@ -798,7 +805,7 @@ SOURCES = $(libclamavcxx_la_SOURCES) $(libllvmcodegen_la_SOURCES) \ + $(libllvmjit_la_SOURCES) $(libllvmpowerpccodegen_la_SOURCES) \ + $(libllvmsystem_la_SOURCES) $(libllvmx86codegen_la_SOURCES) \ + $(tblgen_SOURCES) +-DIST_SOURCES = $(libclamavcxx_la_SOURCES) \ ++DIST_SOURCES = $(am__libclamavcxx_la_SOURCES_DIST) \ + $(am__libllvmcodegen_la_SOURCES_DIST) \ + $(am__libllvmjit_la_SOURCES_DIST) \ + $(am__libllvmpowerpccodegen_la_SOURCES_DIST) \ +@@ -958,38 +965,34 @@ LLVM_INCLUDES = -I$(top_srcdir)/llvm/include -I$(top_builddir)/llvm/include + # TODO: HP-UX should have -D_REENTRANT -D_HPUX_SOURCE + LLVM_DEFS = -D__STDC_LIMIT_MACROS -D__STDC_CONSTANT_MACROS -D_DEBUG -D_GNU_SOURCE + AM_CPPFLAGS = -I$(top_srcdir)/../.. -I$(top_srcdir)/.. \ +- -I$(top_builddir)/../../ $(am__append_1) ++ -I$(top_builddir)/../../ $(am__append_2) + AM_CXXFLAGS = $(LLVM_CXXFLAGS) -fno-exceptions + ACLOCAL_AMFLAGS = -I m4 +-libclamavcxx_la_SOURCES = bytecode2llvm.cpp\ +- ClamBCRTChecks.cpp\ +- ClamBCModule.h\ +- ClamBCDiagnostics.h\ +- detect.cpp +- ++libclamavcxx_la_SOURCES = bytecode2llvm.cpp ClamBCRTChecks.cpp \ ++ ClamBCModule.h ClamBCDiagnostics.h detect.cpp $(am__append_1) + @BUILD_EXTERNAL_LLVM_FALSE@libclamavcxx_la_CXXFLAGS = $(LLVM_CXXFLAGS) + #$(LLVM_CONFIG): build-llvm + # we know this will be built with GNU make, so its safe to use GNU make specific + # $(shell ...) + #LLVM_DEPS=$(shell $(LLVM_CONFIG) --libfiles jit nativecodegen) +-@BUILD_EXTERNAL_LLVM_TRUE@libclamavcxx_la_CXXFLAGS = $(AM_CPPFLAGS) @LLVMCONFIG_CXXFLAGS@ -fexceptions -DLLVM28 ++@BUILD_EXTERNAL_LLVM_TRUE@libclamavcxx_la_CXXFLAGS = $(AM_CPPFLAGS) @LLVMCONFIG_CXXFLAGS@ -fexceptions -DLLVM28 -DLLVM29 + @BUILD_EXTERNAL_LLVM_FALSE@libclamavcxx_la_LDFLAGS = -no-undefined + @BUILD_EXTERNAL_LLVM_TRUE@libclamavcxx_la_LDFLAGS = @LLVMCONFIG_LDFLAGS@ @LLVMCONFIG_LIBS@ + @BUILD_EXTERNAL_LLVM_FALSE@libclamavcxx_la_DEPENDENCIES = \ + @BUILD_EXTERNAL_LLVM_FALSE@ libllvmjit.la libllvmcodegen.la \ +-@BUILD_EXTERNAL_LLVM_FALSE@ libllvmsystem.la $(am__append_3) \ +-@BUILD_EXTERNAL_LLVM_FALSE@ $(am__append_6) ++@BUILD_EXTERNAL_LLVM_FALSE@ libllvmsystem.la $(am__append_4) \ ++@BUILD_EXTERNAL_LLVM_FALSE@ $(am__append_7) + @BUILD_EXTERNAL_LLVM_TRUE@libclamavcxx_la_DEPENDENCIES = \ + @BUILD_EXTERNAL_LLVM_TRUE@ @LLVMCONFIG_LIBFILES@ \ +-@BUILD_EXTERNAL_LLVM_TRUE@ $(am__append_3) $(am__append_6) ++@BUILD_EXTERNAL_LLVM_TRUE@ $(am__append_4) $(am__append_7) + @BUILD_EXTERNAL_LLVM_FALSE@noinst_LTLIBRARIES = libclamavcxx.la \ + @BUILD_EXTERNAL_LLVM_FALSE@ libllvmsystem.la libllvmcodegen.la \ +-@BUILD_EXTERNAL_LLVM_FALSE@ libllvmjit.la $(am__append_4) \ +-@BUILD_EXTERNAL_LLVM_FALSE@ $(am__append_7) ++@BUILD_EXTERNAL_LLVM_FALSE@ libllvmjit.la $(am__append_5) \ ++@BUILD_EXTERNAL_LLVM_FALSE@ $(am__append_8) + @BUILD_EXTERNAL_LLVM_TRUE@noinst_LTLIBRARIES = libclamavcxx.la \ +-@BUILD_EXTERNAL_LLVM_TRUE@ $(am__append_4) $(am__append_7) ++@BUILD_EXTERNAL_LLVM_TRUE@ $(am__append_5) $(am__append_8) + @BUILD_EXTERNAL_LLVM_FALSE@libclamavcxx_la_LIBADD = libllvmjit.la \ +-@BUILD_EXTERNAL_LLVM_FALSE@ $(am__append_2) $(am__append_5) \ ++@BUILD_EXTERNAL_LLVM_FALSE@ $(am__append_3) $(am__append_6) \ + @BUILD_EXTERNAL_LLVM_FALSE@ libllvmcodegen.la libllvmsystem.la + @BUILD_EXTERNAL_LLVM_FALSE@LLVM_CXXFLAGS = -Woverloaded-virtual -pedantic -Wno-long-long -Wall -W -Wno-unused-parameter -Wwrite-strings + @BUILD_EXTERNAL_LLVM_FALSE@unittest_CXXFLAGS = @NO_VARIADIC_MACROS@ @NO_MISSING_FIELD_INITIALIZERS@ -DGTEST_HAS_TR1_TUPLE=0 +@@ -1001,7 +1004,7 @@ libclamavcxx_la_SOURCES = bytecode2llvm.cpp\ + + # Rule to rerun LLVM's configure if it changed, before building anything else + # LLVM +-@BUILD_EXTERNAL_LLVM_FALSE@BUILT_SOURCES = $(am__append_8) \ ++@BUILD_EXTERNAL_LLVM_FALSE@BUILT_SOURCES = $(am__append_9) \ + @BUILD_EXTERNAL_LLVM_FALSE@ llvm/config.status + @BUILD_EXTERNAL_LLVM_FALSE@EXTRA_DIST = $(top_srcdir)/llvm llvmcheck.sh $(TBLGENFILES) + @BUILD_EXTERNAL_LLVM_FALSE@libllvmsystem_la_LDFLAGS = @THREAD_LIBS@ +@@ -1776,6 +1779,7 @@ distclean-compile: + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/VirtRegRewriter.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/circular_raw_ostream.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamavcxx_la-ClamBCRTChecks.Plo@am__quote@ ++@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamavcxx_la-PointerTracking.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamavcxx_la-bytecode2llvm.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libclamavcxx_la-detect.Plo@am__quote@ + @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libllvmpowerpccodegen_la-PPCBranchSelector.Plo@am__quote@ +@@ -2070,6 +2074,14 @@ libclamavcxx_la-detect.lo: detect.cpp + @AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ + @am__fastdepCXX_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamavcxx_la_CXXFLAGS) $(CXXFLAGS) -c -o libclamavcxx_la-detect.lo `test -f 'detect.cpp' || echo '$(srcdir)/'`detect.cpp + ++libclamavcxx_la-PointerTracking.lo: PointerTracking.cpp ++@am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamavcxx_la_CXXFLAGS) $(CXXFLAGS) -MT libclamavcxx_la-PointerTracking.lo -MD -MP -MF $(DEPDIR)/libclamavcxx_la-PointerTracking.Tpo -c -o libclamavcxx_la-PointerTracking.lo `test -f 'PointerTracking.cpp' || echo '$(srcdir)/'`PointerTracking.cpp ++@am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libclamavcxx_la-PointerTracking.Tpo $(DEPDIR)/libclamavcxx_la-PointerTracking.Plo ++@am__fastdepCXX_FALSE@ $(AM_V_CXX) @AM_BACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCXX_FALSE@ source='PointerTracking.cpp' object='libclamavcxx_la-PointerTracking.lo' libtool=yes @AMDEPBACKSLASH@ ++@AMDEP_TRUE@@am__fastdepCXX_FALSE@ DEPDIR=$(DEPDIR) $(CXXDEPMODE) $(depcomp) @AMDEPBACKSLASH@ ++@am__fastdepCXX_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(libclamavcxx_la_CXXFLAGS) $(CXXFLAGS) -c -o libclamavcxx_la-PointerTracking.lo `test -f 'PointerTracking.cpp' || echo '$(srcdir)/'`PointerTracking.cpp ++ + ConstantFolding.lo: llvm/lib/Analysis/ConstantFolding.cpp + @am__fastdepCXX_TRUE@ $(AM_V_CXX)$(LIBTOOL) $(AM_V_lt) --tag=CXX $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CXX) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CXXFLAGS) $(CXXFLAGS) -MT ConstantFolding.lo -MD -MP -MF $(DEPDIR)/ConstantFolding.Tpo -c -o ConstantFolding.lo `test -f 'llvm/lib/Analysis/ConstantFolding.cpp' || echo '$(srcdir)/'`llvm/lib/Analysis/ConstantFolding.cpp + @am__fastdepCXX_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/ConstantFolding.Tpo $(DEPDIR)/ConstantFolding.Plo +diff --git libclamav/c++/PointerTracking.cpp libclamav/c++/PointerTracking.cpp +new file mode 100644 +index 0000000..4940648 +--- /dev/null ++++ libclamav/c++/PointerTracking.cpp +@@ -0,0 +1,321 @@ ++//===- PointerTracking.cpp - Pointer Bounds Tracking ------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This file implements tracking of pointer bounds. ++// ++//===----------------------------------------------------------------------===// ++ ++#include "llvm/Analysis/ConstantFolding.h" ++#include "llvm/Analysis/Dominators.h" ++#include "llvm/Analysis/LoopInfo.h" ++#include "llvm/Analysis/MemoryBuiltins.h" ++#include "llvm/Analysis/ValueTracking.h" ++#include "PointerTracking.h" ++#include "llvm/Analysis/ScalarEvolution.h" ++#include "llvm/Analysis/ScalarEvolutionExpressions.h" ++#include "llvm/Constants.h" ++#include "llvm/Module.h" ++#include "llvm/Value.h" ++#include "llvm/Support/CallSite.h" ++#include "llvm/Support/InstIterator.h" ++#include "llvm/Support/raw_ostream.h" ++#include "llvm/Target/TargetData.h" ++using namespace llvm; ++namespace llvm { ++ void initializePointerTrackingPass(llvm::PassRegistry&); ++}; ++INITIALIZE_PASS(PointerTracking, "pointertracking", ++ "Track pointer bounds", false, true); ++char PointerTracking::ID = 0; ++PointerTracking::PointerTracking() : FunctionPass(ID) { ++ initializePointerTrackingPass(*PassRegistry::getPassRegistry()); ++} ++ ++bool PointerTracking::runOnFunction(Function &F) { ++ predCache.clear(); ++ assert(analyzing.empty()); ++ FF = &F; ++ TD = getAnalysisIfAvailable(); ++ SE = &getAnalysis(); ++ LI = &getAnalysis(); ++ DT = &getAnalysis(); ++ return false; ++} ++ ++void PointerTracking::getAnalysisUsage(AnalysisUsage &AU) const { ++ AU.addRequiredTransitive(); ++ AU.addRequiredTransitive(); ++ AU.addRequiredTransitive(); ++ AU.setPreservesAll(); ++} ++ ++bool PointerTracking::doInitialization(Module &M) { ++ const Type *PTy = Type::getInt8PtrTy(M.getContext()); ++ ++ // Find calloc(i64, i64) or calloc(i32, i32). ++ callocFunc = M.getFunction("calloc"); ++ if (callocFunc) { ++ const FunctionType *Ty = callocFunc->getFunctionType(); ++ ++ std::vector args, args2; ++ args.push_back(Type::getInt64Ty(M.getContext())); ++ args.push_back(Type::getInt64Ty(M.getContext())); ++ args2.push_back(Type::getInt32Ty(M.getContext())); ++ args2.push_back(Type::getInt32Ty(M.getContext())); ++ const FunctionType *Calloc1Type = ++ FunctionType::get(PTy, args, false); ++ const FunctionType *Calloc2Type = ++ FunctionType::get(PTy, args2, false); ++ if (Ty != Calloc1Type && Ty != Calloc2Type) ++ callocFunc = 0; // Give up ++ } ++ ++ // Find realloc(i8*, i64) or realloc(i8*, i32). ++ reallocFunc = M.getFunction("realloc"); ++ if (reallocFunc) { ++ const FunctionType *Ty = reallocFunc->getFunctionType(); ++ std::vector args, args2; ++ args.push_back(PTy); ++ args.push_back(Type::getInt64Ty(M.getContext())); ++ args2.push_back(PTy); ++ args2.push_back(Type::getInt32Ty(M.getContext())); ++ ++ const FunctionType *Realloc1Type = ++ FunctionType::get(PTy, args, false); ++ const FunctionType *Realloc2Type = ++ FunctionType::get(PTy, args2, false); ++ if (Ty != Realloc1Type && Ty != Realloc2Type) ++ reallocFunc = 0; // Give up ++ } ++ return false; ++} ++ ++// Calculates the number of elements allocated for pointer P, ++// the type of the element is stored in Ty. ++const SCEV *PointerTracking::computeAllocationCount(Value *P, ++ const Type *&Ty) const { ++ Value *V = P->stripPointerCasts(); ++ if (AllocaInst *AI = dyn_cast(V)) { ++ Value *arraySize = AI->getArraySize(); ++ Ty = AI->getAllocatedType(); ++ // arraySize elements of type Ty. ++ return SE->getSCEV(arraySize); ++ } ++ ++ if (CallInst *CI = extractMallocCall(V)) { ++ Value *arraySize = getMallocArraySize(CI, TD); ++ const Type* AllocTy = getMallocAllocatedType(CI); ++ if (!AllocTy || !arraySize) return SE->getCouldNotCompute(); ++ Ty = AllocTy; ++ // arraySize elements of type Ty. ++ return SE->getSCEV(arraySize); ++ } ++ ++ if (GlobalVariable *GV = dyn_cast(V)) { ++ if (GV->hasDefinitiveInitializer()) { ++ Constant *C = GV->getInitializer(); ++ if (const ArrayType *ATy = dyn_cast(C->getType())) { ++ Ty = ATy->getElementType(); ++ return SE->getConstant(Type::getInt32Ty(P->getContext()), ++ ATy->getNumElements()); ++ } ++ } ++ Ty = GV->getType(); ++ return SE->getConstant(Type::getInt32Ty(P->getContext()), 1); ++ //TODO: implement more tracking for globals ++ } ++ ++ if (CallInst *CI = dyn_cast(V)) { ++ CallSite CS(CI); ++ Function *F = dyn_cast(CS.getCalledValue()->stripPointerCasts()); ++ const Loop *L = LI->getLoopFor(CI->getParent()); ++ if (F == callocFunc) { ++ Ty = Type::getInt8Ty(P->getContext()); ++ // calloc allocates arg0*arg1 bytes. ++ return SE->getSCEVAtScope(SE->getMulExpr(SE->getSCEV(CS.getArgument(0)), ++ SE->getSCEV(CS.getArgument(1))), ++ L); ++ } else if (F == reallocFunc) { ++ Ty = Type::getInt8Ty(P->getContext()); ++ // realloc allocates arg1 bytes. ++ return SE->getSCEVAtScope(CS.getArgument(1), L); ++ } ++ } ++ ++ return SE->getCouldNotCompute(); ++} ++ ++Value *PointerTracking::computeAllocationCountValue(Value *P, const Type *&Ty) const ++{ ++ Value *V = P->stripPointerCasts(); ++ if (AllocaInst *AI = dyn_cast(V)) { ++ Ty = AI->getAllocatedType(); ++ // arraySize elements of type Ty. ++ return AI->getArraySize(); ++ } ++ ++ if (CallInst *CI = extractMallocCall(V)) { ++ Ty = getMallocAllocatedType(CI); ++ if (!Ty) ++ return 0; ++ Value *arraySize = getMallocArraySize(CI, TD); ++ if (!arraySize) { ++ Ty = Type::getInt8Ty(P->getContext()); ++ return CI->getArgOperand(0); ++ } ++ // arraySize elements of type Ty. ++ return arraySize; ++ } ++ ++ if (GlobalVariable *GV = dyn_cast(V)) { ++ if (GV->hasDefinitiveInitializer()) { ++ Constant *C = GV->getInitializer(); ++ if (const ArrayType *ATy = dyn_cast(C->getType())) { ++ Ty = ATy->getElementType(); ++ return ConstantInt::get(Type::getInt32Ty(P->getContext()), ++ ATy->getNumElements()); ++ } ++ } ++ Ty = cast(GV->getType())->getElementType(); ++ return ConstantInt::get(Type::getInt32Ty(P->getContext()), 1); ++ //TODO: implement more tracking for globals ++ } ++ ++ if (CallInst *CI = dyn_cast(V)) { ++ CallSite CS(CI); ++ Function *F = dyn_cast(CS.getCalledValue()->stripPointerCasts()); ++ if (F == reallocFunc) { ++ Ty = Type::getInt8Ty(P->getContext()); ++ // realloc allocates arg1 bytes. ++ return CS.getArgument(1); ++ } ++ } ++ ++ return 0; ++} ++ ++// Calculates the number of elements of type Ty allocated for P. ++const SCEV *PointerTracking::computeAllocationCountForType(Value *P, ++ const Type *Ty) ++ const { ++ const Type *elementTy; ++ const SCEV *Count = computeAllocationCount(P, elementTy); ++ if (isa(Count)) ++ return Count; ++ if (elementTy == Ty) ++ return Count; ++ ++ if (!TD) // need TargetData from this point forward ++ return SE->getCouldNotCompute(); ++ ++ uint64_t elementSize = TD->getTypeAllocSize(elementTy); ++ uint64_t wantSize = TD->getTypeAllocSize(Ty); ++ if (elementSize == wantSize) ++ return Count; ++ if (elementSize % wantSize) //fractional counts not possible ++ return SE->getCouldNotCompute(); ++ return SE->getMulExpr(Count, SE->getConstant(Count->getType(), ++ elementSize/wantSize)); ++} ++ ++const SCEV *PointerTracking::getAllocationElementCount(Value *V) const { ++ // We only deal with pointers. ++ const PointerType *PTy = cast(V->getType()); ++ return computeAllocationCountForType(V, PTy->getElementType()); ++} ++ ++const SCEV *PointerTracking::getAllocationSizeInBytes(Value *V) const { ++ return computeAllocationCountForType(V, Type::getInt8Ty(V->getContext())); ++} ++ ++// Helper for isLoopGuardedBy that checks the swapped and inverted predicate too ++enum SolverResult PointerTracking::isLoopGuardedBy(const Loop *L, ++ Predicate Pred, ++ const SCEV *A, ++ const SCEV *B) const { ++ if (SE->isLoopEntryGuardedByCond(L, Pred, A, B)) ++ return AlwaysTrue; ++ Pred = ICmpInst::getSwappedPredicate(Pred); ++ if (SE->isLoopEntryGuardedByCond(L, Pred, B, A)) ++ return AlwaysTrue; ++ ++ Pred = ICmpInst::getInversePredicate(Pred); ++ if (SE->isLoopEntryGuardedByCond(L, Pred, B, A)) ++ return AlwaysFalse; ++ Pred = ICmpInst::getSwappedPredicate(Pred); ++ if (SE->isLoopEntryGuardedByCond(L, Pred, A, B)) ++ return AlwaysTrue; ++ return Unknown; ++} ++ ++enum SolverResult PointerTracking::checkLimits(const SCEV *Offset, ++ const SCEV *Limit, ++ BasicBlock *BB) ++{ ++ //FIXME: merge implementation ++ return Unknown; ++} ++ ++void PointerTracking::getPointerOffset(Value *Pointer, Value *&Base, ++ const SCEV *&Limit, ++ const SCEV *&Offset) const ++{ ++ Pointer = Pointer->stripPointerCasts(); ++ Base = GetUnderlyingObject(Pointer, TD); ++ Limit = getAllocationSizeInBytes(Base); ++ if (isa(Limit)) { ++ Base = 0; ++ Offset = Limit; ++ return; ++ } ++ ++ Offset = SE->getMinusSCEV(SE->getSCEV(Pointer), SE->getSCEV(Base)); ++ if (isa(Offset)) { ++ Base = 0; ++ Limit = Offset; ++ } ++} ++ ++void PointerTracking::print(raw_ostream &OS, const Module* M) const { ++ // Calling some PT methods may cause caches to be updated, however ++ // this should be safe for the same reason its safe for SCEV. ++ PointerTracking &PT = *const_cast(this); ++ for (inst_iterator I=inst_begin(*FF), E=inst_end(*FF); I != E; ++I) { ++ if (!I->getType()->isPointerTy()) ++ continue; ++ Value *Base; ++ const SCEV *Limit, *Offset; ++ getPointerOffset(&*I, Base, Limit, Offset); ++ if (!Base) ++ continue; ++ ++ if (Base == &*I) { ++ const SCEV *S = getAllocationElementCount(Base); ++ OS << *Base << " ==> " << *S << " elements, "; ++ OS << *Limit << " bytes allocated\n"; ++ continue; ++ } ++ OS << &*I << " -- base: " << *Base; ++ OS << " offset: " << *Offset; ++ ++ enum SolverResult res = PT.checkLimits(Offset, Limit, I->getParent()); ++ switch (res) { ++ case AlwaysTrue: ++ OS << " always safe\n"; ++ break; ++ case AlwaysFalse: ++ OS << " always unsafe\n"; ++ break; ++ case Unknown: ++ OS << " <>\n"; ++ break; ++ } ++ } ++} ++ +diff --git libclamav/c++/PointerTracking.h libclamav/c++/PointerTracking.h +new file mode 100644 +index 0000000..6b49e18 +--- /dev/null ++++ libclamav/c++/PointerTracking.h +@@ -0,0 +1,132 @@ ++//===- PointerTracking.h - Pointer Bounds Tracking --------------*- C++ -*-===// ++// ++// The LLVM Compiler Infrastructure ++// ++// This file is distributed under the University of Illinois Open Source ++// License. See LICENSE.TXT for details. ++// ++//===----------------------------------------------------------------------===// ++// ++// This file implements tracking of pointer bounds. ++// It knows that the libc functions "calloc" and "realloc" allocate memory, thus ++// you should avoid using this pass if they mean something else for your ++// language. ++// ++// All methods assume that the pointer is not NULL, if it is then the returned ++// allocation size is wrong, and the result from checkLimits is wrong too. ++// It also assumes that pointers are valid, and that it is not analyzing a ++// use-after-free scenario. ++// Due to these limitations the "size" returned by these methods should be ++// considered as either 0 or the returned size. ++// ++// Another analysis pass should be used to find use-after-free/NULL dereference ++// bugs. ++// ++//===----------------------------------------------------------------------===// ++ ++#ifndef LLVM_ANALYSIS_POINTERTRACKING_H ++#define LLVM_ANALYSIS_POINTERTRACKING_H ++ ++#include "llvm/ADT/SmallPtrSet.h" ++#include "llvm/Analysis/Dominators.h" ++#include "llvm/Instructions.h" ++#include "llvm/Pass.h" ++#include "llvm/Support/PredIteratorCache.h" ++ ++namespace llvm { ++ class DominatorTree; ++ class ScalarEvolution; ++ class SCEV; ++ class Loop; ++ class LoopInfo; ++ class TargetData; ++ ++ // Result from solver, assuming pointer is not NULL, ++ // and it is not a use-after-free situation. ++ enum SolverResult { ++ AlwaysFalse,// always false with above constraints ++ AlwaysTrue,// always true with above constraints ++ Unknown // it can sometimes be true, sometimes false, or it is undecided ++ }; ++ ++ class PointerTracking : public FunctionPass { ++ public: ++ typedef ICmpInst::Predicate Predicate; ++ static char ID; ++ PointerTracking(); ++ ++ virtual bool doInitialization(Module &M); ++ ++ // If this pointer directly points to an allocation, return ++ // the number of elements of type Ty allocated. ++ // Otherwise return CouldNotCompute. ++ // Since allocations can fail by returning NULL, the real element count ++ // for every allocation is either 0 or the value returned by this function. ++ const SCEV *getAllocationElementCount(Value *P) const; ++ ++ // Same as getAllocationSize() but returns size in bytes. ++ // We consider one byte as 8 bits. ++ const SCEV *getAllocationSizeInBytes(Value *V) const; ++ ++ // Given a Pointer, determine a base pointer of known size, and an offset ++ // therefrom. ++ // When unable to determine, sets Base to NULL, and Limit/Offset to ++ // CouldNotCompute. ++ // BaseSize, and Offset are in bytes: Pointer == Base + Offset ++ void getPointerOffset(Value *Pointer, Value *&Base, const SCEV *& BaseSize, ++ const SCEV *&Offset) const; ++ ++ // Compares the 2 scalar evolution expressions according to predicate, ++ // and if it can prove that the result is always true or always false ++ // return AlwaysTrue/AlwaysFalse. Otherwise it returns Unknown. ++ enum SolverResult compareSCEV(const SCEV *A, Predicate Pred, const SCEV *B, ++ const Loop *L); ++ ++ // Determines whether the condition LHS RHS is sufficient ++ // for the condition A B to hold. ++ // Currently only ULT/ULE is supported. ++ // This errs on the side of returning false. ++ bool conditionSufficient(const SCEV *LHS, Predicate Pred1, const SCEV *RHS, ++ const SCEV *A, Predicate Pred2, const SCEV *B, ++ const Loop *L); ++ ++ // Determines whether Offset is known to be always in [0, Limit) bounds. ++ // This errs on the side of returning Unknown. ++ enum SolverResult checkLimits(const SCEV *Offset, const SCEV *Limit, ++ BasicBlock *BB); ++ ++ virtual bool runOnFunction(Function &F); ++ virtual void getAnalysisUsage(AnalysisUsage &AU) const; ++ void print(raw_ostream &OS, const Module* = 0) const; ++ Value *computeAllocationCountValue(Value *P, const Type *&Ty) const; ++ private: ++ Function *FF; ++ TargetData *TD; ++ ScalarEvolution *SE; ++ LoopInfo *LI; ++ DominatorTree *DT; ++ ++ Function *callocFunc; ++ Function *reallocFunc; ++ PredIteratorCache predCache; ++ ++ SmallPtrSet analyzing; ++ ++ enum SolverResult isLoopGuardedBy(const Loop *L, Predicate Pred, ++ const SCEV *A, const SCEV *B) const; ++ static bool isMonotonic(const SCEV *S); ++ bool scevPositive(const SCEV *A, const Loop *L, bool strict=true) const; ++ bool conditionSufficient(Value *Cond, bool negated, ++ const SCEV *A, Predicate Pred, const SCEV *B); ++ Value *getConditionToReach(BasicBlock *A, ++ DomTreeNodeBase *B, ++ bool &negated); ++ Value *getConditionToReach(BasicBlock *A, ++ BasicBlock *B, ++ bool &negated); ++ const SCEV *computeAllocationCount(Value *P, const Type *&Ty) const; ++ const SCEV *computeAllocationCountForType(Value *P, const Type *Ty) const; ++ }; ++} ++#endif ++ +diff --git libclamav/c++/bytecode2llvm.cpp libclamav/c++/bytecode2llvm.cpp +index a392876..ee060d0 100644 +--- libclamav/c++/bytecode2llvm.cpp ++++ libclamav/c++/bytecode2llvm.cpp +@@ -59,13 +59,29 @@ + #include "llvm/Support/SourceMgr.h" + #include "llvm/Support/IRBuilder.h" + #include "llvm/Support/PrettyStackTrace.h" ++ ++#ifdef LLVM29 ++#include "llvm/Support/DataTypes.h" ++#include "llvm/Support/FileSystem.h" ++#include "llvm/Support/Host.h" ++#include "llvm/Support/Memory.h" ++#include "llvm/Support/Mutex.h" ++#include "llvm/Support/Signals.h" ++#include "llvm/Support/Threading.h" ++#include "llvm/Support/ThreadLocal.h" ++#include "llvm/IntrinsicInst.h" ++#include "llvm/PassRegistry.h" ++#else + #include "llvm/System/DataTypes.h" + #include "llvm/System/Host.h" + #include "llvm/System/Memory.h" + #include "llvm/System/Mutex.h" + #include "llvm/System/Signals.h" +-#include "llvm/Support/Timer.h" + #include "llvm/System/Threading.h" ++#include "llvm/System/ThreadLocal.h" ++#endif ++ ++#include "llvm/Support/Timer.h" + + extern "C" { + void LLVMInitializeX86AsmPrinter(); +@@ -78,7 +94,6 @@ void LLVMInitializePowerPCAsmPrinter(); + #include "llvm/Transforms/Scalar.h" + #include "llvm/Transforms/IPO.h" + #include "llvm/Transforms/Utils/BasicBlockUtils.h" +-#include "llvm/System/ThreadLocal.h" + #include + #include + #include +@@ -133,6 +148,11 @@ struct cli_bcengine { + }; + + extern "C" uint8_t cli_debug_flag; ++#ifdef LLVM29 ++namespace llvm { ++ void initializeRuntimeLimitsPass(PassRegistry&); ++}; ++#endif + namespace { + + #ifndef LLVM28 +@@ -149,6 +169,10 @@ namespace { + #define DEFINEPASS(passname) passname() : FunctionPass(&ID) + #endif + ++#ifdef LLVM29 ++#define NORETURN LLVM_ATTRIBUTE_NORETURN ++#endif ++ + static sys::ThreadLocal ExceptionReturn; + + static void UpgradeCall(CallInst *&C, Function *Intr) +@@ -526,7 +550,12 @@ class RuntimeLimits : public FunctionPass { + + public: + static char ID; +- DEFINEPASS(RuntimeLimits) {} ++ DEFINEPASS(RuntimeLimits) { ++#ifdef LLVM29 ++ PassRegistry &Registry = *PassRegistry::getPassRegistry(); ++ initializeRuntimeLimitsPass(Registry); ++#endif ++ } + + virtual bool runOnFunction(Function &F) { + BBSetTy BackedgeTargets; +@@ -1043,12 +1072,18 @@ public: + // Have an alloca -> some instruction uses its address otherwise + // mem2reg would have converted it to an SSA register. + // Enable stack protector for this function. ++#ifndef LLVM29 ++ // LLVM 2.9 has broken SSP, it does a 'mov 0x28, $rax', which tries ++ // to read from the address 0x28 and crashes + F->addFnAttr(Attribute::StackProtectReq); ++#endif + } + // always add stackprotect attribute (bb #2239), so we know this + // function was verified. If there is no alloca it won't actually add + // stack protector in emitted code so this won't slow down the app. ++#ifndef LLVM29 + F->addFnAttr(Attribute::StackProtect); ++#endif + } + + Value *GEPOperand(Value *V) { +@@ -1830,6 +1865,13 @@ static void addFunctionProtos(struct CommonFunctions *CF, ExecutionEngine *EE, M + } + + } ++#ifdef LLVM29 ++INITIALIZE_PASS_BEGIN(RuntimeLimits, "rl", "Runtime Limits", false, false) ++INITIALIZE_PASS_DEPENDENCY(LoopInfo) ++INITIALIZE_PASS_DEPENDENCY(ScalarEvolution) ++INITIALIZE_PASS_DEPENDENCY(DominatorTree) ++INITIALIZE_PASS_END(RuntimeLimits, "rl" ,"Runtime Limits", false, false) ++#endif + + static pthread_mutex_t watchdog_mutex = PTHREAD_MUTEX_INITIALIZER; + static pthread_cond_t watchdog_cond = PTHREAD_COND_INITIALIZER; +@@ -2179,7 +2221,9 @@ int cli_bytecode_prepare_jit(struct cli_all_bc *bcs) + PM.add(createCFGSimplificationPass()); + PM.add(createGlobalOptimizerPass()); + PM.add(createConstantMergePass()); +- PM.add(new RuntimeLimits()); ++ ++ RuntimeLimits *RL = new RuntimeLimits(); ++ PM.add(RL); + TimerWrapper pmTimer2("Transform passes"); + pmTimer2.startTimer(); + PM.run(*M); +@@ -2327,7 +2371,17 @@ void cli_bytecode_debug_printsrc(const struct cli_bc_ctx *ctx) + if (I == LinePrinter.files.end()) { + lines = new linesTy; + std::string ErrorMessage; ++#ifdef LLVM29 ++ OwningPtr File; ++ error_code ec = MemoryBuffer::getFile(path, File); ++ if (ec) { ++ ErrorMessage = ec.message(); ++ lines->buffer = 0; ++ } else ++ lines->buffer = File.take(); ++#else + lines->buffer = MemoryBuffer::getFile(path, &ErrorMessage); ++#endif + if (!lines->buffer) { + errs() << "Unable to open file '" << path << "'\n"; + return ; +@@ -2401,6 +2455,117 @@ void stop(const char *msg, llvm::Function* F, llvm::Instruction* I) + } + } + ++#ifdef LLVM29 ++static Value *findDbgGlobalDeclare(GlobalVariable *V) { ++ const Module *M = V->getParent(); ++ NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.gv"); ++ if (!NMD) ++ return 0; ++ ++ for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { ++ DIDescriptor DIG(cast(NMD->getOperand(i))); ++ if (!DIG.isGlobalVariable()) ++ continue; ++ if (DIGlobalVariable(DIG).getGlobal() == V) ++ return DIG; ++ } ++ return 0; ++} ++ ++/// Find the debug info descriptor corresponding to this function. ++static Value *findDbgSubprogramDeclare(Function *V) { ++ const Module *M = V->getParent(); ++ NamedMDNode *NMD = M->getNamedMetadata("llvm.dbg.sp"); ++ if (!NMD) ++ return 0; ++ ++ for (unsigned i = 0, e = NMD->getNumOperands(); i != e; ++i) { ++ DIDescriptor DIG(cast(NMD->getOperand(i))); ++ if (!DIG.isSubprogram()) ++ continue; ++ if (DISubprogram(DIG).getFunction() == V) ++ return DIG; ++ } ++ return 0; ++} ++ ++/// Finds the llvm.dbg.declare intrinsic corresponding to this value if any. ++/// It looks through pointer casts too. ++static const DbgDeclareInst *findDbgDeclare(const Value *V) { ++ V = V->stripPointerCasts(); ++ ++ if (!isa(V) && !isa(V)) ++ return 0; ++ ++ const Function *F = NULL; ++ if (const Instruction *I = dyn_cast(V)) ++ F = I->getParent()->getParent(); ++ else if (const Argument *A = dyn_cast(V)) ++ F = A->getParent(); ++ ++ for (Function::const_iterator FI = F->begin(), FE = F->end(); FI != FE; ++FI) ++ for (BasicBlock::const_iterator BI = (*FI).begin(), BE = (*FI).end(); ++ BI != BE; ++BI) ++ if (const DbgDeclareInst *DDI = dyn_cast(BI)) ++ if (DDI->getAddress() == V) ++ return DDI; ++ ++ return 0; ++} ++static bool getLocationInfo(const Value *V, std::string &DisplayName, ++ std::string &Type, unsigned &LineNo, ++ std::string &File, std::string &Dir) { ++ DICompileUnit Unit; ++ DIType TypeD; ++ ++ if (GlobalVariable *GV = dyn_cast(const_cast(V))) { ++ Value *DIGV = findDbgGlobalDeclare(GV); ++ if (!DIGV) return false; ++ DIGlobalVariable Var(cast(DIGV)); ++ ++ StringRef D = Var.getDisplayName(); ++ if (!D.empty()) ++ DisplayName = D; ++ LineNo = Var.getLineNumber(); ++ Unit = Var.getCompileUnit(); ++ TypeD = Var.getType(); ++ } else if (Function *F = dyn_cast(const_cast(V))){ ++ Value *DIF = findDbgSubprogramDeclare(F); ++ if (!DIF) return false; ++ DISubprogram Var(cast(DIF)); ++ ++ StringRef D = Var.getDisplayName(); ++ if (!D.empty()) ++ DisplayName = D; ++ LineNo = Var.getLineNumber(); ++ Unit = Var.getCompileUnit(); ++ TypeD = Var.getType(); ++ } else { ++ const DbgDeclareInst *DDI = findDbgDeclare(V); ++ if (!DDI) return false; ++ DIVariable Var(cast(DDI->getVariable())); ++ ++ StringRef D = Var.getName(); ++ if (!D.empty()) ++ DisplayName = D; ++ LineNo = Var.getLineNumber(); ++ Unit = Var.getCompileUnit(); ++ TypeD = Var.getType(); ++ } ++ ++ StringRef T = TypeD.getName(); ++ if (!T.empty()) ++ Type = T; ++ StringRef F = Unit.getFilename(); ++ if (!F.empty()) ++ File = F; ++ StringRef D = Unit.getDirectory(); ++ if (!D.empty()) ++ Dir = D; ++ return true; ++} ++#endif ++ + void printValue(llvm::Value *V, bool a, bool b) { + std::string DisplayName; + std::string Type; +diff --git libclamav/c++/configure libclamav/c++/configure +index 4712599..1fc6c2e 100755 +--- libclamav/c++/configure ++++ libclamav/c++/configure +@@ -15370,8 +15370,8 @@ if test "${with_system_llvm+set}" = set; then : + *) + llvmconfig="$withval" + llvmver=`$llvmconfig --version` +- if test "$llvmver" != "2.8" -a "$llvmver" != "2.8svn" -a "$llvmver" != "2.8rc"; then +- as_fn_error $? "LLVM 2.8 or 2.8svn required, but \"$llvmver\" found" "$LINENO" 5 ++ if test "$llvmver" != "2.9"; then ++ as_fn_error $? "LLVM 2.9 required, but \"$llvmver\" found" "$LINENO" 5 + fi + LLVMCONFIG_CXXFLAGS=`$llvmconfig --cxxflags` + +diff --git libclamav/c++/configure.ac libclamav/c++/configure.ac +index c5b30ec..3ba5333 100644 +--- libclamav/c++/configure.ac ++++ libclamav/c++/configure.ac +@@ -59,8 +59,8 @@ AC_ARG_WITH([system-llvm], AC_HELP_STRING([-with-system-llvm], + *) + llvmconfig="$withval" + llvmver=`$llvmconfig --version` +- if test "$llvmver" != "2.8" -a "$llvmver" != "2.8svn" -a "$llvmver" != "2.8rc"; then +- AC_MSG_ERROR([LLVM 2.8 or 2.8svn required, but "$llvmver" found]) ++ if test "$llvmver" != "2.9"; then ++ AC_MSG_ERROR([LLVM 2.9 required, but "$llvmver" found]) + fi + AC_SUBST(LLVMCONFIG_CXXFLAGS, [`$llvmconfig --cxxflags`]) + AC_SUBST(LLVMCONFIG_LDFLAGS, [`$llvmconfig --ldflags`]) +diff --git libclamav/c++/detect.cpp libclamav/c++/detect.cpp +index c88fdfa..fdb86a2 100644 +--- libclamav/c++/detect.cpp ++++ libclamav/c++/detect.cpp +@@ -22,9 +22,16 @@ + + #include "llvm/ADT/Triple.h" + #include "llvm/Support/raw_ostream.h" ++#ifdef LLVM29 ++#include "llvm/Support/Host.h" ++#include "llvm/Support/DataTypes.h" ++#include "llvm/Support/Memory.h" ++#else + #include "llvm/System/Host.h" + #include "llvm/System/DataTypes.h" + #include "llvm/System/Memory.h" ++#endif ++ + #include "llvm/Config/config.h" + + extern "C" { +@@ -137,7 +144,9 @@ void cli_detect_env_jit(struct cli_environment *env) + CASE_OS(Linux, os_linux); + CASE_OS(Lv2, os_unknown); + CASE_OS(MinGW32, os_win32); ++#ifndef LLVM29 + CASE_OS(MinGW64, os_win64); ++#endif + CASE_OS(NetBSD, os_bsd); + CASE_OS(OpenBSD, os_bsd); + CASE_OS(Psp, os_unknown);