[Pkg-clamav-commits] [SCM] Debian repository for ClamAV branch, debian/unstable, updated. debian/0.95+dfsg-1-6156-g094ec9b
Török Edvin
edwin at clamav.net
Sun Apr 4 01:02:07 UTC 2010
The following commit has been merged in the debian/unstable branch:
commit d1487222f7529538c6e6489cdd0baf0de114b3e5
Author: Török Edvin <edwin at clamav.net>
Date: Tue Aug 25 18:54:14 2009 +0300
Draft of libclamav <-> jit communication.
diff --git a/clambc/bcrun.c b/clambc/bcrun.c
index 45f0af3..4f6b092 100644
--- a/clambc/bcrun.c
+++ b/clambc/bcrun.c
@@ -22,6 +22,7 @@
#if HAVE_CONFIG_H
#include "clamav-config.h"
#endif
+#include "cltypes.h"
#include "bytecode.h"
#include "clamav.h"
#include "shared/optparser.h"
@@ -52,6 +53,7 @@ int main(int argc, char *argv[])
int rc;
struct optstruct *opts;
unsigned funcid=0, i;
+ struct cli_all_bc bcs;
opts = optparse(NULL, argc, argv, 1, OPT_CLAMBC, 0, NULL);
if (!opts) {
@@ -83,6 +85,23 @@ int main(int argc, char *argv[])
}
cl_debug();
+ rc = cl_init(CL_INIT_DEFAULT);
+ if (rc != CL_SUCCESS) {
+ fprintf(stderr,"Unable to init libclamav: %s\n", cl_strerror(rc));
+ optfree(opts);
+ exit(4);
+ }
+
+ rc = cli_bytecode_init(&bcs);
+ if (rc != CL_SUCCESS) {
+ fprintf(stderr,"Unable to init bytecode engine: %s\n", cl_strerror(rc));
+ optfree(opts);
+ exit(4);
+ }
+
+ bcs.all_bcs = bc;
+ bcs.count = 1;
+
rc = cli_bytecode_load(bc, f, NULL);
if (rc != CL_SUCCESS) {
fprintf(stderr,"Unable to load bytecode: %s\n", cl_strerror(rc));
@@ -90,7 +109,7 @@ int main(int argc, char *argv[])
exit(4);
}
- rc = cli_bytecode_prepare(bc);
+ rc = cli_bytecode_prepare(&bcs);
if (rc != CL_SUCCESS) {
fprintf(stderr,"Unable to prepare bytecode: %s\n", cl_strerror(rc));
optfree(opts);
@@ -133,6 +152,7 @@ int main(int argc, char *argv[])
}
cli_bytecode_context_destroy(ctx);
cli_bytecode_destroy(bc);
+ cli_bytecode_done(&bcs);
free(bc);
optfree(opts);
printf("Exiting\n");
diff --git a/configure.in b/configure.in
index 6bbcea7..16c5eb3 100644
--- a/configure.in
+++ b/configure.in
@@ -56,6 +56,8 @@ AC_PROG_INSTALL
AC_PROG_LN_S
AC_PROG_MAKE_SET
+AC_CONFIG_LLVM
+
LT_CONFIG_LTDL_DIR([libltdl])
LT_INIT([dlopen])
LTDL_INIT([recursive])
@@ -351,8 +353,6 @@ main (void)
], [AC_MSG_RESULT([ok, bug not present])],
[AC_MSG_ERROR([your compiler has gcc PR37573 bug, use a lower optimization level (-O1 or -O2), see http://gcc.gnu.org/bugzilla/show_bug.cgi?id=37573])], [AC_MSG_RESULT([cross-compiling, assumed ok])])
-AC_CONFIG_LLVM
-
dnl Linker feature checks
dnl check for version script support in the linker (GNU ld, or Solaris ld style)
AC_CACHE_CHECK([for ld --version-script], [ac_cv_ld_version_script], [dnl
@@ -809,9 +809,12 @@ enable_debug=$enableval, enable_debug="no")
if test "$enable_debug" = "yes"; then
AC_DEFINE([CL_DEBUG],1,[enable debugging])
+ ac_configure_args="$ac_configure_args --disable-optimized"
else
AC_DEFINE([NDEBUG],1,[disable assertions])
+ ac_configure_args="$ac_configure_args --enable-optimized"
fi
+AM_CONDITIONAL([DEBUG_BUILD], test "x$enable_debug" = "xyes")
AC_ARG_ENABLE([no-cache],
[ --enable-no-cache use "Cache-Control: no-cache" in freshclam],
diff --git a/libclamav/Makefile.am b/libclamav/Makefile.am
index b52351a..aa7f0ec 100644
--- a/libclamav/Makefile.am
+++ b/libclamav/Makefile.am
@@ -20,10 +20,6 @@ AM_CPPFLAGS = -I$(top_srcdir) -I at srcdir@/nsis $(LTDLINCL)
lib_LTLIBRARIES =
EXTRA_DIST =
-if ENABLE_LLVM
-SUBDIRS = llvm
-endif
-
if ENABLE_UNRAR
AM_CPPFLAGS += -DWARN_DLOPEN_FAIL
@@ -115,7 +111,7 @@ libclamav_internal_utils_nothreads_la_LDFLAGS=-static
libclamav_internal_utils_nothreads_la_CFLAGS=-DCL_NOTHREADS
libclamav_la_LIBADD = @LIBLTDL@ $(IFACELIBADD) libclamav_internal_utils.la @LIBCLAMAV_LIBS@ @THREAD_LIBS@
-libclamav_la_DEPENDENCIES = @LTDLDEPS@ $(IFACEDEP) libclamav_internal_utils.la
+libclamav_la_DEPENDENCIES = @LTDLDEPS@ $(IFACEDEP) libclamav_internal_utils.la
libclamav_la_CFLAGS = -DSEARCH_LIBDIR=\"$(libdir)\"
libclamav_la_LDFLAGS = @TH_SAFE@ -version-info @LIBCLAMAV_VERSION@ -no-undefined
@@ -336,6 +332,24 @@ libclamav_la_SOURCES += bignum.c \
bignum_class.h
endif
+if ENABLE_LLVM
+
+SUBDIRS = llvm
+if DEBUG_BUILD
+LLVM_CONFIG=llvm/llvm/Debug/bin/llvm-config
+else
+LLVM_CONFIG=llvm/llvm/Release/bin/llvm-config
+endif
+libclamav_la_CPPFLAGS = $(AM_CPPFLAGS) `$(LLVM_CONFIG) --cppflags`
+libclamav_la_LDFLAGS += `$(LLVM_CONFIG) --ldflags --libs jit nativecodegen`
+libclamav_la_SOURCES += bytecode2llvm.cpp
+
+else
+
+libclamav_la_SOURCES += bytecode_nojit.c
+
+endif
+
.PHONY: version.h.tmp
version.c: version.h
version.h: version.h.tmp
diff --git a/libclamav/bytecode.c b/libclamav/bytecode.c
index 1e80813..8c3a586 100644
--- a/libclamav/bytecode.c
+++ b/libclamav/bytecode.c
@@ -1025,7 +1025,10 @@ int cli_bytecode_run(const struct cli_bc *bc, struct cli_bc_ctx *ctx)
inst.u.ops.funcid = ctx->funcid;
inst.u.ops.ops = ctx->operands;
inst.u.ops.opsizes = ctx->opsizes;
- return cli_vm_execute(ctx->bc, ctx, &func, &inst);
+ if (bc->state == bc_interp)
+ return cli_vm_execute(ctx->bc, ctx, &func, &inst);
+ else
+ return cli_vm_execute_jit(ctx->bc, ctx, &func, &inst);
}
uint64_t cli_bytecode_context_getresult_int(struct cli_bc_ctx *ctx)
@@ -1207,21 +1210,30 @@ static int cli_bytecode_prepare_interpreter(struct cli_bc *bc)
return CL_SUCCESS;
}
-static int cli_bytecode_prepare_jit(struct cli_bc *bc)
+int cli_bytecode_prepare(struct cli_all_bc *bcs)
{
- if (bc->state != bc_loaded) {
- cli_warnmsg("Cannot prepare for JIT, because it has already been converted to interpreter");
- return CL_EBYTECODE;
+ unsigned i;
+ int rc;
+ if (cli_bytecode_prepare_jit(bcs) == CL_SUCCESS)
+ return CL_SUCCESS;
+ for (i=0;i<bcs->count;i++) {
+ struct cli_bc *bc = &bcs->all_bcs[i];
+ if (bc->state == bc_interp || bc->state == bc_jit)
+ continue;
+ rc = cli_bytecode_prepare_interpreter(bc);
+ if (rc != CL_SUCCESS)
+ return rc;
}
- cli_warnmsg("JIT not yet implemented\n");
- return CL_EBYTECODE;
+ return CL_SUCCESS;
}
-int cli_bytecode_prepare(struct cli_bc *bc)
+int cli_bytecode_init(struct cli_all_bc *allbc)
{
- if (bc->state == bc_interp || bc->state == bc_jit)
- return CL_SUCCESS;
- if (cli_bytecode_prepare_jit(bc) == CL_SUCCESS)
- return CL_SUCCESS;
- return cli_bytecode_prepare_interpreter(bc);
+ memset(allbc, 0, sizeof(*allbc));
+ return cli_bytecode_init_jit(allbc);
+}
+
+int cli_bytecode_done(struct cli_all_bc *allbc)
+{
+ return cli_bytecode_done_jit(allbc);
}
diff --git a/libclamav/bytecode.h b/libclamav/bytecode.h
index 1721f98..2f596d1 100644
--- a/libclamav/bytecode.h
+++ b/libclamav/bytecode.h
@@ -23,8 +23,6 @@
#define BYTECODE_H
#include <stdio.h>
#include "clambc.h"
-#include "cltypes.h"
-#include "others.h"
struct cli_dbio;
struct cli_bc_ctx;
@@ -32,6 +30,8 @@ struct cli_bc_func;
struct cli_bc_value;
struct cli_bc_inst;
struct cli_bc_type;
+struct cli_bc_engine;
+struct bitset_tag;
enum bc_state {
bc_loaded,
@@ -50,7 +50,13 @@ struct cli_bc {
struct cli_bc_type *types;
enum bc_state state;
uint16_t start_tid;
- bitset_t *uses_apis;
+ struct bitset_tag *uses_apis;
+};
+
+struct cli_all_bc {
+ struct cli_bc *all_bcs;
+ unsigned count;
+ struct cli_bcengine *engine;
};
struct cli_bc_ctx *cli_bytecode_context_alloc(void);
@@ -61,9 +67,11 @@ int cli_bytecode_context_clear(struct cli_bc_ctx *ctx);
uint64_t cli_bytecode_context_getresult_int(struct cli_bc_ctx *ctx);
void cli_bytecode_context_destroy(struct cli_bc_ctx *ctx);
+int cli_bytecode_init(struct cli_all_bc *allbc);
int cli_bytecode_load(struct cli_bc *bc, FILE *f, struct cli_dbio *dbio);
-int cli_bytecode_prepare(struct cli_bc *bc);
+int cli_bytecode_prepare(struct cli_all_bc *allbc);
int cli_bytecode_run(const struct cli_bc *bc, struct cli_bc_ctx *ctx);
void cli_bytecode_destroy(struct cli_bc *bc);
+int cli_bytecode_done(struct cli_all_bc *allbc);
#endif
diff --git a/libclamav/bytecode2llvm.cpp b/libclamav/bytecode2llvm.cpp
new file mode 100644
index 0000000..63674b2
--- /dev/null
+++ b/libclamav/bytecode2llvm.cpp
@@ -0,0 +1,114 @@
+#include "llvm/Support/DataTypes.h"
+#include "llvm/System/Threading.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/ExecutionEngine/JIT.h"
+#include "llvm/LLVMContext.h"
+#include "llvm/System/Signals.h"
+#include "llvm/Target/TargetSelect.h"
+#include "llvm/Module.h"
+#include "llvm/ModuleProvider.h"
+#include <cstdlib>
+#include <new>
+
+#include "clamav.h"
+#include "clambc.h"
+#include "bytecode_priv.h"
+#include "bytecode.h"
+
+#define MODULE "libclamav JIT: "
+
+using namespace llvm;
+struct cli_bcengine {
+ ExecutionEngine *EE;
+ LLVMContext Context;
+
+};
+
+namespace {
+
+ void do_shutdown() {
+ llvm_shutdown();
+ }
+ void llvm_error_handler(void *user_data, const std::string &reason)
+ {
+ }
+}
+
+int cli_vm_execute_jit(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst)
+{
+ return 0;
+}
+
+int cli_bytecode_prepare_jit(struct cli_all_bc *bcs)
+{
+ // LLVM itself never throws exceptions, but operator new may throw bad_alloc
+ try {
+ Module *M = new Module("ClamAV jit module", bcs->engine->Context);
+ {
+ // Create the JIT.
+ std::string ErrorMsg;
+ EngineBuilder builder(M);
+ builder.setErrorStr(&ErrorMsg);
+ builder.setEngineKind(EngineKind::JIT);
+ builder.setOptLevel(CodeGenOpt::Aggressive);
+ ExecutionEngine *EE = bcs->engine->EE = builder.create();
+ if (!EE) {
+ if (!ErrorMsg.empty())
+ errs() << MODULE << "error creating execution engine: " << ErrorMsg << "\n";
+ else
+ errs() << MODULE << "JIT not registered?\n";
+ return CL_EBYTECODE;
+ }
+ EE->DisableLazyCompilation();
+
+ // compile all functions now, not lazily!
+ for (Module::iterator I = M->begin(), E = M->end(); I != E; ++I) {
+ Function *Fn = &*I;
+ if (!Fn->isDeclaration())
+ EE->getPointerToFunction(Fn);
+ }
+ }
+ return -1;
+ } catch (std::bad_alloc &badalloc) {
+ errs() << MODULE << badalloc.what() << "\n";
+ return CL_EMEM;
+ } catch (...) {
+ errs() << MODULE << "Unexpected unknown exception occurred.\n";
+ return CL_EBYTECODE;
+ }
+}
+
+int bytecode_init(void)
+{
+ llvm_install_error_handler(llvm_error_handler);
+ sys::PrintStackTraceOnErrorSignal();
+ atexit(do_shutdown);
+
+ llvm_start_multithreaded();
+
+ // If we have a native target, initialize it to ensure it is linked in and
+ // usable by the JIT.
+ InitializeNativeTarget();
+ return 0;
+}
+
+// Called once when loading a new set of BC files
+int cli_bytecode_init_jit(struct cli_all_bc *bcs)
+{
+ bcs->engine = (struct cli_bcengine*) malloc(sizeof(struct cli_bcengine));
+ if (!bcs->engine)
+ return CL_EMEM;
+ return 0;
+}
+
+int cli_bytecode_done_jit(struct cli_all_bc *bcs)
+{
+ if (bcs->engine->EE)
+ delete bcs->engine->EE;
+ free(bcs->engine);
+ bcs->engine = 0;
+ return 0;
+}
diff --git a/shared/fdpassing.h b/libclamav/bytecode_nojit.c
similarity index 53%
copy from shared/fdpassing.h
copy to libclamav/bytecode_nojit.c
index 8cac9b9..1c73e9d 100644
--- a/shared/fdpassing.h
+++ b/libclamav/bytecode_nojit.c
@@ -1,4 +1,6 @@
/*
+ * Load, and verify ClamAV bytecode.
+ *
* Copyright (C) 2009 Sourcefire, Inc.
*
* Authors: Török Edvin
@@ -17,37 +19,30 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
* MA 02110-1301, USA.
*/
-#ifndef FDPASSING_H
-#define FDPASSING_H
-
-#ifdef HAVE_FD_PASSING
-
-#ifdef FDPASS_NEED_XOPEN
-/* to expose BSD 4.4/Unix98 semantics instead of BSD 4.3 semantics */
-#define _XOPEN_SOURCE 500
-#endif
-
-#include <sys/types.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <sys/uio.h>
-
-/* Solaris 8 */
-#if !defined CMSG_SPACE || !defined CMSG_LEN
-#ifndef ALIGN
-#define ALIGN(len) len
-#endif
-
-#ifndef CMSG_SPACE
-#define CMSG_SPACE(len) (ALIGN(sizeof(struct cmsghdr)) + ALIGN(len))
-#endif
-
-#ifndef CMSG_LEN
-#define CMSG_LEN(len) (ALIGN(sizeof(struct cmsghdr)) + len)
-#endif
-#endif
-
-
-#endif
-#endif
+#include "bytecode.h"
+
+int cli_bytecode_prepare_jit(struct cli_bc *bc)
+{
+ if (bc->state != bc_loaded) {
+ cli_warnmsg("Cannot prepare for JIT, because it has already been converted to interpreter");
+ return CL_EBYTECODE;
+ }
+ cli_warnmsg("JIT not yet implemented\n");
+ return CL_EBYTECODE;
+}
+
+int cli_vm_execute_jit(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst)
+{
+ return CL_EBYTECODE;
+}
+
+int cli_bytecode_init_jit(struct cli_all_bc *allbc)
+{
+ return CL_SUCCESS;
+}
+
+int cli_bytecode_done_jit(struct cli_all_bc *allbc)
+{
+ return CL_SUCCESS;
+}
diff --git a/libclamav/bytecode_priv.h b/libclamav/bytecode_priv.h
index 052f89c..8387971 100644
--- a/libclamav/bytecode_priv.h
+++ b/libclamav/bytecode_priv.h
@@ -95,6 +95,20 @@ struct cli_bc_ctx {
uint16_t funcid;
unsigned numParams;
};
-
+struct cli_all_bc;
int cli_vm_execute(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst);
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+int cli_vm_execute_jit(const struct cli_bc *bc, struct cli_bc_ctx *ctx, const struct cli_bc_func *func, const struct cli_bc_inst *inst);
+int cli_bytecode_prepare_jit(struct cli_all_bc *bc);
+int cli_bytecode_init_jit(struct cli_all_bc *bc);
+int cli_bytecode_done_jit(struct cli_all_bc *bc);
+int bytecode_init(void);
+
+#ifdef __cplusplus
+}
+#endif
#endif
diff --git a/libclamav/libclamav.map b/libclamav/libclamav.map
index 870c19e..48f85be 100644
--- a/libclamav/libclamav.map
+++ b/libclamav/libclamav.map
@@ -155,6 +155,8 @@ CLAMAV_PRIVATE {
cli_bytecode_context_setparam_ptr;
cli_bytecode_context_getresult_int;
cli_bytecode_context_clear;
+ cli_bytecode_init;
+ cli_bytecode_done;
local:
*;
};
diff --git a/libclamav/llvm/GNUmakefile.in b/libclamav/llvm/GNUmakefile.in
index cde2dc8..311726a 100644
--- a/libclamav/llvm/GNUmakefile.in
+++ b/libclamav/llvm/GNUmakefile.in
@@ -1,11 +1,16 @@
all: build-llvm
build-llvm:
- $(MAKE) -C llvm ENABLE_OPTIMIZED=1 OPTIMIZE_OPTION=-O2 libs-only
+ $(MAKE) -C llvm OPTIMIZE_OPTION=-O2 libs-only
build-llvm-for-check:
- $(MAKE) -C llvm ENABLE_OPTIMIZED=1 OPTIMIZE_OPTION=-O2 tools-only
+ $(MAKE) -C llvm OPTIMIZE_OPTION=-O2 tools-only
-check: build-llvm-for-check
+install:
+clean:
+ $(MAKE) -C llvm clean
+
+check:
+check-llvm: build-llvm-for-check
$(MAKE) -C llvm check
$(MAKE) -C llvm unittests
diff --git a/libclamav/llvm/TODO.CLAMAV b/libclamav/llvm/TODO.CLAMAV
index c1f5324..d60d1fb 100644
--- a/libclamav/llvm/TODO.CLAMAV
+++ b/libclamav/llvm/TODO.CLAMAV
@@ -1 +1,15 @@
Convert to clamav's build system.
+
+Right now static linking of libclamav doesn't work with llvm parts for a number
+of reasons:
+1. llvm is not built with libtool, and it builds .a files (or .so files)
+2. if I link with .a files, that works for a .so (LLVM's .a files are PIC), but
+ the created libclamav.a will miss the .a files, so I'd need to install the llvm
+ .a files together with clamav's
+3. libtool solves this by putting individual .o files into the target libtool .a
+archive, but since I link against non-libtool archives it doesn't know how to do
+that
+4. if I link against a .so then obviously it is not static linking
+
+If llvm would be converted to clamav's buildsystem then static linking of
+libclamav would work.
diff --git a/libclamav/others.c b/libclamav/others.c
index b947d50..142c14c 100644
--- a/libclamav/others.c
+++ b/libclamav/others.c
@@ -269,10 +269,14 @@ const char *cl_strerror(int clerror)
int cl_init(unsigned int initoptions)
{
+ int rc;
/* put dlopen() stuff here, etc. */
if (lt_init() == 0) {
cli_rarload();
}
+ rc = bytecode_init();
+ if (rc)
+ return rc;
return CL_SUCCESS;
}
diff --git a/m4/llvm.m4 b/m4/llvm.m4
index bb292fc..0fdc0f8 100644
--- a/m4/llvm.m4
+++ b/m4/llvm.m4
@@ -1,4 +1,5 @@
AC_DEFUN([AC_CONFIG_LLVM],[
+AC_REQUIRE([AC_PROG_CXX])
dnl automatically enable LLVM if host environment is supported, and automatically
dnl disable it if not, unless the user explicitly enables or disables LLVM.
AC_ARG_ENABLE([llvm],AC_HELP_STRING([--enable-llvm],
@@ -6,15 +7,15 @@ AC_ARG_ENABLE([llvm],AC_HELP_STRING([--enable-llvm],
[enable_llvm=$enableval], [enable_llvm="auto"])
if test "$enable_llvm" = "auto"; then
AC_MSG_NOTICE([Checking whether we can build LLVM])
- if test -z "$CXX"; then
- AC_CHECK_TOOLS(GXX,[g++ c++ cxx])
- else
- GXX="$CXX";
+ AC_PROG_CXX([g++])
+ if test "$GXX" != "yes"; then
+ enable_llvm="no";
+ AC_MSG_NOTICE([GNU C++ compiler not found, not building LLVM])
fi
- gxx_version=`${GXX} -dumpversion`
+ gxx_version=`${CXX} -dumpversion`
if test "$?" -ne 0; then
enable_llvm="no";
- AC_MSG_NOTICE([GNU C++ compiler not found, not building LLVM])
+ AC_MSG_NOTICE([Unable to get GNU C++ compiler version, not building LLVM])
else
case "${gxx_version}" in
[012].*|3.[0123].*)
diff --git a/unit_tests/check_bytecode.c b/unit_tests/check_bytecode.c
index 9fc0eee..e52d95e 100644
--- a/unit_tests/check_bytecode.c
+++ b/unit_tests/check_bytecode.c
@@ -41,6 +41,7 @@ static void runtest(const char *file, uint64_t expected)
FILE *f;
struct cli_bc bc;
struct cli_bc_ctx *ctx;
+ struct cli_all_bc bcs;
uint64_t v;
fail_unless(fd >= 0, "retmagic open failed");
@@ -49,11 +50,17 @@ static void runtest(const char *file, uint64_t expected)
cl_debug();
+ rc = cli_bytecode_init(&bcs);
+ fail_unless(rc == CL_SUCCESS, "cli_bytecode_init failed");
+
+ bcs.all_bcs = &bc;
+ bcs.count = 1;
+
rc = cli_bytecode_load(&bc, f, NULL);
fail_unless(rc == CL_SUCCESS, "cli_bytecode_load failed");
fclose(f);
- rc = cli_bytecode_prepare(&bc);
+ rc = cli_bytecode_prepare(&bcs);
fail_unless(rc == CL_SUCCESS, "cli_bytecode_prepare failed");
ctx = cli_bytecode_context_alloc();
@@ -68,6 +75,7 @@ static void runtest(const char *file, uint64_t expected)
expected, v);
cli_bytecode_context_destroy(ctx);
cli_bytecode_destroy(&bc);
+ cli_bytecode_done(&bcs);
}
START_TEST (test_retmagic)
--
Debian repository for ClamAV
More information about the Pkg-clamav-commits
mailing list