[Pkg-clamav-devel] Bug#926171: unblock: clamav/0.101.2+dfsg-1

Sebastian Andrzej Siewior sebastian at breakpoint.cc
Mon Apr 1 13:42:00 BST 2019


Package: release.debian.org
User: release.debian.org at packages.debian.org
Usertags: unblock
Severity: normal

Please unblock package clamav.
This is the new upstream releases fixing 6 CVEs. Looking at the debdiff
(after removing auto generated files, copyright updates, white space
damage / reformatting) it seems also fix memory leaks in ARJ/PDF file
scanners. Those are mentioned in the "Fixes for the following assorted
bugs" in upstream[0] release notes.

unblock clamav/0.101.2+dfsg-1

[0] https://blog.clamav.net/2019/03/clamav-01012-and-01003-patches-have.html

Sebastian
-------------- next part --------------
diff -Nru clamav-0.101.1+dfsg/clamd/scanner.c clamav-0.101.2+dfsg/clamd/scanner.c
--- clamav-0.101.1+dfsg/clamd/scanner.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/clamd/scanner.c	2019-03-13 22:13:01.000000000 +0100
@@ -394,7 +394,7 @@
 	context.filename = fdstr;
 	context.virsize = 0;
 	context.scandata = NULL;
-	ret = cl_scandesc_callback(fd, NULL, &virname, scanned, engine, options, &context);
+	ret = cl_scandesc_callback(fd, conn->filename, &virname, scanned, engine, options, &context);
 	thrmgr_setactivetask(NULL, NULL);
 
 	if (thrmgr_group_need_terminate(conn->group)) {
@@ -568,7 +568,7 @@
 		context.filename = peer_addr;
 		context.virsize = 0;
 		context.scandata = NULL;
-		ret = cl_scandesc_callback(tmpd, NULL, &virname, scanned, engine, options, &context);
+		ret = cl_scandesc_callback(tmpd, tmpname, &virname, scanned, engine, options, &context);
 		thrmgr_setactivetask(NULL, NULL);
     } else {
     	ret = -1;
diff -Nru clamav-0.101.1+dfsg/configure.ac clamav-0.101.2+dfsg/configure.ac
--- clamav-0.101.1+dfsg/configure.ac	2019-01-07 22:16:54.000000000 +0100
+++ clamav-0.101.2+dfsg/configure.ac	2019-03-30 14:57:20.000000000 +0100
@@ -20,7 +22,7 @@
 AC_PREREQ([2.59])
 dnl For a release change [devel] to the real version [0.xy]
 dnl also change VERSION below
-AC_INIT([ClamAV], [0.101.1], [https://bugzilla.clamav.net/], [clamav], [https://www.clamav.net/])
+AC_INIT([ClamAV], [0.101.2], [https://bugzilla.clamav.net/], [clamav], [https://www.clamav.net/])
 
 dnl enable C++
 AC_PROG_CXX()
@@ -78,6 +80,7 @@
 build_configure_args=`echo "$ac_configure_args" | sed -e 's/[\"]//g'`
 AC_SUBST([BUILD_CONFIGURE_FLAGS], [$build_configure_args])
 
+m4_include([m4/reorganization/code_checks/fuzz.m4])
 m4_include([m4/reorganization/code_checks/functions.m4])
 m4_include([m4/reorganization/code_checks/mpool.m4])
 m4_include([m4/reorganization/code_checks/unit_tests.m4])
@@ -170,6 +173,7 @@
 etc/Makefile
 test/Makefile
 unit_tests/Makefile
+fuzz/Makefile
 clamdtop/Makefile
 clambc/Makefile
 libfreshclam/Makefile
diff -Nru clamav-0.101.1+dfsg/debian/changelog clamav-0.101.2+dfsg/debian/changelog
--- clamav-0.101.1+dfsg/debian/changelog	2019-02-28 23:36:02.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/changelog	2019-03-30 16:25:48.000000000 +0100
@@ -1,3 +1,26 @@
+clamav (0.101.2+dfsg-1) unstable; urgency=high
+
+  * Import 0.101.2
+   - CVE-2019-1787 (An out-of-bounds heap read condition may occur when
+     scanning PDF documents)
+   - CVE-2019-1789 (An out-of-bounds heap read condition may occur when
+     scanning PE files)
+   - CVE-2019-1788 (An out-of-bounds heap write condition may occur when
+     scanning OLE2 files)
+   - CVE-2019-1786 (An out-of-bounds heap read condition may occur when
+     scanning malformed PDF documents)
+   - CVE-2019-1785 (A path-traversal write condition may occur as a result of
+     improper input validation when scanning RAR archives)
+   - CVE-2019-1798 (A use-after-free condition may occur as a result of
+     improper error handling when scanning nested RAR archives)
+   - update symbols file
+   - Remove DetectBrokenExecutables option from clamd template, it is
+     deprecated.
+  * Drop the dbgsym migration line.
+  * Bump standards-version to 4.3.0 without further change
+
+ -- Sebastian Andrzej Siewior <sebastian at breakpoint.cc>  Sat, 30 Mar 2019 16:25:48 +0100
+
 clamav (0.101.1+dfsg-3) unstable; urgency=medium
 
   * Upload to unstable.
diff -Nru clamav-0.101.1+dfsg/debian/clamav-daemon.postinst.in clamav-0.101.2+dfsg/debian/clamav-daemon.postinst.in
--- clamav-0.101.1+dfsg/debian/clamav-daemon.postinst.in	2019-01-10 23:33:34.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/clamav-daemon.postinst.in	2019-03-30 16:04:35.000000000 +0100
@@ -197,7 +197,6 @@
     [ -z "$DisableCache" ] && DisableCache=false
     [ -z "$ScanPE" ] && ScanPE=true
     [ -z "$ScanELF" ] && ScanELF=true
-    [ -z "$DetectBrokenExecutables" ] && DetectBrokenExecutables=false
     [ -z "$ScanOLE2" ] && ScanOLE2=true
     [ -z "$OLE2BlockMacros" ] && OLE2BlockMacros=false
     [ -z "$OnAccessExcludeRootUID" ] && OnAccessExcludeRootUID=no
@@ -307,7 +306,6 @@
 MaxScriptNormalize $MaxScriptNormalize
 MaxZipTypeRcg $MaxZipTypeRcg
 ScanSWF $ScanSWF
-DetectBrokenExecutables $DetectBrokenExecutables
 ExitOnOOM $ExitOnOOM
 LeaveTemporaryFiles $LeaveTemporaryFiles
 AlgorithmicDetection $AlgorithmicDetection
diff -Nru clamav-0.101.1+dfsg/debian/clamav-testfiles.lintian-overrides clamav-0.101.2+dfsg/debian/clamav-testfiles.lintian-overrides
--- clamav-0.101.1+dfsg/debian/clamav-testfiles.lintian-overrides	2019-01-07 23:18:26.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/clamav-testfiles.lintian-overrides	2019-03-30 16:25:48.000000000 +0100
@@ -1,2 +1,4 @@
 # This is intentionally shipped compressed and uncompressed to be able to test, if clamav detects also the compressed file.
 clamav-testfiles: duplicated-compressed-file usr/share/clamav-testfiles/clam.exe.bz2
+# These executable are test files for clamav (they are not executed otherwise).
+clamav-testfiles: portable-executable-missing-security-features usr/share/clamav-testfiles/*.exe *
diff -Nru clamav-0.101.1+dfsg/debian/control clamav-0.101.2+dfsg/debian/control
--- clamav-0.101.1+dfsg/debian/control	2019-01-09 23:34:23.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/control	2019-03-30 16:25:48.000000000 +0100
@@ -30,7 +30,7 @@
                po-debconf,
                python:native,
                zlib1g-dev
-Standards-Version: 4.1.5
+Standards-Version: 4.3.0
 Rules-Requires-Root: no
 Vcs-Git: https://salsa.debian.org/clamav-team/clamav.git
 Vcs-Browser: https://salsa.debian.org/clamav-team/clamav
diff -Nru clamav-0.101.1+dfsg/debian/copyright clamav-0.101.2+dfsg/debian/copyright
--- clamav-0.101.1+dfsg/debian/copyright	2019-01-07 23:18:26.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/copyright	2019-03-30 16:25:48.000000000 +0100
@@ -89,7 +89,6 @@
  clamdscan/Makefile.am
  clamscan/Makefile.am
  database/Makefile.am
- docs/clamdoc.tex
  docs/Makefile.am
  etc/Makefile.am
  examples/ex1.c
@@ -106,7 +105,6 @@
  libclamav/Makefile.am
  libclamav/c++/configure.ac
  libclamav/c++/Makefile.am
- libclamunrar_iface/Makefile.am
  Makefile.am
  sigtool/Makefile.am
  sigtool/vba.c
@@ -270,7 +268,7 @@
 Files:
  libclamav/mspack.c
  libclamav/mspack.h
- libclamunrar_iface/unrar_iface.c
+ libclamunrar_iface/unrar_iface.cpp
  libclamunrar_iface/unrar_iface.h
 Copyright:
  2003-2004 Stuart Caie
@@ -436,7 +434,6 @@
  libclamav/c++/aclocal.m4
  libclamav/c++/Makefile.in
  libclamav/Makefile.in
- libclamunrar_iface/Makefile.in
  libltdl/Makefile.in
  Makefile.in
  shared/Makefile.in
diff -Nru clamav-0.101.1+dfsg/debian/.git-dpm clamav-0.101.2+dfsg/debian/.git-dpm
--- clamav-0.101.1+dfsg/debian/.git-dpm	2019-01-07 23:18:28.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/.git-dpm	2019-03-30 15:32:49.000000000 +0100
@@ -1,8 +1,8 @@
 # see git-dpm(1) from git-dpm package
-9ddcc71e6832d0c6ddd675d2dca3bb4758e4d7c9
-9ddcc71e6832d0c6ddd675d2dca3bb4758e4d7c9
-beeb989a01d8d941f1408bc7d7792aa985e872dd
-beeb989a01d8d941f1408bc7d7792aa985e872dd
-clamav_0.101.1+dfsg.orig.tar.xz
-0db5f62275b81d9fea65fe07990a75d64a32769f
-4987424
+cb77f255d9bc2871a474227e2a8676dfd930a483
+cb77f255d9bc2871a474227e2a8676dfd930a483
+5a612c89e68e5010b2cd71002ceb15efc03a2324
+5a612c89e68e5010b2cd71002ceb15efc03a2324
+clamav_0.101.2+dfsg.orig.tar.xz
+7f723ff0a4ce24ef821947fd3832e3f54e17a875
+4719692
diff -Nru clamav-0.101.1+dfsg/debian/libclamav9.symbols clamav-0.101.2+dfsg/debian/libclamav9.symbols
--- clamav-0.101.1+dfsg/debian/libclamav9.symbols	2019-01-07 23:20:32.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/libclamav9.symbols	2019-03-30 16:25:48.000000000 +0100
@@ -1,16 +1,16 @@
 libclamav.so.9 libclamav9 #MINVER#
 * Build-Depends-Package: libclamav-dev
- CLAMAV_PRIVATE at CLAMAV_PRIVATE 0.101.1
+ CLAMAV_PRIVATE at CLAMAV_PRIVATE 0.101.2
  CLAMAV_PUBLIC at CLAMAV_PUBLIC 0.101.0
- base64Flush at CLAMAV_PRIVATE 0.101.1
- blobAddData at CLAMAV_PRIVATE 0.101.1
- blobCreate at CLAMAV_PRIVATE 0.101.1
- blobDestroy at CLAMAV_PRIVATE 0.101.1
- cl_ASN1_GetTimeT at CLAMAV_PRIVATE 0.101.1
+ base64Flush at CLAMAV_PRIVATE 0.101.2
+ blobAddData at CLAMAV_PRIVATE 0.101.2
+ blobCreate at CLAMAV_PRIVATE 0.101.2
+ blobDestroy at CLAMAV_PRIVATE 0.101.2
+ cl_ASN1_GetTimeT at CLAMAV_PRIVATE 0.101.2
  cl_always_gen_section_hash at CLAMAV_PUBLIC 0.101.0
- cl_base64_decode at CLAMAV_PRIVATE 0.101.1
- cl_base64_encode at CLAMAV_PRIVATE 0.101.1
- cl_cleanup_crypto at CLAMAV_PRIVATE 0.101.1
+ cl_base64_decode at CLAMAV_PRIVATE 0.101.2
+ cl_base64_encode at CLAMAV_PRIVATE 0.101.2
+ cl_cleanup_crypto at CLAMAV_PRIVATE 0.101.2
  cl_countsigs at CLAMAV_PUBLIC 0.101.0
  cl_cvdfree at CLAMAV_PUBLIC 0.101.0
  cl_cvdhead at CLAMAV_PUBLIC 0.101.0
@@ -50,19 +50,19 @@
  cl_fmap_close at CLAMAV_PUBLIC 0.101.0
  cl_fmap_open_handle at CLAMAV_PUBLIC 0.101.0
  cl_fmap_open_memory at CLAMAV_PUBLIC 0.101.0
- cl_get_pkey_file at CLAMAV_PRIVATE 0.101.1
- cl_get_x509_from_mem at CLAMAV_PRIVATE 0.101.1
- cl_hash_data at CLAMAV_PRIVATE 0.101.1
+ cl_get_pkey_file at CLAMAV_PRIVATE 0.101.2
+ cl_get_x509_from_mem at CLAMAV_PRIVATE 0.101.2
+ cl_hash_data at CLAMAV_PRIVATE 0.101.2
  cl_hash_destroy at CLAMAV_PUBLIC 0.101.0
- cl_hash_file_fd at CLAMAV_PRIVATE 0.101.1
- cl_hash_file_fd_ctx at CLAMAV_PRIVATE 0.101.1
- cl_hash_file_fp at CLAMAV_PRIVATE 0.101.1
+ cl_hash_file_fd at CLAMAV_PRIVATE 0.101.2
+ cl_hash_file_fd_ctx at CLAMAV_PRIVATE 0.101.2
+ cl_hash_file_fp at CLAMAV_PRIVATE 0.101.2
  cl_hash_init at CLAMAV_PUBLIC 0.101.0
  cl_init at CLAMAV_PUBLIC 0.101.0
- cl_initialize_crypto at CLAMAV_PRIVATE 0.101.1
+ cl_initialize_crypto at CLAMAV_PRIVATE 0.101.2
  cl_load at CLAMAV_PUBLIC 0.101.0
- cl_load_cert at CLAMAV_PRIVATE 0.101.1
- cl_load_crl at CLAMAV_PRIVATE 0.101.1
+ cl_load_cert at CLAMAV_PRIVATE 0.101.2
+ cl_load_crl at CLAMAV_PRIVATE 0.101.2
  cl_retdbdir at CLAMAV_PUBLIC 0.101.0
  cl_retflevel at CLAMAV_PUBLIC 0.101.1
  cl_retver at CLAMAV_PUBLIC 0.101.0
@@ -72,182 +72,185 @@
  cl_scanfile_callback at CLAMAV_PUBLIC 0.101.0
  cl_scanmap_callback at CLAMAV_PUBLIC 0.101.0
  cl_set_clcb_msg at CLAMAV_PUBLIC 0.101.0
- cl_sha1 at CLAMAV_PRIVATE 0.101.1
- cl_sha256 at CLAMAV_PRIVATE 0.101.1
- cl_sign_data at CLAMAV_PRIVATE 0.101.1
- cl_sign_data_keyfile at CLAMAV_PRIVATE 0.101.1
- cl_sign_file_fd at CLAMAV_PRIVATE 0.101.1
- cl_sign_file_fp at CLAMAV_PRIVATE 0.101.1
+ cl_sha1 at CLAMAV_PRIVATE 0.101.2
+ cl_sha256 at CLAMAV_PRIVATE 0.101.2
+ cl_sign_data at CLAMAV_PRIVATE 0.101.2
+ cl_sign_data_keyfile at CLAMAV_PRIVATE 0.101.2
+ cl_sign_file_fd at CLAMAV_PRIVATE 0.101.2
+ cl_sign_file_fp at CLAMAV_PRIVATE 0.101.2
  cl_statchkdir at CLAMAV_PUBLIC 0.101.0
  cl_statfree at CLAMAV_PUBLIC 0.101.0
  cl_statinidir at CLAMAV_PUBLIC 0.101.0
  cl_strerror at CLAMAV_PUBLIC 0.101.0
  cl_update_hash at CLAMAV_PUBLIC 0.101.0
- cl_validate_certificate_chain at CLAMAV_PRIVATE 0.101.1
- cl_validate_certificate_chain_ts_dir at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_fd at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_fd_x509 at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_fd_x509_keyfile at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_hash at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_hash_x509 at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_hash_x509_keyfile at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_x509 at CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_x509_keyfile at CLAMAV_PRIVATE 0.101.1
- cli_ac_buildtrie at CLAMAV_PRIVATE 0.101.1
- cli_ac_chklsig at CLAMAV_PRIVATE 0.101.1
- cli_ac_free at CLAMAV_PRIVATE 0.101.1
- cli_ac_freedata at CLAMAV_PRIVATE 0.101.1
- cli_ac_init at CLAMAV_PRIVATE 0.101.1
- cli_ac_initdata at CLAMAV_PRIVATE 0.101.1
- cli_ac_scanbuff at CLAMAV_PRIVATE 0.101.1
- cli_bm_free at CLAMAV_PRIVATE 0.101.1
- cli_bm_init at CLAMAV_PRIVATE 0.101.1
- cli_bm_scanbuff at CLAMAV_PRIVATE 0.101.1
- cli_build_regex_list at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_alloc at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_clear at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_destroy at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_getresult_int at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_set_trace at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setfile at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setfuncid at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setparam_int at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setparam_ptr at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_debug at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_debug_printsrc at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_describe at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_destroy at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_done at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_init at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_load at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_prepare2 at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_printversion at CLAMAV_PRIVATE 0.101.1
- cli_bytecode_run at CLAMAV_PRIVATE 0.101.1
- cli_bytefunc_describe at CLAMAV_PRIVATE 0.101.1
- cli_byteinst_describe at CLAMAV_PRIVATE 0.101.1
- cli_bytetype_describe at CLAMAV_PRIVATE 0.101.1
- cli_bytevalue_describe at CLAMAV_PRIVATE 0.101.1
- cli_calloc at CLAMAV_PRIVATE 0.101.1
- cli_checkfp_pe at CLAMAV_PRIVATE 0.101.1
- cli_chomp at CLAMAV_PRIVATE 0.101.1
- cli_ctime at CLAMAV_PRIVATE 0.101.1
- cli_cvdunpack at CLAMAV_PRIVATE 0.101.1
- cli_dbgmsg_internal at CLAMAV_PRIVATE 0.101.1
- cli_dconf_init at CLAMAV_PRIVATE 0.101.1
- cli_debug_flag at CLAMAV_PRIVATE 0.101.1
- cli_detect_environment at CLAMAV_PRIVATE 0.101.1
- cli_disasm_one at CLAMAV_PRIVATE 0.101.1
- cli_errmsg at CLAMAV_PRIVATE 0.101.1
- cli_filecopy at CLAMAV_PRIVATE 0.101.1
- cli_fmap_scandesc at CLAMAV_PRIVATE 0.101.1
- cli_ftw at CLAMAV_PRIVATE 0.101.1
- cli_genhash_pe at CLAMAV_PRIVATE 0.101.1
- cli_gentemp at CLAMAV_PRIVATE 0.101.1
- cli_gentempfd at CLAMAV_PRIVATE 0.101.1
- cli_gettmpdir at CLAMAV_PRIVATE 0.101.1
- cli_hashfile at CLAMAV_PRIVATE 0.101.1
- cli_hashset_destroy at CLAMAV_PRIVATE 0.101.1
- cli_hashstream at CLAMAV_PRIVATE 0.101.1
- cli_hex2str at CLAMAV_PRIVATE 0.101.1
- cli_hex2ui at CLAMAV_PRIVATE 0.101.1
- cli_initroots at CLAMAV_PRIVATE 0.101.1
- cli_isnumber at CLAMAV_PRIVATE 0.101.1
- cli_js_destroy at CLAMAV_PRIVATE 0.101.1
- cli_js_init at CLAMAV_PRIVATE 0.101.1
- cli_js_output at CLAMAV_PRIVATE 0.101.1
- cli_js_parse_done at CLAMAV_PRIVATE 0.101.1
- cli_js_process_buffer at CLAMAV_PRIVATE 0.101.1
- cli_ldbtokenize at CLAMAV_PRIVATE 0.101.1
- cli_malloc at CLAMAV_PRIVATE 0.101.1
- cli_memstr at CLAMAV_PRIVATE 0.101.1
- cli_ole2_extract at CLAMAV_PRIVATE 0.101.1
- cli_parse_add at CLAMAV_PRIVATE 0.101.1
- cli_pcre_build at CLAMAV_PRIVATE 0.101.1
- cli_pcre_freeoff at CLAMAV_PRIVATE 0.101.1
- cli_pcre_init at CLAMAV_PRIVATE 0.101.1
- cli_pcre_perf_events_destroy at CLAMAV_PRIVATE 0.101.1
- cli_pcre_perf_print at CLAMAV_PRIVATE 0.101.1
- cli_pcre_recaloff at CLAMAV_PRIVATE 0.101.1
- cli_pcre_scanbuf at CLAMAV_PRIVATE 0.101.1
- cli_ppt_vba_read at CLAMAV_PRIVATE 0.101.1
- cli_printcxxver at CLAMAV_PRIVATE 0.101.1
- cli_readn at CLAMAV_PRIVATE 0.101.1
- cli_realloc at CLAMAV_PRIVATE 0.101.1
- cli_regcomp at CLAMAV_PRIVATE 0.101.1
- cli_regex2suffix at CLAMAV_PRIVATE 0.101.1
- cli_regexec at CLAMAV_PRIVATE 0.101.1
- cli_regfree at CLAMAV_PRIVATE 0.101.1
- cli_rmdirs at CLAMAV_PRIVATE 0.101.1
- cli_rndnum at CLAMAV_PRIVATE 0.101.1
- cli_scanbuff at CLAMAV_PRIVATE 0.101.1
- cli_sigopts_handler at CLAMAV_PRIVATE 0.101.1
- cli_sigperf_events_destroy at CLAMAV_PRIVATE 0.101.1
- cli_sigperf_print at CLAMAV_PRIVATE 0.101.1
- cli_str2hex at CLAMAV_PRIVATE 0.101.1
- cli_strbcasestr at CLAMAV_PRIVATE 0.101.1
- cli_strdup at CLAMAV_PRIVATE 0.101.1
- cli_strerror at CLAMAV_PRIVATE 0.101.1
- cli_strlcat at CLAMAV_PRIVATE 0.101.1
- cli_strlcpy at CLAMAV_PRIVATE 0.101.1
- cli_strrcpy at CLAMAV_PRIVATE 0.101.1
- cli_strtok at CLAMAV_PRIVATE 0.101.1
- cli_strtokbuf at CLAMAV_PRIVATE 0.101.1
- cli_strtokenize at CLAMAV_PRIVATE 0.101.1
- cli_textbuffer_append_normalize at CLAMAV_PRIVATE 0.101.1
- cli_unescape at CLAMAV_PRIVATE 0.101.1
- cli_unlink at CLAMAV_PRIVATE 0.101.1
- cli_url_canon at CLAMAV_PRIVATE 0.101.1
- cli_utf16_to_utf8 at CLAMAV_PRIVATE 0.101.1
- cli_utf16toascii at CLAMAV_PRIVATE 0.101.1
- cli_vba_inflate at CLAMAV_PRIVATE 0.101.1
- cli_vba_readdir at CLAMAV_PRIVATE 0.101.1
- cli_versig2 at CLAMAV_PRIVATE 0.101.1
- cli_versig at CLAMAV_PRIVATE 0.101.1
- cli_warnmsg at CLAMAV_PRIVATE 0.101.1
- cli_wm_decrypt_macro at CLAMAV_PRIVATE 0.101.1
- cli_wm_readdir at CLAMAV_PRIVATE 0.101.1
- cli_writen at CLAMAV_PRIVATE 0.101.1
- decodeLine at CLAMAV_PRIVATE 0.101.1
- disasmbuf at CLAMAV_PRIVATE 0.101.1
- fmap at CLAMAV_PRIVATE 0.101.1
- get_fpu_endian at CLAMAV_PRIVATE 0.101.1
- have_clamjit at CLAMAV_PRIVATE 0.101.1
- have_rar at CLAMAV_PRIVATE 0.101.1
- html_normalise_map at CLAMAV_PRIVATE 0.101.1
- html_normalise_mem at CLAMAV_PRIVATE 0.101.1
- html_screnc_decode at CLAMAV_PRIVATE 0.101.1
- html_tag_arg_free at CLAMAV_PRIVATE 0.101.1
- init_domainlist at CLAMAV_PRIVATE 0.101.1
- init_regex_list at CLAMAV_PRIVATE 0.101.1
- init_whitelist at CLAMAV_PRIVATE 0.101.1
- is_regex_ok at CLAMAV_PRIVATE 0.101.1
- load_regex_matcher at CLAMAV_PRIVATE 0.101.1
+ cl_validate_certificate_chain at CLAMAV_PRIVATE 0.101.2
+ cl_validate_certificate_chain_ts_dir at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_fd at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_fd_x509 at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_fd_x509_keyfile at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_hash at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_hash_x509 at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_hash_x509_keyfile at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_x509 at CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_x509_keyfile at CLAMAV_PRIVATE 0.101.2
+ cli_ac_buildtrie at CLAMAV_PRIVATE 0.101.2
+ cli_ac_chklsig at CLAMAV_PRIVATE 0.101.2
+ cli_ac_free at CLAMAV_PRIVATE 0.101.2
+ cli_ac_freedata at CLAMAV_PRIVATE 0.101.2
+ cli_ac_init at CLAMAV_PRIVATE 0.101.2
+ cli_ac_initdata at CLAMAV_PRIVATE 0.101.2
+ cli_ac_scanbuff at CLAMAV_PRIVATE 0.101.2
+ cli_bm_free at CLAMAV_PRIVATE 0.101.2
+ cli_bm_init at CLAMAV_PRIVATE 0.101.2
+ cli_bm_scanbuff at CLAMAV_PRIVATE 0.101.2
+ cli_build_regex_list at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_alloc at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_clear at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_getresult_int at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_set_trace at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setfile at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setfuncid at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setparam_int at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setparam_ptr at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_debug at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_debug_printsrc at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_describe at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_done at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_init at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_load at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_prepare2 at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_printversion at CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_run at CLAMAV_PRIVATE 0.101.2
+ cli_bytefunc_describe at CLAMAV_PRIVATE 0.101.2
+ cli_byteinst_describe at CLAMAV_PRIVATE 0.101.2
+ cli_bytetype_describe at CLAMAV_PRIVATE 0.101.2
+ cli_bytevalue_describe at CLAMAV_PRIVATE 0.101.2
+ cli_calloc at CLAMAV_PRIVATE 0.101.2
+ cli_checkfp_pe at CLAMAV_PRIVATE 0.101.2
+ cli_chomp at CLAMAV_PRIVATE 0.101.2
+ cli_ctime at CLAMAV_PRIVATE 0.101.2
+ cli_cvdunpack at CLAMAV_PRIVATE 0.101.2
+ cli_dbgmsg_internal at CLAMAV_PRIVATE 0.101.2
+ cli_dconf_init at CLAMAV_PRIVATE 0.101.2
+ cli_debug_flag at CLAMAV_PRIVATE 0.101.2
+ cli_detect_environment at CLAMAV_PRIVATE 0.101.2
+ cli_disasm_one at CLAMAV_PRIVATE 0.101.2
+ cli_errmsg at CLAMAV_PRIVATE 0.101.2
+ cli_filecopy at CLAMAV_PRIVATE 0.101.2
+ cli_fmap_scandesc at CLAMAV_PRIVATE 0.101.2
+ cli_free_vba_project at CLAMAV_PRIVATE 0.101.2
+ cli_ftw at CLAMAV_PRIVATE 0.101.2
+ cli_genhash_pe at CLAMAV_PRIVATE 0.101.2
+ cli_gentemp at CLAMAV_PRIVATE 0.101.2
+ cli_gentempfd at CLAMAV_PRIVATE 0.101.2
+ cli_gettmpdir at CLAMAV_PRIVATE 0.101.2
+ cli_hashfile at CLAMAV_PRIVATE 0.101.2
+ cli_hashset_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_hashstream at CLAMAV_PRIVATE 0.101.2
+ cli_hex2str at CLAMAV_PRIVATE 0.101.2
+ cli_hex2ui at CLAMAV_PRIVATE 0.101.2
+ cli_initroots at CLAMAV_PRIVATE 0.101.2
+ cli_isnumber at CLAMAV_PRIVATE 0.101.2
+ cli_js_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_js_init at CLAMAV_PRIVATE 0.101.2
+ cli_js_output at CLAMAV_PRIVATE 0.101.2
+ cli_js_parse_done at CLAMAV_PRIVATE 0.101.2
+ cli_js_process_buffer at CLAMAV_PRIVATE 0.101.2
+ cli_ldbtokenize at CLAMAV_PRIVATE 0.101.2
+ cli_malloc at CLAMAV_PRIVATE 0.101.2
+ cli_memstr at CLAMAV_PRIVATE 0.101.2
+ cli_ole2_extract at CLAMAV_PRIVATE 0.101.2
+ cli_parse_add at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_build at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_freeoff at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_init at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_perf_events_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_perf_print at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_recaloff at CLAMAV_PRIVATE 0.101.2
+ cli_pcre_scanbuf at CLAMAV_PRIVATE 0.101.2
+ cli_ppt_vba_read at CLAMAV_PRIVATE 0.101.2
+ cli_printcxxver at CLAMAV_PRIVATE 0.101.2
+ cli_readn at CLAMAV_PRIVATE 0.101.2
+ cli_realloc at CLAMAV_PRIVATE 0.101.2
+ cli_regcomp at CLAMAV_PRIVATE 0.101.2
+ cli_regex2suffix at CLAMAV_PRIVATE 0.101.2
+ cli_regexec at CLAMAV_PRIVATE 0.101.2
+ cli_regfree at CLAMAV_PRIVATE 0.101.2
+ cli_rmdirs at CLAMAV_PRIVATE 0.101.2
+ cli_rndnum at CLAMAV_PRIVATE 0.101.2
+ cli_sanitize_filepath at CLAMAV_PRIVATE 0.101.2
+ cli_scanbuff at CLAMAV_PRIVATE 0.101.2
+ cli_sigopts_handler at CLAMAV_PRIVATE 0.101.2
+ cli_sigperf_events_destroy at CLAMAV_PRIVATE 0.101.2
+ cli_sigperf_print at CLAMAV_PRIVATE 0.101.2
+ cli_str2hex at CLAMAV_PRIVATE 0.101.2
+ cli_strbcasestr at CLAMAV_PRIVATE 0.101.2
+ cli_strdup at CLAMAV_PRIVATE 0.101.2
+ cli_strerror at CLAMAV_PRIVATE 0.101.2
+ cli_strlcat at CLAMAV_PRIVATE 0.101.2
+ cli_strlcpy at CLAMAV_PRIVATE 0.101.2
+ cli_strnstr at CLAMAV_PRIVATE 0.101.2
+ cli_strrcpy at CLAMAV_PRIVATE 0.101.2
+ cli_strtok at CLAMAV_PRIVATE 0.101.2
+ cli_strtokbuf at CLAMAV_PRIVATE 0.101.2
+ cli_strtokenize at CLAMAV_PRIVATE 0.101.2
+ cli_textbuffer_append_normalize at CLAMAV_PRIVATE 0.101.2
+ cli_unescape at CLAMAV_PRIVATE 0.101.2
+ cli_unlink at CLAMAV_PRIVATE 0.101.2
+ cli_url_canon at CLAMAV_PRIVATE 0.101.2
+ cli_utf16_to_utf8 at CLAMAV_PRIVATE 0.101.2
+ cli_utf16toascii at CLAMAV_PRIVATE 0.101.2
+ cli_vba_inflate at CLAMAV_PRIVATE 0.101.2
+ cli_vba_readdir at CLAMAV_PRIVATE 0.101.2
+ cli_versig2 at CLAMAV_PRIVATE 0.101.2
+ cli_versig at CLAMAV_PRIVATE 0.101.2
+ cli_warnmsg at CLAMAV_PRIVATE 0.101.2
+ cli_wm_decrypt_macro at CLAMAV_PRIVATE 0.101.2
+ cli_wm_readdir at CLAMAV_PRIVATE 0.101.2
+ cli_writen at CLAMAV_PRIVATE 0.101.2
+ decodeLine at CLAMAV_PRIVATE 0.101.2
+ disasmbuf at CLAMAV_PRIVATE 0.101.2
+ fmap at CLAMAV_PRIVATE 0.101.2
+ get_fpu_endian at CLAMAV_PRIVATE 0.101.2
+ have_clamjit at CLAMAV_PRIVATE 0.101.2
+ have_rar at CLAMAV_PRIVATE 0.101.2
+ html_normalise_map at CLAMAV_PRIVATE 0.101.2
+ html_normalise_mem at CLAMAV_PRIVATE 0.101.2
+ html_screnc_decode at CLAMAV_PRIVATE 0.101.2
+ html_tag_arg_free at CLAMAV_PRIVATE 0.101.2
+ init_domainlist at CLAMAV_PRIVATE 0.101.2
+ init_regex_list at CLAMAV_PRIVATE 0.101.2
+ init_whitelist at CLAMAV_PRIVATE 0.101.2
+ is_regex_ok at CLAMAV_PRIVATE 0.101.2
+ load_regex_matcher at CLAMAV_PRIVATE 0.101.2
  lsig_sub_matched at CLAMAV_PUBLIC 0.101.0
- messageCreate at CLAMAV_PRIVATE 0.101.1
- messageDestroy at CLAMAV_PRIVATE 0.101.1
- mpool_calloc at CLAMAV_PRIVATE 0.101.1
- mpool_create at CLAMAV_PRIVATE 0.101.1
- mpool_destroy at CLAMAV_PRIVATE 0.101.1
- mpool_free at CLAMAV_PRIVATE 0.101.1
- mpool_getstats at CLAMAV_PRIVATE 0.101.1
- phishingScan at CLAMAV_PRIVATE 0.101.1
- phishing_done at CLAMAV_PRIVATE 0.101.1
- phishing_init at CLAMAV_PRIVATE 0.101.1
- regex_list_add_pattern at CLAMAV_PRIVATE 0.101.1
- regex_list_done at CLAMAV_PRIVATE 0.101.1
- regex_list_match at CLAMAV_PRIVATE 0.101.1
- tableCreate at CLAMAV_PRIVATE 0.101.1
- tableDestroy at CLAMAV_PRIVATE 0.101.1
- tableFind at CLAMAV_PRIVATE 0.101.1
- tableInsert at CLAMAV_PRIVATE 0.101.1
- tableIterate at CLAMAV_PRIVATE 0.101.1
- tableRemove at CLAMAV_PRIVATE 0.101.1
- tableUpdate at CLAMAV_PRIVATE 0.101.1
- text_normalize_init at CLAMAV_PRIVATE 0.101.1
- text_normalize_map at CLAMAV_PRIVATE 0.101.1
- text_normalize_reset at CLAMAV_PRIVATE 0.101.1
- uniq_add at CLAMAV_PRIVATE 0.101.1
- uniq_free at CLAMAV_PRIVATE 0.101.1
- uniq_get at CLAMAV_PRIVATE 0.101.1
- uniq_init at CLAMAV_PRIVATE 0.101.1
+ messageCreate at CLAMAV_PRIVATE 0.101.2
+ messageDestroy at CLAMAV_PRIVATE 0.101.2
+ mpool_calloc at CLAMAV_PRIVATE 0.101.2
+ mpool_create at CLAMAV_PRIVATE 0.101.2
+ mpool_destroy at CLAMAV_PRIVATE 0.101.2
+ mpool_free at CLAMAV_PRIVATE 0.101.2
+ mpool_getstats at CLAMAV_PRIVATE 0.101.2
+ phishingScan at CLAMAV_PRIVATE 0.101.2
+ phishing_done at CLAMAV_PRIVATE 0.101.2
+ phishing_init at CLAMAV_PRIVATE 0.101.2
+ regex_list_add_pattern at CLAMAV_PRIVATE 0.101.2
+ regex_list_done at CLAMAV_PRIVATE 0.101.2
+ regex_list_match at CLAMAV_PRIVATE 0.101.2
+ tableCreate at CLAMAV_PRIVATE 0.101.2
+ tableDestroy at CLAMAV_PRIVATE 0.101.2
+ tableFind at CLAMAV_PRIVATE 0.101.2
+ tableInsert at CLAMAV_PRIVATE 0.101.2
+ tableIterate at CLAMAV_PRIVATE 0.101.2
+ tableRemove at CLAMAV_PRIVATE 0.101.2
+ tableUpdate at CLAMAV_PRIVATE 0.101.2
+ text_normalize_init at CLAMAV_PRIVATE 0.101.2
+ text_normalize_map at CLAMAV_PRIVATE 0.101.2
+ text_normalize_reset at CLAMAV_PRIVATE 0.101.2
+ uniq_add at CLAMAV_PRIVATE 0.101.2
+ uniq_free at CLAMAV_PRIVATE 0.101.2
+ uniq_get at CLAMAV_PRIVATE 0.101.2
+ uniq_init at CLAMAV_PRIVATE 0.101.2
diff -Nru clamav-0.101.1+dfsg/debian/rules clamav-0.101.2+dfsg/debian/rules
--- clamav-0.101.1+dfsg/debian/rules	2019-01-09 23:32:24.000000000 +0100
+++ clamav-0.101.2+dfsg/debian/rules	2019-03-30 16:25:48.000000000 +0100
@@ -142,9 +142,6 @@
 	T=900 dh_auto_test -- V=1 VERBOSE=1
 endif
 
-override_dh_strip:
-	dh_strip --dbgsym-migration=clamav-dbg
-
 override_dh_install:
 	dh_install
 	dh_apparmor -pclamav-freshclam --profile-name=usr.bin.freshclam
diff -Nru clamav-0.101.1+dfsg/fuzz/clamav_dbload_fuzzer.cpp clamav-0.101.2+dfsg/fuzz/clamav_dbload_fuzzer.cpp
--- clamav-0.101.1+dfsg/fuzz/clamav_dbload_fuzzer.cpp	1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/clamav_dbload_fuzzer.cpp	2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,136 @@
+/*
+ * Fuzz target for cl_load()
+ *
+ * Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Authors: Micah Snyder
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+
+#include "clamav.h"
+
+void clamav_message_callback(enum cl_msg severity, const char* fullmsg,
+                             const char* msg, void* context)
+{
+}
+
+class ClamAVState
+{
+  public:
+    ClamAVState()
+    {
+        // Silence all the log messages, none of them are meaningful.
+        cl_set_clcb_msg(clamav_message_callback);
+
+        cl_init(CL_INIT_DEFAULT);
+        engine = cl_engine_new();
+        cl_engine_compile(engine);
+
+        tmp_db_name = NULL;
+    }
+
+    ~ClamAVState()
+    {
+        cl_engine_free(engine);
+
+        if (NULL != tmp_db_name) {
+            unlink(tmp_db_name);
+        }
+    }
+
+    struct cl_engine* engine;
+    const char* tmp_db_name;
+};
+
+// Global with static initializer to setup an engine so we don't need to do
+// that on each execution.
+ClamAVState kClamAVState;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+    unsigned int sigs = 0;
+    FILE* fuzzdb      = NULL;
+
+    unsigned int dboptions =
+        CL_DB_PHISHING | CL_DB_PHISHING_URLS |
+        CL_DB_BYTECODE | CL_DB_BYTECODE_UNSIGNED |
+        CL_DB_PUA | CL_DB_ENHANCED;
+
+#if defined(CLAMAV_FUZZ_CDB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.cdb";
+#elif defined(CLAMAV_FUZZ_CFG)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.cfg";
+#elif defined(CLAMAV_FUZZ_CRB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.crb";
+#elif defined(CLAMAV_FUZZ_FP)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.fp";
+#elif defined(CLAMAV_FUZZ_FTM)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ftm";
+#elif defined(CLAMAV_FUZZ_HDB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.hdb";
+#elif defined(CLAMAV_FUZZ_HSB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.hsb";
+#elif defined(CLAMAV_FUZZ_IDB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.idb";
+#elif defined(CLAMAV_FUZZ_IGN)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ign";
+#elif defined(CLAMAV_FUZZ_IGN2)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ign2";
+#elif defined(CLAMAV_FUZZ_LDB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ldb";
+#elif defined(CLAMAV_FUZZ_MDB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.mdb";
+#elif defined(CLAMAV_FUZZ_MSB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.msb";
+#elif defined(CLAMAV_FUZZ_NDB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.ndb";
+#elif defined(CLAMAV_FUZZ_PDB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.pdb";
+#elif defined(CLAMAV_FUZZ_WDB)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.wdb";
+#elif defined(CLAMAV_FUZZ_YARA)
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz.yara";
+#else
+    kClamAVState.tmp_db_name = "dbload_tmp_fuzz";
+#endif
+
+    fuzzdb = fopen(kClamAVState.tmp_db_name, "w");
+    fwrite(data, size, 1, fuzzdb);
+    fclose(fuzzdb);
+
+    cl_load(
+        kClamAVState.tmp_db_name,
+        kClamAVState.engine,
+        &sigs,
+        dboptions);
+
+    return 0;
+}
diff -Nru clamav-0.101.1+dfsg/fuzz/clamav_scanfile_fuzzer.cpp clamav-0.101.2+dfsg/fuzz/clamav_scanfile_fuzzer.cpp
--- clamav-0.101.1+dfsg/fuzz/clamav_scanfile_fuzzer.cpp	1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/clamav_scanfile_fuzzer.cpp	2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,135 @@
+/*
+ * Fuzz target for cl_scanfile()
+ *
+ * Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Authors: Micah Snyder, Alex Gaynor
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+
+#include "clamav.h"
+
+void clamav_message_callback(enum cl_msg severity, const char* fullmsg,
+                             const char* msg, void* context)
+{
+}
+
+class ClamAVState
+{
+  public:
+    ClamAVState()
+    {
+        // Silence all the log messages, none of them are meaningful.
+        cl_set_clcb_msg(clamav_message_callback);
+
+        cl_init(CL_INIT_DEFAULT);
+        engine = cl_engine_new();
+        cl_engine_compile(engine);
+
+        tmp_file_name = NULL;
+    }
+
+    ~ClamAVState()
+    {
+        cl_engine_free(engine);
+
+        if (NULL != tmp_file_name) {
+            unlink(tmp_file_name);
+        }
+    }
+
+    struct cl_engine* engine;
+    const char* tmp_file_name;
+};
+
+// Global with static initializer to setup an engine so we don't need to do
+// that on each execution.
+ClamAVState kClamAVState;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t* data, size_t size)
+{
+    FILE* fuzzfile                  = NULL;
+    struct cl_scan_options scanopts = {0};
+
+    memset(&scanopts, 0, sizeof(struct cl_scan_options));
+
+#if defined(CLAMAV_FUZZ_ARCHIVE)
+    kClamAVState.tmp_file_name = "tmp.scanfile.archive";
+    scanopts.parse |= CL_SCAN_PARSE_ARCHIVE;
+#elif defined(CLAMAV_FUZZ_MAIL)
+    kClamAVState.tmp_file_name = "tmp.scanfile.eml";
+    scanopts.parse |= CL_SCAN_PARSE_MAIL;
+#elif defined(CLAMAV_FUZZ_OLE2)
+    kClamAVState.tmp_file_name = "tmp.scanfile.ole2";
+    scanopts.parse |= CL_SCAN_PARSE_OLE2;
+#elif defined(CLAMAV_FUZZ_PDF)
+    kClamAVState.tmp_file_name = "tmp.scanfile.pdf";
+    scanopts.parse |= CL_SCAN_PARSE_PDF;
+#elif defined(CLAMAV_FUZZ_HTML)
+    kClamAVState.tmp_file_name = "tmp.scanfile.html";
+    scanopts.parse |= CL_SCAN_PARSE_HTML;
+#elif defined(CLAMAV_FUZZ_PE)
+    kClamAVState.tmp_file_name = "tmp.scanfile.pe";
+    scanopts.parse |= CL_SCAN_PARSE_PE;
+#elif defined(CLAMAV_FUZZ_ELF)
+    kClamAVState.tmp_file_name = "tmp.scanfile.elf";
+    scanopts.parse |= CL_SCAN_PARSE_ELF;
+#elif defined(CLAMAV_FUZZ_SWF)
+    kClamAVState.tmp_file_name = "tmp.scanfile.swf";
+    scanopts.parse |= CL_SCAN_PARSE_SWF;
+#elif defined(CLAMAV_FUZZ_XMLDOCS)
+    kClamAVState.tmp_file_name = "tmp.scanfile.docx";
+    scanopts.parse |= CL_SCAN_PARSE_XMLDOCS;
+#elif defined(CLAMAV_FUZZ_HWP3)
+    kClamAVState.tmp_file_name = "tmp.scanfile.hwp";
+    scanopts.parse |= CL_SCAN_PARSE_HWP3;
+#else
+    kClamAVState.tmp_file_name = "tmp.scanfile";
+    scanopts.parse |= ~(0);
+#endif
+    scanopts.general |= CL_SCAN_GENERAL_HEURISTICS;
+
+    fuzzfile = fopen(kClamAVState.tmp_file_name, "w");
+    fwrite(data, size, 1, fuzzfile);
+    fclose(fuzzfile);
+
+    const char* virus_name = nullptr;
+    unsigned long scanned  = 0;
+    cl_scanfile(
+        kClamAVState.tmp_file_name,
+        &virus_name,
+        &scanned,
+        kClamAVState.engine,
+        &scanopts);
+
+    return 0;
+}
diff -Nru clamav-0.101.1+dfsg/fuzz/clamav_scanmap_fuzzer.cpp clamav-0.101.2+dfsg/fuzz/clamav_scanmap_fuzzer.cpp
--- clamav-0.101.1+dfsg/fuzz/clamav_scanmap_fuzzer.cpp	1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/clamav_scanmap_fuzzer.cpp	2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,117 @@
+/*
+ * Fuzz target for cl_scanmap_callback()
+ *
+ * Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ * Authors: Micah Snyder, Alex Gaynor
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright notice,
+ * this list of conditions and the following disclaimer in the documentation
+ * and/or other materials provided with the distribution.
+ *
+ * 3. Neither the name of the copyright holder nor the names of its contributors
+ * may be used to endorse or promote products derived from this software without
+ * specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <stdint.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "clamav.h"
+
+
+void clamav_message_callback(enum cl_msg severity, const char *fullmsg,
+                             const char *msg, void *context) {
+}
+
+class ClamAVState {
+public:
+    ClamAVState() {
+        // Silence all the log messages, none of them are meaningful.
+        cl_set_clcb_msg(clamav_message_callback);
+
+        cl_init(CL_INIT_DEFAULT);
+        engine = cl_engine_new();
+        cl_engine_compile(engine);
+    }
+
+    ~ClamAVState() {
+        cl_engine_free(engine);
+    }
+
+    struct cl_engine *engine;
+};
+
+// Global with static initializer to setup an engine so we don't need to do
+// that on each execution.
+ClamAVState kClamAVState;
+
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
+    
+    struct cl_scan_options scanopts = {0};
+    
+    cl_fmap_t *clamav_data = cl_fmap_open_memory(data, size);
+
+    memset(&scanopts, 0, sizeof(struct cl_scan_options));
+
+    scanopts.parse |= 
+#if defined(CLAMAV_FUZZ_ARCHIVE)
+        CL_SCAN_PARSE_ARCHIVE;
+#elif defined(CLAMAV_FUZZ_MAIL)
+        CL_SCAN_PARSE_MAIL;
+#elif defined(CLAMAV_FUZZ_OLE2)
+        CL_SCAN_PARSE_OLE2;
+#elif defined(CLAMAV_FUZZ_PDF)
+        CL_SCAN_PARSE_PDF;
+#elif defined(CLAMAV_FUZZ_HTML)
+        CL_SCAN_PARSE_HTML;
+#elif defined(CLAMAV_FUZZ_PE)
+        CL_SCAN_PARSE_PE;
+#elif defined(CLAMAV_FUZZ_ELF)
+        CL_SCAN_PARSE_ELF;
+#elif defined(CLAMAV_FUZZ_SWF)
+        CL_SCAN_PARSE_SWF;
+#elif defined(CLAMAV_FUZZ_XMLDOCS)
+        CL_SCAN_PARSE_XMLDOCS;
+#elif defined(CLAMAV_FUZZ_HWP3)
+        CL_SCAN_PARSE_HWP3;
+#else
+        ~(0);
+#endif
+
+    scanopts.general |= CL_SCAN_GENERAL_HEURISTICS;
+
+    const char *virus_name = nullptr;
+    unsigned long scanned = 0;
+    cl_scanmap_callback(
+        clamav_data,
+        NULL,
+        &virus_name,
+        &scanned,
+        kClamAVState.engine,
+        &scanopts,
+        nullptr
+    );
+
+    cl_fmap_close(clamav_data);
+
+    return 0;
+}
diff -Nru clamav-0.101.1+dfsg/fuzz/Makefile.am clamav-0.101.2+dfsg/fuzz/Makefile.am
--- clamav-0.101.1+dfsg/fuzz/Makefile.am	1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/Makefile.am	2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,247 @@
+# Process this file with automake to produce Makefile.in
+
+# By default, use our own standalone_fuzz_target_runner.
+# This runner does no fuzzing, but simply executes the inputs
+# provided via parameters.
+# Run e.g. "make all LIB_FUZZING_ENGINE=/path/to/libFuzzer.a"
+# to link the fuzzer(s) against a real fuzzing engine.
+#
+# OSS-Fuzz will define its own value for LIB_FUZZING_ENGINE.
+
+if ENABLE_FUZZ
+
+LIB_FUZZING_ENGINE ?= standalone_fuzz_target_runner.a
+
+AM_CPPFLAGS = \
+    @SSL_CPPFLAGS@ \
+    -I$(top_srcdir) -I$(top_srcdir)/shared -I$(top_srcdir)/libclamav \
+    -std=c++11 -stdlib=libc++
+
+AM_LDFLAGS = \
+    @SSL_LDFLAGS@
+
+fuzzdir = "fuzz-targets"
+
+fuzz_PROGRAMS = \
+    clamav_scanmap_fuzzer \
+    clamav_scanmap_ARCHIVE_fuzzer \
+    clamav_scanmap_MAIL_fuzzer \
+    clamav_scanmap_OLE2_fuzzer \
+    clamav_scanmap_PDF_fuzzer \
+    clamav_scanmap_HTML_fuzzer \
+    clamav_scanmap_PE_fuzzer \
+    clamav_scanmap_ELF_fuzzer \
+    clamav_scanmap_SWF_fuzzer \
+    clamav_scanmap_XMLDOCS_fuzzer \
+    clamav_scanmap_HWP3_fuzzer \
+    clamav_scanfile_fuzzer \
+    clamav_scanfile_ARCHIVE_fuzzer \
+    clamav_scanfile_MAIL_fuzzer \
+    clamav_scanfile_OLE2_fuzzer \
+    clamav_scanfile_PDF_fuzzer \
+    clamav_scanfile_HTML_fuzzer \
+    clamav_scanfile_PE_fuzzer \
+    clamav_scanfile_ELF_fuzzer \
+    clamav_scanfile_SWF_fuzzer \
+    clamav_scanfile_XMLDOCS_fuzzer \
+    clamav_scanfile_HWP3_fuzzer \
+    clamav_dbload_CDB_fuzzer \
+    clamav_dbload_CFG_fuzzer \
+    clamav_dbload_CRB_fuzzer \
+    clamav_dbload_FP_fuzzer \
+    clamav_dbload_FTM_fuzzer \
+    clamav_dbload_HDB_fuzzer \
+    clamav_dbload_HSB_fuzzer \
+    clamav_dbload_IDB_fuzzer \
+    clamav_dbload_IGN_fuzzer \
+    clamav_dbload_IGN2_fuzzer \
+    clamav_dbload_LDB_fuzzer \
+    clamav_dbload_MDB_fuzzer \
+    clamav_dbload_MSB_fuzzer \
+    clamav_dbload_NDB_fuzzer \
+    clamav_dbload_PDB_fuzzer \
+    clamav_dbload_WDB_fuzzer \
+    clamav_dbload_YARA_fuzzer
+
+dist_standalone_fuzz_target_runner_a_SOURCES = standalone_fuzz_target_runner.cpp
+noinst_LIBRARIES = standalone_fuzz_target_runner.a
+
+dist_clamav_scanmap_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+
+dist_clamav_scanmap_ARCHIVE_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_ARCHIVE_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_ARCHIVE_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_ARCHIVE $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_MAIL_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_MAIL_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_MAIL_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_MAIL $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_OLE2_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_OLE2_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_OLE2_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_OLE2 $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_PDF_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_PDF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_PDF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PDF $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_HTML_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_HTML_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_HTML_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HTML $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_PE_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_PE_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_PE_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PE $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_ELF_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_ELF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_ELF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_ELF $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_SWF_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_SWF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_SWF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_SWF $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_XMLDOCS_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_XMLDOCS_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_XMLDOCS_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_XMLDOCS $(AM_CPPFLAGS)
+
+dist_clamav_scanmap_HWP3_fuzzer_SOURCES = clamav_scanmap_fuzzer.cpp
+clamav_scanmap_HWP3_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanmap_HWP3_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HWP3 $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+
+dist_clamav_scanfile_ARCHIVE_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_ARCHIVE_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_ARCHIVE_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_ARCHIVE $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_MAIL_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_MAIL_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_MAIL_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_MAIL $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_OLE2_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_OLE2_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_OLE2_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_OLE2 $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_PDF_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_PDF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_PDF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PDF $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_HTML_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_HTML_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_HTML_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HTML $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_PE_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_PE_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_PE_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PE $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_ELF_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_ELF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_ELF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_ELF $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_SWF_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_SWF_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_SWF_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_SWF $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_XMLDOCS_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_XMLDOCS_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_XMLDOCS_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_XMLDOCS $(AM_CPPFLAGS)
+
+dist_clamav_scanfile_HWP3_fuzzer_SOURCES = clamav_scanfile_fuzzer.cpp
+clamav_scanfile_HWP3_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_scanfile_HWP3_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HWP3 $(AM_CPPFLAGS)
+
+dist_clamav_dbload_CDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_CDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_CDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_CDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_CFG_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_CFG_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_CFG_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_CFG $(AM_CPPFLAGS)
+
+dist_clamav_dbload_CRB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_CRB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_CRB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_CRB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_FP_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_FP_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_FP_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_FP $(AM_CPPFLAGS)
+
+dist_clamav_dbload_FTM_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_FTM_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_FTM_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_FTM $(AM_CPPFLAGS)
+
+dist_clamav_dbload_HDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_HDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_HDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_HSB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_HSB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_HSB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_HSB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_IDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_IDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_IDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_IDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_IGN_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_IGN_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_IGN_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_IGN $(AM_CPPFLAGS)
+
+dist_clamav_dbload_IGN2_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_IGN2_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_IGN2_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_IGN2 $(AM_CPPFLAGS)
+
+dist_clamav_dbload_LDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_LDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_LDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_LDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_MDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_MDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_MDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_MDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_MSB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_MSB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_MSB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_MSB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_NDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_NDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_NDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_NDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_PDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_PDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_PDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_PDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_WDB_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_WDB_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_WDB_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_WDB $(AM_CPPFLAGS)
+
+dist_clamav_dbload_YARA_fuzzer_SOURCES = clamav_dbload_fuzzer.cpp
+clamav_dbload_YARA_fuzzer_LDADD = $(LIB_FUZZING_ENGINE) @SSL_LIBS@ $(top_builddir)/libclamav/libclamav.la $(top_builddir)/libclamav/libclammspack.la
+clamav_dbload_YARA_fuzzer_CPPFLAGS = -DCLAMAV_FUZZ_YARA $(AM_CPPFLAGS)
+
+all: $(LIB_FUZZING_ENGINE)
+
+check: all
+	for type in ARCHIVE MAIL OLE2 PDF HTML PE ELF SWF XMLDOCS HWP3 ; do \
+	    builddir="$(builddir)" $(srcdir)/run_fuzzer_tests.py -f clamav_scanmap_fuzzer -c $(top_srcdir)/../clamav-fuzz-corpus/scantype/$$type ; \
+	done
+	for type in ARCHIVE MAIL OLE2 PDF HTML PE ELF SWF XMLDOCS HWP3 ; do \
+	    builddir="$(builddir)" $(srcdir)/run_fuzzer_tests.py -f "clamav_scanfile_"$$type"_fuzzer" -c $(top_srcdir)/../clamav-fuzz-corpus/scantype/$$type ; \
+	done
+	for type in CDB CFG CRB FP FTM HDB HSB IDB IGN IGN2 LDB MDB MSB NDB PDB WDB YARA ; do \
+	    builddir="$(builddir)" $(srcdir)/run_fuzzer_tests.py -f "clamav_dbload_"$$type"_fuzzer" -c $(top_srcdir)/../clamav-fuzz-corpus/database/$$type ; \
+	done
+
+else
+
+all:
+check:
+	@echo "Building fuzz targets is not enabled"
+	@echo "Use: ./configure --enable-fuzz --with-libjson=no --with-pcre=no --enable-static=yes --enable-shared=no --disable-llvm"
+	@exit 1
+
+endif
+
+CLEANFILES = *.gcda *.gcno
+EXTRA_DIST = README.md run_fuzzer_tests.py
diff -Nru clamav-0.101.1+dfsg/fuzz/README.md clamav-0.101.2+dfsg/fuzz/README.md
--- clamav-0.101.1+dfsg/fuzz/README.md	1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/README.md	2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,20 @@
+# OSS-Fuzz
+
+ClamAV has chosen to integrate with [oss-fuzz](https://github.com/google/oss-fuzz).
+
+What this means is that this repository includes:
+
+- Fuzz targets:
+  - A function to which we apply fuzzing.
+  - For ClamAV, clamav_scanfile_fuzzer.cc may be compiled with specific macros defined to produce multiple fuzz targets.
+  - Additional fuzz targets may be added to fuzz other ClamAV inputs.
+  
+- Seed corpora:
+  - A set of minimal test inputs that generate maximal code coverage.
+  - Each ClamAV fuzz target has a seed corpus located under: fuzz/corpus/<target>
+
+- Fuzzing dictionaries:
+  - A simple dictionary of tokens used by the input language. This can have a dramatic positive effect on fuzzing efficiency. For example, when fuzzing an XML parser, a dictionary of XML tokens will help.
+  - Some ClamAV fuzz targets have a dictionary located under: fuzz/dictionaries/<target>.dict
+
+For more information on how this is set up, see: [ideal OSS-Fuzz integration](https://github.com/google/oss-fuzz/blob/master/docs/ideal_integration.md)
diff -Nru clamav-0.101.1+dfsg/fuzz/run_fuzzer_tests.py clamav-0.101.2+dfsg/fuzz/run_fuzzer_tests.py
--- clamav-0.101.1+dfsg/fuzz/run_fuzzer_tests.py	1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/run_fuzzer_tests.py	2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,141 @@
+#!/usr/bin/env python
+# Copyright (C) 2018-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+
+'''
+This script is a convenience tool to run a standalone fuzz target against each
+item in its associated fuzz corpus.
+'''
+
+from __future__ import print_function, division, absolute_import
+
+import argparse
+import os
+import subprocess
+import sys
+import tempfile
+import threading
+
+def which(program):
+    '''
+    Implements bash "which" feature.
+    Find the full path to a program located in the PATH.
+
+    https://stackoverflow.com/a/377028
+    '''
+    def is_exe(fpath):
+        return os.path.isfile(fpath) and os.access(fpath, os.X_OK)
+
+    fpath, _ = os.path.split(program)
+    if fpath:
+        if is_exe(program):
+            return program
+    else:
+        for path in os.environ["PATH"].split(os.pathsep):
+            exe_file = os.path.join(path, program)
+            if is_exe(exe_file):
+                return exe_file
+
+    return None
+
+def cmd(command):
+    '''
+    Run a command in a subprocess.
+
+    https://stackoverflow.com/a/4408409
+    https://stackoverflow.com/a/10012262
+    '''
+    with tempfile.TemporaryFile() as tempf:
+        p = subprocess.Popen(command, stderr=tempf)
+        is_killed = {'value': False}
+
+        def timeout(p, is_killed):
+            is_killed['value'] = True
+            p.kill()
+
+        timer = threading.Timer(2, timeout, [p, is_killed])
+
+        try:
+            timer.start()
+            p.wait()
+            tempf.seek(0)
+            text = tempf.read().decode("utf-8").strip()
+            returncode = p.returncode
+        finally:
+            timer.cancel()
+
+        if is_killed['value']:
+            text = 'error: timeout, ' + text
+            returncode = 1
+
+        return text, returncode
+
+def run_test(fuzzer, corpus_path):
+    '''
+    Test a standalone fuzz target with each item from the fuzz corpus.
+    '''
+    builddir = os.environ.get("builddir", ".")
+    fuzz_target = os.path.join(builddir, fuzzer)
+
+    print("Fuzz Target:  {fuzzer}".format(fuzzer=fuzzer))
+    print("Corpus Path:  {corpus_path}".format(corpus_path=corpus_path))
+
+    if not os.path.exists(fuzz_target):
+        print("Failed to find fuzz target: {binary}!".format(binary=fuzz_target))
+        sys.exit(1)
+
+    failures = 0
+
+    valgrind = None
+    if os.environ.get('VG', ''):
+        valgrind = which('valgrind')
+
+    for fname in os.listdir(corpus_path):
+        seedpath = os.path.join(corpus_path, fname)
+
+        text, returncode = cmd([fuzz_target, seedpath])
+        if text.strip():
+            print(text)
+
+        failed = False
+        if returncode != 0 or 'error' in text:
+            print('failure on %s' % fname)
+            failed = True
+
+        if valgrind:
+            text, returncode = cmd(
+                [valgrind, '--error-exitcode=1', fuzz_target, seedpath])
+            if returncode:
+                print(text)
+                print('failure on %s' % fname)
+                failed = True
+
+        if failed:
+            failures = failures + 1
+
+    if failures:
+        print("%i scanfile fuzzer related tests failed." % failures)
+        sys.exit(1)
+
+def main():
+    '''
+    Get command line options to support this tool.
+    '''
+    parser = argparse.ArgumentParser(description=__doc__)
+
+    parser.add_argument(
+        '-f',
+        '--fuzzer',
+        required=True,
+        help="The fuzz target to test.")
+    parser.add_argument(
+        '-c',
+        '--corpus',
+        required=True,
+        help="Path of the fuzz corpus.")
+
+    args = parser.parse_args()
+
+    run_test(args.fuzzer, args.corpus)
+
+if __name__ == '__main__':
+    main()
diff -Nru clamav-0.101.1+dfsg/fuzz/standalone_fuzz_target_runner.cpp clamav-0.101.2+dfsg/fuzz/standalone_fuzz_target_runner.cpp
--- clamav-0.101.1+dfsg/fuzz/standalone_fuzz_target_runner.cpp	1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/fuzz/standalone_fuzz_target_runner.cpp	2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,35 @@
+// Copyright 2017 Google Inc. All Rights Reserved.
+// Licensed under the Apache License, Version 2.0 (the "License");
+
+// Example of a standalone runner for "fuzz targets".
+// It reads all files passed as parameters and feeds their contents
+// one by one into the fuzz target (LLVMFuzzerTestOneInput).
+// This runner does not do any fuzzing, but allows us to run the fuzz target
+// on the test corpus (e.g. "do_stuff_test_data") or on a single file,
+// e.g. the one that comes from a bug report.
+
+#include <cassert>
+#include <iostream>
+#include <fstream>
+#include <vector>
+
+// Forward declare the "fuzz target" interface.
+// We deliberately keep this inteface simple and header-free.
+extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size);
+
+int main(int argc, char **argv) {
+  for (int i = 1; i < argc; i++) {
+    std::ifstream in(argv[i]);
+    in.seekg(0, in.end);
+    size_t length = in.tellg();
+    in.seekg (0, in.beg);
+    std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
+    // Allocate exactly length bytes so that we reliably catch buffer overflows.
+    std::vector<char> bytes(length);
+    in.read(bytes.data(), bytes.size());
+    assert(in);
+    LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
+                           bytes.size());
+    std::cout << "Execution successful" << std::endl;
+  }
+}
\ No newline at end of file
diff -Nru clamav-0.101.1+dfsg/libclamav/7z/Xz.c clamav-0.101.2+dfsg/libclamav/7z/Xz.c
--- clamav-0.101.1+dfsg/libclamav/7z/Xz.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/7z/Xz.c	2019-03-13 22:13:01.000000000 +0100
@@ -93,6 +93,7 @@
           return 0;
 
       cl_finish_hash(p->sha, digest);
+      p->sha = NULL;
       break;
     default:
       return 0;
diff -Nru clamav-0.101.1+dfsg/libclamav/7z/XzDec.c clamav-0.101.2+dfsg/libclamav/7z/XzDec.c
--- clamav-0.101.1+dfsg/libclamav/7z/XzDec.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/7z/XzDec.c	2019-03-13 22:13:01.000000000 +0100
@@ -614,7 +614,11 @@
 
 void XzUnpacker_Free(CXzUnpacker *p)
 {
+  if (!p)
+    return;
   MixCoder_Free(&p->decoder);
+  cl_hash_destroy(p->sha);
+  p->sha = NULL;
 }
 
 SRes XzUnpacker_Code(CXzUnpacker *p, Byte *dest, SizeT *destLen,
@@ -816,8 +820,10 @@
             p->state = XZ_STATE_STREAM_INDEX_CRC;
             p->indexSize += 4;
             p->pos = 0;
-            if ((p->sha))
+            if ((p->sha)) {
                 cl_finish_hash(p->sha, digest);
+                p->sha = NULL;
+            }
 
             if (memcmp(digest, p->shaDigest, SHA256_DIGEST_SIZE) != 0)
               return SZ_ERROR_CRC;
diff -Nru clamav-0.101.1+dfsg/libclamav/aspack.c clamav-0.101.2+dfsg/libclamav/aspack.c
--- clamav-0.101.1+dfsg/libclamav/aspack.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/aspack.c	2019-03-13 22:13:01.000000000 +0100
@@ -395,7 +395,9 @@
 
   for (i = 0; i < 58; i++) {
     stream.init_array[i] = j;
-    j += ( 1 << image[ep+i+stream_init_multiplier_offset]); /* boundchecked in pe.c */
+        if (ep + i + stream_init_multiplier_offset < size) {
+            j += (1 << image[ep + i + stream_init_multiplier_offset]);
+        }
   }
 
   memset(stream.array1,0,sizeof(stream.array1));
diff -Nru clamav-0.101.1+dfsg/libclamav/clamav.h clamav-0.101.2+dfsg/libclamav/clamav.h
--- clamav-0.101.1+dfsg/libclamav/clamav.h	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/clamav.h	2019-03-13 22:13:01.000000000 +0100
@@ -157,10 +157,11 @@
 };
 
 /* general */
-#define CL_SCAN_GENERAL_ALLMATCHES                  0x1 /* scan in all-match mode */
-#define CL_SCAN_GENERAL_COLLECT_METADATA            0x2 /* collect metadata (--gen-json) */
-#define CL_SCAN_GENERAL_HEURISTICS                  0x4 /* option to enable heuristic alerts */
-#define CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE        0x8 /* allow heuristic match to take precedence. */
+#define CL_SCAN_GENERAL_ALLMATCHES                  0x1  /* scan in all-match mode */
+#define CL_SCAN_GENERAL_COLLECT_METADATA            0x2  /* collect metadata (--gen-json) */
+#define CL_SCAN_GENERAL_HEURISTICS                  0x4  /* option to enable heuristic alerts */
+#define CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE        0x8  /* allow heuristic match to take precedence. */
+#define CL_SCAN_GENERAL_UNPRIVILEGED                0x10 /* scanner will not have read access to files. */
 
 /* parsing capabilities options */
 #define CL_SCAN_PARSE_ARCHIVE                       0x1
diff -Nru clamav-0.101.1+dfsg/libclamav/cpio.c clamav-0.101.2+dfsg/libclamav/cpio.c
--- clamav-0.101.1+dfsg/libclamav/cpio.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/cpio.c	2019-03-13 22:13:01.000000000 +0100
@@ -146,7 +146,7 @@
 	    } else if(hdr_namesize % 2)
 		pos++;
 	}
-	filesize = (uint32_t) (EC16(hdr_old.filesize[0], conv) << 16 | EC16(hdr_old.filesize[1], conv));
+        filesize = (uint32_t)((uint32_t)EC16(hdr_old.filesize[0], conv) << 16 | EC16(hdr_old.filesize[1], conv));
 	cli_dbgmsg("CPIO: Filesize: %u\n", filesize);
 	if(!filesize)
 	    continue;
diff -Nru clamav-0.101.1+dfsg/libclamav/htmlnorm.c clamav-0.101.2+dfsg/libclamav/htmlnorm.c
--- clamav-0.101.1+dfsg/libclamav/htmlnorm.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/htmlnorm.c	2019-03-13 22:13:01.000000000 +0100
@@ -1,10 +1,10 @@
 /*
- *  Copyright (C) 2015, 2018 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *  Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
  *  Copyright (C) 2007-2013 Sourcefire, Inc.
  *
  *  Authors: Trog
- * 
- *  Summary: Normalise HTML text. Decode MS Script Encoder protection. 
+ *
+ *  Summary: Normalise HTML text. Decode MS Script Encoder protection.
  *           The ScrEnc decoder was initially based upon an analysis by Andreas Marx.
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -100,7 +100,7 @@
 	unsigned char contents[MAX_TAG_CONTENTS_LENGTH + 1];
 };
 
-static const int base64_chars[256] = {
+static const int32_t base64_chars[256] = {
     -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
     -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,-1,
     -1,-1,-1,-1, -1,-1,-1,-1, -1,-1,-1,62, -1,-1,-1,63,
@@ -590,29 +590,29 @@
 			}
 		}
 		ptr++;
-		s->length--;
-	}
-	if(!s->length) {
-		size_t remaining;
-		if(strlen((const char*)ptr) >= 12) {
-			uint32_t expected;
-			expected = base64_chars[ptr[0]] << 2;
-			expected += base64_chars[ptr[1]] >> 4;
-			expected += (base64_chars[ptr[1]] & 0x0f) << 12;
-			expected += (base64_chars[ptr[2]] >> 2) << 8;
-			expected += (base64_chars[ptr[2]] & 0x03) << 22;
-			expected += base64_chars[ptr[3]] << 16;
-			expected += (base64_chars[ptr[4]] << 2) << 24;
-			expected += (base64_chars[ptr[5]] >> 4) << 24;
-			ptr += 8;
-			if(s->sum != expected) {
-				cli_dbgmsg("screnc_decode: checksum mismatch: %u != %u\n", s->sum, expected);
-			} else {
-				if(strncmp((const char*)ptr, "^#~@", 4) != 0) {
-					cli_dbgmsg("screnc_decode: terminator not found\n");
-				} else {
-					cli_dbgmsg("screnc_decode: OK\n");
-				}
+                s->length--;
+        }
+        if(!s->length) {
+            size_t remaining;
+            if(strlen((const char*)ptr) >= 12) {
+                uint32_t expected;
+                expected = base64_chars[ptr[0]] < 0 ? 0 : base64_chars[ptr[0]] << 2;
+                expected += base64_chars[ptr[1]] >> 4;
+                expected += (base64_chars[ptr[1]] & 0x0f) << 12;
+                expected += ((base64_chars[ptr[2]] >> 2) < 0 ? 0 : (base64_chars[ptr[2]] >> 2)) << 8;
+                expected += (base64_chars[ptr[2]] & 0x03) << 22;
+                expected += base64_chars[ptr[3]] < 0 ? 0 : base64_chars[ptr[3]] << 16;
+                expected += (base64_chars[ptr[4]] < 0 ? 0 : base64_chars[ptr[4]] << 2) << 24;
+                expected += ((base64_chars[ptr[5]] >> 4) < 0 ? 0 : (base64_chars[ptr[5]] >> 4)) << 24;
+                ptr += 8;
+                if(s->sum != expected) {
+                    cli_dbgmsg("screnc_decode: checksum mismatch: %u != %u\n", s->sum, expected);
+                } else {
+                    if(strncmp((const char*)ptr, "^#~@", 4) != 0) {
+                        cli_dbgmsg("screnc_decode: terminator not found\n");
+                    } else {
+                        cli_dbgmsg("screnc_decode: OK\n");
+                    }
 			}
 			ptr += 4;
 		}
@@ -647,7 +647,7 @@
 static int cli_html_normalise(int fd, m_area_t *m_area, const char *dirname, tag_arguments_t *hrefs,const struct cli_dconf* dconf)
 {
 	int fd_tmp, tag_length = 0, tag_arg_length = 0, binary;
-	int retval=FALSE, escape=FALSE, value = 0, hex=FALSE, tag_val_length=0;
+    int64_t retval = FALSE, escape = FALSE, value = 0, hex = FALSE, tag_val_length = 0;
 	int look_for_screnc=FALSE, in_screnc=FALSE,in_script=FALSE, text_space_written=FALSE;
 	FILE *stream_in = NULL;
 	html_state state=HTML_NORM, next_state=HTML_BAD_STATE, saved_next_state=HTML_BAD_STATE;
@@ -684,7 +684,7 @@
 			cli_dbgmsg("Invalid HTML fd\n");
 			return FALSE;
 		}
-		lseek(fd, 0, SEEK_SET);	
+		lseek(fd, 0, SEEK_SET);
 		fd_tmp = dup(fd);
 		if (fd_tmp < 0) {
 			return FALSE;
@@ -1459,10 +1459,16 @@
 					next_state = HTML_BAD_STATE;
 					ptr++;
 				} else if (isdigit(*ptr) || (hex && isxdigit(*ptr))) {
-					if (hex) {
+                        if (hex && (value >> 32) * 16 < INT32_MAX) {
 						value *= 16;
-					} else {
+                        } else if ((value >> 32) * 10 < INT32_MAX) {
 						value *= 10;
+                        } else {
+                            html_output_c(file_buff_o2, value);
+                            state      = next_state;
+                            next_state = HTML_BAD_STATE;
+                            ptr++;
+                            break;
 					}
 					if (isdigit(*ptr)) {
 						value += (*ptr - '0');
@@ -1504,28 +1510,28 @@
 				if (strlen((const char*)ptr) < 8) {
 					state = HTML_NORM;
 					next_state = HTML_BAD_STATE;
-					break;
-				}
-				memset(&screnc_state, 0, sizeof(screnc_state));
-				screnc_state.length = base64_chars[ptr[0]] << 2;
-				screnc_state.length += base64_chars[ptr[1]] >> 4;
-				screnc_state.length += (base64_chars[ptr[1]] & 0x0f) << 12;
-				screnc_state.length += (base64_chars[ptr[2]] >> 2) << 8;
-				screnc_state.length += (base64_chars[ptr[2]] & 0x03) << 22;
-				screnc_state.length += base64_chars[ptr[3]] << 16;
-				screnc_state.length += (base64_chars[ptr[4]] << 2) << 24;
-				screnc_state.length += (base64_chars[ptr[5]] >> 4) << 24;
-				state = HTML_JSDECODE_DECRYPT;
-				in_screnc = TRUE;
-				next_state = HTML_BAD_STATE;
-				/* for JS normalizer */
-				ptr[7] = '\n';
-				ptr += 8;
-				break;
-			case HTML_JSDECODE_DECRYPT:
-				screnc_decode(ptr, &screnc_state);
-				if(!screnc_state.length) {
-					state = HTML_NORM;
+                                        break;
+                                }
+                                memset(&screnc_state, 0, sizeof(screnc_state));
+                                screnc_state.length = base64_chars[ptr[0]] < 0 ? 0 : base64_chars[ptr[0]] << 2;
+                                screnc_state.length += base64_chars[ptr[1]] >> 4;
+                                screnc_state.length += (base64_chars[ptr[1]] & 0x0f) << 12;
+                                screnc_state.length += ((base64_chars[ptr[2]] >> 2) < 0 ? 0 : (base64_chars[ptr[2]] >> 2)) << 8;
+                                screnc_state.length += (base64_chars[ptr[2]] & 0x03) << 22;
+                                screnc_state.length += base64_chars[ptr[3]] < 0 ? 0 : base64_chars[ptr[3]] << 16;
+                                screnc_state.length += (base64_chars[ptr[4]] < 0 ? 0 : base64_chars[ptr[4]] << 2) << 24;
+                                screnc_state.length += ((base64_chars[ptr[5]] >> 4) < 0 ? 0 : (base64_chars[ptr[5]] >> 4)) << 24;
+                                state = HTML_JSDECODE_DECRYPT;
+                                in_screnc = TRUE;
+                                next_state = HTML_BAD_STATE;
+                                /* for JS normalizer */
+                                ptr[7] = '\n';
+                                ptr += 8;
+                                break;
+                        case HTML_JSDECODE_DECRYPT:
+                                screnc_decode(ptr, &screnc_state);
+                                if(!screnc_state.length) {
+                                    state = HTML_NORM;
 					next_state = HTML_BAD_STATE;
 					in_screnc = FALSE;
 					break;
@@ -1603,6 +1609,15 @@
 				break;
 			case HTML_RFC2397_INIT:
 				if (dirname) {
+                        if (NULL != file_tmp_o1) {
+                            if (file_tmp_o1->fd != -1) {
+                                html_output_flush(file_tmp_o1);
+                                close(file_tmp_o1->fd);
+                                file_tmp_o1->fd = -1;
+                            }
+                            free(file_tmp_o1);
+                        }
+
 					file_tmp_o1 = (file_buff_t *) cli_malloc(sizeof(file_buff_t));
 					if (!file_tmp_o1) {
                         cli_errmsg("cli_html_normalise: Unable to allocate memory for file_tmp_o1\n");
@@ -1686,8 +1701,11 @@
 				break;
 			case HTML_RFC2397_FINISH:
 				if(file_tmp_o1) {
+                        if (file_tmp_o1->fd != -1) {
 					html_output_flush(file_tmp_o1);
 					close(file_tmp_o1->fd);
+                            file_tmp_o1->fd = -1;
+                        }
 					free(file_tmp_o1);
 					file_tmp_o1 = NULL;
 				}
@@ -1709,7 +1727,14 @@
 				state = HTML_RFC2397_DATA;
 				break;
 			case HTML_ESCAPE_CHAR:
+                    if ((value >> 32) * 16 < INT32_MAX) {
 				value *= 16;
+                    } else {
+                        state = next_state;
+                        next_state = HTML_BAD_STATE;
+                        ptr++;
+                        break;
+                    }
 				length++;
 				if (isxdigit(*ptr)) {
 					if (isdigit(*ptr)) {
@@ -1817,9 +1842,10 @@
         file_buff_text=NULL;
 	}
 	if(file_tmp_o1) {
+        if (file_tmp_o1->fd != -1) {
 		html_output_flush(file_tmp_o1);
-		if(file_tmp_o1 && file_tmp_o1->fd != -1)
 			close(file_tmp_o1->fd);
+        }
 		free(file_tmp_o1);
 	}
 	return retval;
@@ -1900,17 +1926,16 @@
 		ptr++;
 	} while (count < 8);
 
-	memset(&screnc_state, 0, sizeof(screnc_state));
-	screnc_state.length = base64_chars[tmpstr[0]] << 2;
-	screnc_state.length += base64_chars[tmpstr[1]] >> 4;
-	screnc_state.length += (base64_chars[tmpstr[1]] & 0x0f) << 12;
-	screnc_state.length += (base64_chars[tmpstr[2]] >> 2) << 8;
-	screnc_state.length += (base64_chars[tmpstr[2]] & 0x03) << 22;
-	screnc_state.length += base64_chars[tmpstr[3]] << 16;
-	screnc_state.length += (base64_chars[tmpstr[4]] << 2) << 24;
-	screnc_state.length += (base64_chars[tmpstr[5]] >> 4) << 24;
-
-	cli_writen(ofd, "<script>",strlen("<script>"));
+        memset(&screnc_state, 0, sizeof(screnc_state));
+        screnc_state.length = base64_chars[tmpstr[0]] < 0 ? 0 : base64_chars[tmpstr[0]] << 2;
+        screnc_state.length += base64_chars[tmpstr[1]] >> 4;
+        screnc_state.length += (base64_chars[tmpstr[1]] & 0x0f) << 12;
+        screnc_state.length += ((base64_chars[tmpstr[2]] >> 2) < 0 ? 0 : (base64_chars[tmpstr[2]] >> 2)) << 8;
+        screnc_state.length += (base64_chars[tmpstr[2]] & 0x03) << 22;
+        screnc_state.length += base64_chars[tmpstr[3]] < 0 ? 0 : base64_chars[tmpstr[3]] << 16;
+        screnc_state.length += (base64_chars[tmpstr[4]] < 0 ? 0 : base64_chars[tmpstr[4]] << 2) << 24;
+        screnc_state.length += ((base64_chars[tmpstr[5]] >> 4) < 0 ? 0 : (base64_chars[tmpstr[5]] >> 4)) << 24;
+        cli_writen(ofd, "<script>",strlen("<script>"));
 	while (screnc_state.length && line) {
 		screnc_decode(ptr, &screnc_state);
 		cli_writen(ofd, ptr, strlen((const char*)ptr));
diff -Nru clamav-0.101.1+dfsg/libclamav/ole2_extract.c clamav-0.101.2+dfsg/libclamav/ole2_extract.c
--- clamav-0.101.1+dfsg/libclamav/ole2_extract.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/ole2_extract.c	2019-03-13 22:13:01.000000000 +0100
@@ -399,9 +399,14 @@
         return FALSE;
     }
     /* other methods: (blockno+1) * 512 or (blockno * block_size) + 512; */
+    if ((uint64_t) blockno << hdr->log2_big_block_size < INT32_MAX) {
     offset = (blockno << hdr->log2_big_block_size) + MAX(512, 1 << hdr->log2_big_block_size);   /* 512 is header size */
-
     offend = offset + size;
+    } else {
+        offset = INT32_MAX - size;
+        offend = INT32_MAX;
+    }
+
     if ((offend <= 0) || (offset < 0) || (offset >= hdr->m_length)) {
         return FALSE;
     } else if (offend > hdr->m_length) {
@@ -762,10 +767,16 @@
                     }
                     else {
                         ole2_list_delete(&node_list);
+                            if (dirname)
+                                free(dirname);
                         return ret;
                     }
                 }
             }
+                if (dirname) {
+                    free(dirname);
+                    dirname = NULL;
+                }
             if ((int)(prop_block[idx].prev) != -1) {
 	        if ((ret=ole2_list_push(&node_list, prop_block[idx].prev)) != CL_SUCCESS) {
 		    ole2_list_delete(&node_list);
@@ -778,8 +789,6 @@
 		    return ret;
 		}
             }
-            if (dirname)
-                free(dirname);
             break;
         default:
             cli_dbgmsg("ERROR: unknown OLE2 entry type: %d\n", prop_block[idx].type);
@@ -813,10 +822,18 @@
         return CL_SUCCESS;
     }
     name = get_property_name2(prop->name, prop->name_size);
-    if (name)
-        cnt = uniq_add(hdr->U, name, strlen(name), &hash);
-    else
-        cnt = uniq_add(hdr->U, NULL, 0, &hash);
+    if (name) {
+        if (CL_SUCCESS != uniq_add(hdr->U, name, strlen(name), &hash, &cnt)) {
+            free(name);
+            cli_dbgmsg("OLE2 [handler_writefile]: too many property names added to uniq store.\n");
+            return CL_BREAK;
+        }
+    } else {
+        if (CL_SUCCESS != uniq_add(hdr->U, NULL, 0, &hash, &cnt)) {
+            cli_dbgmsg("OLE2 [handler_writefile]: too many property names added to uniq store.\n");
+            return CL_BREAK;
+        }
+    }
     snprintf(newname, sizeof(newname), "%s" PATHSEP "%s_%u", dir, hash, cnt);
     newname[sizeof(newname) - 1] = '\0';
     cli_dbgmsg("OLE2 [handler_writefile]: Dumping '%s' to '%s'\n", name ? name : "<empty>", newname);
diff -Nru clamav-0.101.1+dfsg/libclamav/others_common.c clamav-0.101.2+dfsg/libclamav/others_common.c
--- clamav-0.101.1+dfsg/libclamav/others_common.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/others_common.c	2019-03-13 22:13:01.000000000 +0100
@@ -29,49 +29,50 @@
 #include <string.h>
 #include <stdlib.h>
 #include <ctype.h>
-#ifdef	HAVE_UNISTD_H
+#ifdef HAVE_UNISTD_H
 #include <unistd.h>
 #endif
 #include <sys/types.h>
 #include <sys/stat.h>
 #include <dirent.h>
-#ifndef	_WIN32
+#ifndef _WIN32
 #include <sys/wait.h>
 #include <sys/time.h>
 #endif
 #include <time.h>
 #include <fcntl.h>
-#ifdef	HAVE_PWD_H
+#ifdef HAVE_PWD_H
 #include <pwd.h>
 #endif
 #include <errno.h>
 #include "target.h"
-#ifdef	HAVE_SYS_PARAM_H
+#ifdef HAVE_SYS_PARAM_H
 #include <sys/param.h>
 #endif
-#ifdef	HAVE_MALLOC_H
+#ifdef HAVE_MALLOC_H
 #include <malloc.h>
 #endif
 
 #include "clamav.h"
 #include "others.h"
+#include "platform.h"
 #include "regex/regex.h"
 #include "ltdl.h"
 #include "matcher-ac.h"
 
-static unsigned char name_salt[16] = { 16, 38, 97, 12, 8, 4, 72, 196, 217, 144, 33, 124, 18, 11, 17, 253 };
+static unsigned char name_salt[16] = {16, 38, 97, 12, 8, 4, 72, 196, 217, 144, 33, 124, 18, 11, 17, 253};
 
 #ifdef CL_NOTHREADS
 #undef CL_THREAD_SAFE
 #endif
 
 #ifdef CL_THREAD_SAFE
-#  include <pthread.h>
+#include <pthread.h>
 
 static pthread_mutex_t cli_gentemp_mutex = PTHREAD_MUTEX_INITIALIZER;
-# ifndef HAVE_CTIME_R
+#ifndef HAVE_CTIME_R
 static pthread_mutex_t cli_ctime_mutex = PTHREAD_MUTEX_INITIALIZER;
-# endif
+#endif
 static pthread_mutex_t cli_strerror_mutex = PTHREAD_MUTEX_INITIALIZER;
 static pthread_key_t cli_ctx_tls_key;
 static pthread_once_t cli_ctx_tls_key_once = PTHREAD_ONCE_INIT;
@@ -81,7 +82,7 @@
     pthread_key_create(&cli_ctx_tls_key, NULL);
 }
 
-void cli_logg_setup(const cli_ctx *ctx)
+void cli_logg_setup(const cli_ctx* ctx)
 {
     pthread_once(&cli_ctx_tls_key_once, cli_ctx_tls_key_alloc);
     pthread_setspecific(cli_ctx_tls_key, ctx);
@@ -92,22 +93,22 @@
     pthread_setspecific(cli_ctx_tls_key, NULL);
 }
 
-static inline void *cli_getctx(void)
+static inline void* cli_getctx(void)
 {
-    cli_ctx *ctx;
+    cli_ctx* ctx;
     pthread_once(&cli_ctx_tls_key_once, cli_ctx_tls_key_alloc);
     ctx = pthread_getspecific(cli_ctx_tls_key);
     return ctx ? ctx->cb_ctx : NULL;
 }
 #else
 
-static const cli_ctx *current_ctx = NULL;
-void cli_logg_setup(const cli_ctx *ctx)
+static const cli_ctx* current_ctx = NULL;
+void cli_logg_setup(const cli_ctx* ctx)
 {
     current_ctx = ctx;
 }
 
-static inline void *cli_getctx(void)
+static inline void* cli_getctx(void)
 {
     return current_ctx ? current_ctx->cb_ctx : NULL;
 }
@@ -117,10 +118,10 @@
 }
 #endif
 
-uint8_t cli_debug_flag = 0;
+uint8_t cli_debug_flag              = 0;
 uint8_t cli_always_gen_section_hash = 0;
 
-static void fputs_callback(enum cl_msg severity, const char *fullmsg, const char *msg, void *context)
+static void fputs_callback(enum cl_msg severity, const char* fullmsg, const char* msg, void* context)
 {
     UNUSEDPARAM(severity);
     UNUSEDPARAM(msg);
@@ -135,138 +136,136 @@
     msg_callback = callback;
 }
 
-#define MSGCODE(buff, len, x)				    \
-	va_list args;					    \
-	size_t len = sizeof(x) - 1;			    \
-	char buff[BUFSIZ];				    \
-    strncpy(buff, x, len);				    \
-    va_start(args, str);				    \
-    vsnprintf(buff + len, sizeof(buff) - len, str, args);   \
-    buff[sizeof(buff) - 1] = '\0';			    \
+#define MSGCODE(buff, len, x)                             \
+    va_list args;                                         \
+    size_t len = sizeof(x) - 1;                           \
+    char buff[BUFSIZ];                                    \
+    strncpy(buff, x, len);                                \
+    va_start(args, str);                                  \
+    vsnprintf(buff + len, sizeof(buff) - len, str, args); \
+    buff[sizeof(buff) - 1] = '\0';                        \
     va_end(args)
 
-void cli_warnmsg(const char *str, ...)
+void cli_warnmsg(const char* str, ...)
 {
     MSGCODE(buff, len, "LibClamAV Warning: ");
-    msg_callback(CL_MSG_WARN, buff, buff+len, cli_getctx());
+    msg_callback(CL_MSG_WARN, buff, buff + len, cli_getctx());
 }
 
-void cli_errmsg(const char *str, ...)
+void cli_errmsg(const char* str, ...)
 {
     MSGCODE(buff, len, "LibClamAV Error: ");
-    msg_callback(CL_MSG_ERROR, buff, buff+len, cli_getctx());
+    msg_callback(CL_MSG_ERROR, buff, buff + len, cli_getctx());
 }
 
-void cli_infomsg(const cli_ctx* ctx, const char *str, ...)
+void cli_infomsg(const cli_ctx* ctx, const char* str, ...)
 {
     MSGCODE(buff, len, "LibClamAV info: ");
-    msg_callback(CL_MSG_INFO_VERBOSE, buff, buff+len, ctx ? ctx->cb_ctx : NULL);
+    msg_callback(CL_MSG_INFO_VERBOSE, buff, buff + len, ctx ? ctx->cb_ctx : NULL);
 }
 
-void cli_dbgmsg_internal(const char *str, ...)
+void cli_dbgmsg_internal(const char* str, ...)
 {
     MSGCODE(buff, len, "LibClamAV debug: ");
     fputs(buff, stderr);
 }
 
-int cli_matchregex(const char *str, const char *regex)
+int cli_matchregex(const char* str, const char* regex)
 {
-	regex_t reg;
-	int match, flags = REG_EXTENDED | REG_NOSUB;
+    regex_t reg;
+    int match, flags = REG_EXTENDED | REG_NOSUB;
 #ifdef _WIN32
     flags |= REG_ICASE;
 #endif
     if(cli_regcomp(&reg, regex, flags) == 0) {
-	match = (cli_regexec(&reg, str, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
-	cli_regfree(&reg);
-	return match;
+        match = (cli_regexec(&reg, str, 0, NULL, 0) == REG_NOMATCH) ? 0 : 1;
+        cli_regfree(&reg);
+        return match;
     }
 
     return 0;
 }
-void *cli_malloc(size_t size)
+void* cli_malloc(size_t size)
 {
-	void *alloc;
-
+    void* alloc;
 
     if(!size || size > CLI_MAX_ALLOCATION) {
-	cli_errmsg("cli_malloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int) size);
-	return NULL;
+        cli_errmsg("cli_malloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int)size);
+        return NULL;
     }
 
     alloc = malloc(size);
 
     if(!alloc) {
-	perror("malloc_problem");
-	cli_errmsg("cli_malloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int) size);
-	return NULL;
-    } else return alloc;
+        perror("malloc_problem");
+        cli_errmsg("cli_malloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int)size);
+        return NULL;
+    } else
+        return alloc;
 }
 
-void *cli_calloc(size_t nmemb, size_t size)
+void* cli_calloc(size_t nmemb, size_t size)
 {
-	void *alloc;
-
+    void* alloc;
 
-    if(!nmemb || !size || size > CLI_MAX_ALLOCATION || nmemb > CLI_MAX_ALLOCATION
-        || (nmemb*size > CLI_MAX_ALLOCATION)) {
-	cli_errmsg("cli_calloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int) nmemb*size);
-	return NULL;
+    if(!nmemb || !size || size > CLI_MAX_ALLOCATION || nmemb > CLI_MAX_ALLOCATION || (nmemb * size > CLI_MAX_ALLOCATION)) {
+        cli_errmsg("cli_calloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int)nmemb * size);
+        return NULL;
     }
 
     alloc = calloc(nmemb, size);
 
     if(!alloc) {
-	perror("calloc_problem");
-	cli_errmsg("cli_calloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int) (nmemb * size));
-	return NULL;
-    } else return alloc;
+        perror("calloc_problem");
+        cli_errmsg("cli_calloc(): Can't allocate memory (%lu bytes).\n", (unsigned long int)(nmemb * size));
+        return NULL;
+    } else
+        return alloc;
 }
 
-void *cli_realloc(void *ptr, size_t size)
+void* cli_realloc(void* ptr, size_t size)
 {
-	void *alloc;
-
+    void* alloc;
 
     if(!size || size > CLI_MAX_ALLOCATION) {
-	cli_errmsg("cli_realloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int) size);
-	return NULL;
+        cli_errmsg("cli_realloc(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int)size);
+        return NULL;
     }
 
     alloc = realloc(ptr, size);
 
     if(!alloc) {
-	perror("realloc_problem");
-	cli_errmsg("cli_realloc(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int) size);
-	return NULL;
-    } else return alloc;
+        perror("realloc_problem");
+        cli_errmsg("cli_realloc(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int)size);
+        return NULL;
+    } else
+        return alloc;
 }
 
-void *cli_realloc2(void *ptr, size_t size)
+void* cli_realloc2(void* ptr, size_t size)
 {
-	void *alloc;
-
+    void* alloc;
 
     if(!size || size > CLI_MAX_ALLOCATION) {
-	cli_errmsg("cli_realloc2(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int) size);
-	return NULL;
+        cli_errmsg("cli_realloc2(): Attempt to allocate %lu bytes. Please report to https://bugzilla.clamav.net\n", (unsigned long int)size);
+        return NULL;
     }
 
     alloc = realloc(ptr, size);
 
     if(!alloc) {
-	perror("realloc_problem");
-	cli_errmsg("cli_realloc2(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int) size);
-	if(ptr)
-	    free(ptr);
-	return NULL;
-    } else return alloc;
+        perror("realloc_problem");
+        cli_errmsg("cli_realloc2(): Can't re-allocate memory to %lu bytes.\n", (unsigned long int)size);
+        if(ptr)
+            free(ptr);
+        return NULL;
+    } else
+        return alloc;
 }
 
-char *cli_strdup(const char *s)
+char* cli_strdup(const char* s)
 {
-        char *alloc;
-
+    char* alloc;
 
     if(s == NULL) {
         cli_errmsg("cli_strdup(): s == NULL. Please report to https://bugzilla.clamav.net\n");
@@ -277,7 +276,7 @@
 
     if(!alloc) {
         perror("strdup_problem");
-        cli_errmsg("cli_strdup(): Can't allocate memory (%u bytes).\n", (unsigned int) strlen(s));
+        cli_errmsg("cli_strdup(): Can't allocate memory (%u bytes).\n", (unsigned int)strlen(s));
         return NULL;
     }
 
@@ -285,142 +284,137 @@
 }
 
 /* returns converted timestamp, in case of error the returned string contains at least one character */
-const char* cli_ctime(const time_t *timep, char *buf, const size_t bufsize)
+const char* cli_ctime(const time_t* timep, char* buf, const size_t bufsize)
 {
-	const char *ret;
-	if(bufsize < 26) {
-		/* standard says we must have at least 26 bytes buffer */
-		cli_warnmsg("buffer too small for ctime\n");
-		return " ";
-	}
-	if((uint32_t)(*timep) > 0x7fffffff) {
-		/* some systems can consider these timestamps invalid */
-		strncpy(buf, "invalid timestamp", bufsize-1);
-		buf[bufsize-1] = '\0';
-		return buf;
-	}
-
-#ifdef HAVE_CTIME_R	
-# ifdef HAVE_CTIME_R_2
-	ret = ctime_r(timep, buf);
-# else
-	ret = ctime_r(timep, buf, bufsize);
-# endif
+    const char* ret;
+    if(bufsize < 26) {
+        /* standard says we must have at least 26 bytes buffer */
+        cli_warnmsg("buffer too small for ctime\n");
+        return " ";
+    }
+    if((uint32_t)(*timep) > 0x7fffffff) {
+        /* some systems can consider these timestamps invalid */
+        strncpy(buf, "invalid timestamp", bufsize - 1);
+        buf[bufsize - 1] = '\0';
+        return buf;
+    }
+
+#ifdef HAVE_CTIME_R
+#ifdef HAVE_CTIME_R_2
+    ret = ctime_r(timep, buf);
+#else
+    ret = ctime_r(timep, buf, bufsize);
+#endif
 #else /* no ctime_r */
 
-# ifdef CL_THREAD_SAFE
-	pthread_mutex_lock(&cli_ctime_mutex);
-# endif
-	ret = ctime(timep);
-	if(ret) {
-		strncpy(buf, ret, bufsize-1);
-		buf[bufsize-1] = '\0';
-		ret = buf;
-	}
-# ifdef CL_THREAD_SAFE
-	pthread_mutex_unlock(&cli_ctime_mutex);
-# endif
-#endif
-	/* common */
-	if(!ret) {
-		buf[0] = ' ';
-		buf[1] = '\0';
-		return buf;
-	}
-	return ret;
+#ifdef CL_THREAD_SAFE
+    pthread_mutex_lock(&cli_ctime_mutex);
+#endif
+    ret = ctime(timep);
+    if(ret) {
+        strncpy(buf, ret, bufsize - 1);
+        buf[bufsize - 1] = '\0';
+        ret              = buf;
+    }
+#ifdef CL_THREAD_SAFE
+    pthread_mutex_unlock(&cli_ctime_mutex);
+#endif
+#endif
+    /* common */
+    if(!ret) {
+        buf[0] = ' ';
+        buf[1] = '\0';
+        return buf;
+    }
+    return ret;
 }
 
 /* Function: readn
         Try hard to read the requested number of bytes
 */
-int cli_readn(int fd, void *buff, unsigned int count)
+int cli_readn(int fd, void* buff, unsigned int count)
 {
-        int retval;
-        unsigned int todo;
-        unsigned char *current;
-
-
-        todo = count;
-        current = (unsigned char *) buff;
-
-        do {
-                retval = read(fd, current, todo);
-                if (retval == 0) {
-                        return (count - todo);
-                }
-                if (retval < 0) {
-			char err[128];
-			if (errno == EINTR) {
-				continue;
-			}
-			cli_errmsg("cli_readn: read error: %s\n", cli_strerror(errno, err, sizeof(err)));
-                        return -1;
-                }
-                todo -= retval;
-                current += retval;
-        } while (todo > 0);
-
+    int retval;
+    unsigned int todo;
+    unsigned char* current;
+
+    todo    = count;
+    current = (unsigned char*)buff;
+
+    do {
+        retval = read(fd, current, todo);
+        if(retval == 0) {
+            return (count - todo);
+        }
+        if(retval < 0) {
+            char err[128];
+            if(errno == EINTR) {
+                continue;
+            }
+            cli_errmsg("cli_readn: read error: %s\n", cli_strerror(errno, err, sizeof(err)));
+            return -1;
+        }
+        todo -= retval;
+        current += retval;
+    } while(todo > 0);
 
-        return count;
+    return count;
 }
 
 /* Function: writen
         Try hard to write the specified number of bytes
 */
-int cli_writen(int fd, const void *buff, unsigned int count)
+int cli_writen(int fd, const void* buff, unsigned int count)
 {
-        int retval;
-        unsigned int todo;
-        const unsigned char *current;
-
-
-        todo = count;
-        current = (const unsigned char *) buff;
-
-        do {
-                retval = write(fd, current, todo);
-                if (retval < 0) {
-			char err[128];
-			if (errno == EINTR) {
-				continue;
-			}
-			cli_errmsg("cli_writen: write error: %s\n", cli_strerror(errno, err, sizeof(err)));
-                        return -1;
-                }
-                todo -= retval;
-                current += retval;
-        } while (todo > 0);
-
+    int retval;
+    unsigned int todo;
+    const unsigned char* current;
+
+    todo    = count;
+    current = (const unsigned char*)buff;
+
+    do {
+        retval = write(fd, current, todo);
+        if(retval < 0) {
+            char err[128];
+            if(errno == EINTR) {
+                continue;
+            }
+            cli_errmsg("cli_writen: write error: %s\n", cli_strerror(errno, err, sizeof(err)));
+            return -1;
+        }
+        todo -= retval;
+        current += retval;
+    } while(todo > 0);
 
-        return count;
+    return count;
 }
 
-int cli_filecopy(const char *src, const char *dest)
+int cli_filecopy(const char* src, const char* dest)
 {
 
 #ifdef _WIN32
     return CopyFileA(src, dest, 0) ? 0 : -1;
 #else
-	char *buffer;
-	int s, d, bytes;
+    char* buffer;
+    int s, d, bytes;
 
+    if((s = open(src, O_RDONLY | O_BINARY)) == -1)
+        return -1;
 
-    if((s = open(src, O_RDONLY|O_BINARY)) == -1)
-	return -1;
-
-    if((d = open(dest, O_CREAT|O_WRONLY|O_TRUNC|O_BINARY, S_IRWXU)) == -1) {
-	close(s);
-	return -1;
+    if((d = open(dest, O_CREAT | O_WRONLY | O_TRUNC | O_BINARY, S_IRWXU)) == -1) {
+        close(s);
+        return -1;
     }
 
     if(!(buffer = cli_malloc(FILEBUFF))) {
-	close(s);
-	close(d);
-	return -1;
+        close(s);
+        close(d);
+        return -1;
     }
 
     while((bytes = cli_readn(s, buffer, FILEBUFF)) > 0)
-	cli_writen(d, buffer, bytes);
+        cli_writen(d, buffer, bytes);
 
     free(buffer);
     close(s);
@@ -437,39 +431,40 @@
 #endif /* _WIN32 */
 #endif /* P_tmpdir */
 
-const char *cli_gettmpdir(void) {
-	const char *tmpdir;
+const char* cli_gettmpdir(void)
+{
+    const char* tmpdir;
     unsigned int i;
 
 #ifdef _WIN32
-    char *envs[] = { "TEMP", "TMP", NULL };
+    char* envs[] = {"TEMP", "TMP", NULL};
 #else
-    char *envs[] = { "TMPDIR", NULL };
+    char* envs[] = {"TMPDIR", NULL};
 #endif
 
-    for (i=0; envs[i] != NULL; i++)
-        if ((tmpdir = getenv(envs[i])))
+    for(i = 0; envs[i] != NULL; i++)
+        if((tmpdir = getenv(envs[i])))
             return tmpdir;
 
     return P_tmpdir;
 }
 
 struct dirent_data {
-    char *filename;
-    const char *dirname;
-    STATBUF *statbuf;
-    long  ino; /* -1: inode not available */
-    int   is_dir;/* 0 - no, 1 - yes */
+    char* filename;
+    const char* dirname;
+    STATBUF* statbuf;
+    long ino;   /* -1: inode not available */
+    int is_dir; /* 0 - no, 1 - yes */
 };
 
 /* sort files before directories, and lower inodes before higher inodes */
-static int ftw_compare(const void *a, const void *b)
+static int ftw_compare(const void* a, const void* b)
 {
-    const struct dirent_data *da = a;
-    const struct dirent_data *db = b;
-    long diff = da->is_dir - db->is_dir;
-    if (!diff) {
-	diff = da->ino - db->ino;
+    const struct dirent_data* da = a;
+    const struct dirent_data* db = b;
+    long diff                    = da->is_dir - db->is_dir;
+    if(!diff) {
+        diff = da->ino - db->ino;
     }
     return diff;
 }
@@ -489,100 +484,98 @@
 }
 
 #define FOLLOW_SYMLINK_MASK (CLI_FTW_FOLLOW_FILE_SYMLINK | CLI_FTW_FOLLOW_DIR_SYMLINK)
-static int get_filetype(const char *fname, int flags, int need_stat,
-			 STATBUF *statbuf, enum filetype *ft)
+static int get_filetype(const char* fname, int flags, int need_stat,
+                        STATBUF* statbuf, enum filetype* ft)
 {
     int stated = 0;
 
-    if (*ft == ft_unknown || *ft == ft_link) {
-	need_stat = 1;
+    if(*ft == ft_unknown || *ft == ft_link) {
+        need_stat = 1;
 
-	if ((flags & FOLLOW_SYMLINK_MASK) != FOLLOW_SYMLINK_MASK) {
-	    /* Following only one of directory/file symlinks, or none, may
+        if((flags & FOLLOW_SYMLINK_MASK) != FOLLOW_SYMLINK_MASK) {
+            /* Following only one of directory/file symlinks, or none, may
 	     * need to lstat.
 	     * If we're following both file and directory symlinks, we don't need
 	     * to lstat(), we can just stat() directly.*/
-	    if (*ft != ft_link) {
-		/* need to lstat to determine if it is a symlink */
-		if (LSTAT(fname, statbuf) == -1)
-		    return -1;
-		if (S_ISLNK(statbuf->st_mode)) {
-		    *ft = ft_link;
-		} else {
-		    /* It was not a symlink, stat() not needed */
-		    need_stat = 0;
-		    stated = 1;
-		}
-	    }
-	    if (*ft == ft_link && !(flags & FOLLOW_SYMLINK_MASK)) {
-		/* This is a symlink, but we don't follow any symlinks */
-		*ft = ft_skipped_link;
-		return 0;
-	    }
-	}
-    }
-
-    if (need_stat) {
-	if (CLAMSTAT(fname, statbuf) == -1)
-	    return -1;
-	stated = 1;
-    }
-
-    if (*ft == ft_unknown || *ft == ft_link) {
-	if (S_ISDIR(statbuf->st_mode) &&
-	    (*ft != ft_link || (flags & CLI_FTW_FOLLOW_DIR_SYMLINK))) {
-	    /* A directory, or (a symlink to a directory and we're following dir
+            if(*ft != ft_link) {
+                /* need to lstat to determine if it is a symlink */
+                if(LSTAT(fname, statbuf) == -1)
+                    return -1;
+                if(S_ISLNK(statbuf->st_mode)) {
+                    *ft = ft_link;
+                } else {
+                    /* It was not a symlink, stat() not needed */
+                    need_stat = 0;
+                    stated    = 1;
+                }
+            }
+            if(*ft == ft_link && !(flags & FOLLOW_SYMLINK_MASK)) {
+                /* This is a symlink, but we don't follow any symlinks */
+                *ft = ft_skipped_link;
+                return 0;
+            }
+        }
+    }
+
+    if(need_stat) {
+        if(CLAMSTAT(fname, statbuf) == -1)
+            return -1;
+        stated = 1;
+    }
+
+    if(*ft == ft_unknown || *ft == ft_link) {
+        if(S_ISDIR(statbuf->st_mode) &&
+           (*ft != ft_link || (flags & CLI_FTW_FOLLOW_DIR_SYMLINK))) {
+            /* A directory, or (a symlink to a directory and we're following dir
 	     * symlinks) */
-	    *ft = ft_directory;
-	} else if (S_ISREG(statbuf->st_mode) &&
-		   (*ft != ft_link || (flags & CLI_FTW_FOLLOW_FILE_SYMLINK))) {
-	    /* A file, or (a symlink to a file and we're following file symlinks) */
-	    *ft = ft_regular;
-	} else {
-	    /* default: skipped */
-	    *ft = S_ISLNK(statbuf->st_mode) ?
-		ft_skipped_link : ft_skipped_special;
-	}
+            *ft = ft_directory;
+        } else if(S_ISREG(statbuf->st_mode) &&
+                  (*ft != ft_link || (flags & CLI_FTW_FOLLOW_FILE_SYMLINK))) {
+            /* A file, or (a symlink to a file and we're following file symlinks) */
+            *ft = ft_regular;
+        } else {
+            /* default: skipped */
+            *ft = S_ISLNK(statbuf->st_mode) ? ft_skipped_link : ft_skipped_special;
+        }
     }
     return stated;
 }
 
-static int handle_filetype(const char *fname, int flags,
-			   STATBUF *statbuf, int *stated, enum filetype *ft,
-			   cli_ftw_cb callback, struct cli_ftw_cbdata *data)
+static int handle_filetype(const char* fname, int flags,
+                           STATBUF* statbuf, int* stated, enum filetype* ft,
+                           cli_ftw_cb callback, struct cli_ftw_cbdata* data)
 {
     int ret;
 
-    *stated = get_filetype(fname, flags, flags & CLI_FTW_NEED_STAT , statbuf, ft);
+    *stated = get_filetype(fname, flags, flags & CLI_FTW_NEED_STAT, statbuf, ft);
 
-    if (*stated == -1) {
-	/*  we failed a stat() or lstat() */
-	ret = callback(NULL, NULL, fname, error_stat, data);
-	if (ret != CL_SUCCESS)
-	    return ret;
-	*ft = ft_unknown;
-    } else if (*ft == ft_skipped_link || *ft == ft_skipped_special) {
-	/* skipped filetype */
-	ret = callback(stated ? statbuf : NULL, NULL, fname,
-		       *ft == ft_skipped_link ?
-		       warning_skipped_link : warning_skipped_special, data);
-	if (ret != CL_SUCCESS)
-	    return ret;
+    if(*stated == -1) {
+        /*  we failed a stat() or lstat() */
+        ret = callback(NULL, NULL, fname, error_stat, data);
+        if(ret != CL_SUCCESS)
+            return ret;
+        *ft = ft_unknown;
+    } else if(*ft == ft_skipped_link || *ft == ft_skipped_special) {
+        /* skipped filetype */
+        ret = callback(stated ? statbuf : NULL, NULL, fname,
+                       *ft == ft_skipped_link ? warning_skipped_link : warning_skipped_special, data);
+        if(ret != CL_SUCCESS)
+            return ret;
     }
     return CL_SUCCESS;
 }
 
-static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk);
-static int handle_entry(struct dirent_data *entry, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk)
+static int cli_ftw_dir(const char* dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata* data, cli_ftw_pathchk pathchk);
+static int handle_entry(struct dirent_data* entry, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata* data, cli_ftw_pathchk pathchk)
 {
-    if (!entry->is_dir) {
-	return callback(entry->statbuf, entry->filename, entry->filename, visit_file, data);
+    if(!entry->is_dir) {
+        return callback(entry->statbuf, entry->filename, entry->filename, visit_file, data);
     } else {
-	return cli_ftw_dir(entry->dirname, flags, maxdepth, callback, data, pathchk);
+        return cli_ftw_dir(entry->dirname, flags, maxdepth, callback, data, pathchk);
     }
 }
 
-int cli_ftw(char *path, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk)
+int cli_ftw(char* path, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata* data, cli_ftw_pathchk pathchk)
 {
     STATBUF statbuf;
     enum filetype ft = ft_unknown;
@@ -590,215 +583,215 @@
     int stated = 0;
     int ret;
 
-    if (((flags & CLI_FTW_TRIM_SLASHES) || pathchk) && path[0] && path[1]) {
-	char *pathend;
-	/* trim slashes so that dir and dir/ behave the same when
+    if(((flags & CLI_FTW_TRIM_SLASHES) || pathchk) && path[0] && path[1]) {
+        char* pathend;
+        /* trim slashes so that dir and dir/ behave the same when
 	 * they are symlinks, and we are not following symlinks */
 #ifndef _WIN32
-	while (path[0] == *PATHSEP && path[1] == *PATHSEP) path++;
+        while(path[0] == *PATHSEP && path[1] == *PATHSEP) path++;
 #endif
-	pathend = path + strlen(path);
-	while (pathend > path && pathend[-1] == *PATHSEP) --pathend;
-	*pathend = '\0';
+        pathend = path + strlen(path);
+        while(pathend > path && pathend[-1] == *PATHSEP) --pathend;
+        *pathend = '\0';
     }
     if(pathchk && pathchk(path, data) == 1)
-	return CL_SUCCESS;
+        return CL_SUCCESS;
     ret = handle_filetype(path, flags, &statbuf, &stated, &ft, callback, data);
-    if (ret != CL_SUCCESS)
-	return ret;
-    if (ft_skipped(ft))
-	return CL_SUCCESS;
-    entry.statbuf = stated ? &statbuf : NULL;
-    entry.is_dir = ft == ft_directory;
+    if(ret != CL_SUCCESS)
+        return ret;
+    if(ft_skipped(ft))
+        return CL_SUCCESS;
+    entry.statbuf  = stated ? &statbuf : NULL;
+    entry.is_dir   = ft == ft_directory;
     entry.filename = entry.is_dir ? NULL : strdup(path);
-    entry.dirname = entry.is_dir ? path : NULL;
-    if (entry.is_dir) {
-	ret = callback(entry.statbuf, NULL, path, visit_directory_toplev, data);
-	if (ret != CL_SUCCESS)
-	    return ret;
+    entry.dirname  = entry.is_dir ? path : NULL;
+    if(entry.is_dir) {
+        ret = callback(entry.statbuf, NULL, path, visit_directory_toplev, data);
+        if(ret != CL_SUCCESS)
+            return ret;
     }
     return handle_entry(&entry, flags, maxdepth, callback, data, pathchk);
 }
 
-static int cli_ftw_dir(const char *dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata *data, cli_ftw_pathchk pathchk)
+static int cli_ftw_dir(const char* dirname, int flags, int maxdepth, cli_ftw_cb callback, struct cli_ftw_cbdata* data, cli_ftw_pathchk pathchk)
 {
-    DIR *dd;
+    DIR* dd;
 #if defined(HAVE_READDIR_R_3) || defined(HAVE_READDIR_R_2)
     union {
-	struct dirent d;
-	char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
+        struct dirent d;
+        char b[offsetof(struct dirent, d_name) + NAME_MAX + 1];
     } result;
 #endif
-    struct dirent_data *entries = NULL;
+    struct dirent_data* entries = NULL;
     size_t i, entries_cnt = 0;
     int ret;
 
-    if (maxdepth < 0) {
-	/* exceeded recursion limit */
-	ret = callback(NULL, NULL, dirname, warning_skipped_dir, data);
-	return ret;
+    if(maxdepth < 0) {
+        /* exceeded recursion limit */
+        ret = callback(NULL, NULL, dirname, warning_skipped_dir, data);
+        return ret;
     }
 
     if((dd = opendir(dirname)) != NULL) {
-	struct dirent *dent;
-	int err;
-	errno = 0;
-	ret = CL_SUCCESS;
+        struct dirent* dent;
+        int err;
+        errno = 0;
+        ret   = CL_SUCCESS;
 #ifdef HAVE_READDIR_R_3
-	while(!(err = readdir_r(dd, &result.d, &dent)) && dent) {
+        while(!(err = readdir_r(dd, &result.d, &dent)) && dent) {
 #elif defined(HAVE_READDIR_R_2)
-	while((dent = (struct dirent *) readdir_r(dd, &result.d))) {
+        while((dent = (struct dirent*)readdir_r(dd, &result.d))) {
 #else
-	while((dent = readdir(dd))) {
+        while((dent = readdir(dd))) {
 #endif
-	    int stated = 0;
-	    enum filetype ft;
-	    char *fname;
-	    STATBUF statbuf;
-	    STATBUF *statbufp;
+            int stated = 0;
+            enum filetype ft;
+            char* fname;
+            STATBUF statbuf;
+            STATBUF* statbufp;
 
-	    if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
-		continue;
+            if(!strcmp(dent->d_name, ".") || !strcmp(dent->d_name, ".."))
+                continue;
 #ifdef _DIRENT_HAVE_D_TYPE
-	    switch (dent->d_type) {
-		case DT_DIR:
-		    ft = ft_directory;
-		    break;
-		case DT_LNK:
-		    if (!(flags & FOLLOW_SYMLINK_MASK)) {
-			/* we don't follow symlinks, don't bother
+            switch(dent->d_type) {
+            case DT_DIR:
+                ft = ft_directory;
+                break;
+            case DT_LNK:
+                if(!(flags & FOLLOW_SYMLINK_MASK)) {
+                    /* we don't follow symlinks, don't bother
 			 * stating it */
-			errno = 0;
-			continue;
-		    }
-		    ft = ft_link;
-		    break;
-		case DT_REG:
-		    ft = ft_regular;
-		    break;
-		case DT_UNKNOWN:
-		    ft = ft_unknown;
-		    break;
-		default:
-		    ft = ft_skipped_special;
-		    break;
-	    }
+                    errno = 0;
+                    continue;
+                }
+                ft = ft_link;
+                break;
+            case DT_REG:
+                ft = ft_regular;
+                break;
+            case DT_UNKNOWN:
+                ft = ft_unknown;
+                break;
+            default:
+                ft = ft_skipped_special;
+                break;
+            }
 #else
-	    ft = ft_unknown;
+            ft = ft_unknown;
 #endif
-	    fname = (char *) cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
-	    if(!fname) {
-		ret = callback(NULL, NULL, dirname, error_mem, data);
-		if (ret != CL_SUCCESS)
-		    break;
-		continue; /* have to skip this one if continuing after error */
-	    }
+            fname = (char*)cli_malloc(strlen(dirname) + strlen(dent->d_name) + 2);
+            if(!fname) {
+                ret = callback(NULL, NULL, dirname, error_mem, data);
+                if(ret != CL_SUCCESS)
+                    break;
+                continue; /* have to skip this one if continuing after error */
+            }
             if(!strcmp(dirname, PATHSEP))
-		sprintf(fname, PATHSEP"%s", dent->d_name);
-	    else
-		sprintf(fname, "%s"PATHSEP"%s", dirname, dent->d_name);
-
-	    if(pathchk && pathchk(fname, data) == 1) {
-		free(fname);
-		continue;
-	    }
-
-	    ret = handle_filetype(fname, flags, &statbuf, &stated, &ft, callback, data);
-	    if (ret != CL_SUCCESS) {
-		free(fname);
-		break;
-	    }
-
-	    if (ft_skipped(ft)) { /* skip */
-		free(fname);
-		errno = 0;
-		continue;
-	    }
-
-	    if (stated && (flags & CLI_FTW_NEED_STAT)) {
-		statbufp = cli_malloc(sizeof(*statbufp));
-		if (!statbufp) {
-		    ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
-		    free(fname);
-		    if (ret != CL_SUCCESS)
-			break;
-		    else {
-			errno = 0;
-			continue;
-		    }
-		}
-		memcpy(statbufp, &statbuf, sizeof(statbuf));
-	    } else {
-		statbufp = 0;
-	    }
-
-	    entries_cnt++;
-	    entries = cli_realloc(entries, entries_cnt*sizeof(*entries));
-	    if (!entries) {
-		ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
-		free(fname);
-		if (statbufp)
-		    free(statbufp);
-		break;
-	    } else {
-		struct dirent_data *entry = &entries[entries_cnt-1];
-		entry->filename = fname;
-		entry->statbuf = statbufp;
-		entry->is_dir = ft == ft_directory;
-		entry->dirname = entry->is_dir ? fname : NULL;
+                sprintf(fname, PATHSEP "%s", dent->d_name);
+            else
+                sprintf(fname, "%s" PATHSEP "%s", dirname, dent->d_name);
+
+            if(pathchk && pathchk(fname, data) == 1) {
+                free(fname);
+                continue;
+            }
+
+            ret = handle_filetype(fname, flags, &statbuf, &stated, &ft, callback, data);
+            if(ret != CL_SUCCESS) {
+                free(fname);
+                break;
+            }
+
+            if(ft_skipped(ft)) { /* skip */
+                free(fname);
+                errno = 0;
+                continue;
+            }
+
+            if(stated && (flags & CLI_FTW_NEED_STAT)) {
+                statbufp = cli_malloc(sizeof(*statbufp));
+                if(!statbufp) {
+                    ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
+                    free(fname);
+                    if(ret != CL_SUCCESS)
+                        break;
+                    else {
+                        errno = 0;
+                        continue;
+                    }
+                }
+                memcpy(statbufp, &statbuf, sizeof(statbuf));
+            } else {
+                statbufp = 0;
+            }
+
+            entries_cnt++;
+            entries = cli_realloc(entries, entries_cnt * sizeof(*entries));
+            if(!entries) {
+                ret = callback(stated ? &statbuf : NULL, NULL, fname, error_mem, data);
+                free(fname);
+                if(statbufp)
+                    free(statbufp);
+                break;
+            } else {
+                struct dirent_data* entry = &entries[entries_cnt - 1];
+                entry->filename           = fname;
+                entry->statbuf            = statbufp;
+                entry->is_dir             = ft == ft_directory;
+                entry->dirname            = entry->is_dir ? fname : NULL;
 #ifdef _XOPEN_UNIX
-		entry->ino = dent->d_ino;
+                entry->ino = dent->d_ino;
 #else
-		entry->ino = -1;
+                entry->ino = -1;
 #endif
-	    }
-	    errno = 0;
-	}
+            }
+            errno = 0;
+        }
 #ifndef HAVE_READDIR_R_3
-	err = errno;
+        err = errno;
 #endif
-	closedir(dd);
-	ret = CL_SUCCESS;
-	if (err) {
-	    char errs[128];
-	    cli_errmsg("Unable to readdir() directory %s: %s\n", dirname,
-		       cli_strerror(errno, errs, sizeof(errs)));
-	    /* report error to callback using error_stat */
-	    ret = callback(NULL, NULL, dirname, error_stat, data);
-	    if (ret != CL_SUCCESS) {
-		if (entries) {
-		    for (i=0;i<entries_cnt;i++) {
-			struct dirent_data *entry = &entries[i];
-			free(entry->filename);
-			free(entry->statbuf);
-		    }
-		    free(entries);
-		}
-		return ret;
-	    }
-	}
-
-	if (entries) {
-	    cli_qsort(entries, entries_cnt, sizeof(*entries), ftw_compare);
-	    for (i = 0; i < entries_cnt; i++) {
-		struct dirent_data *entry = &entries[i];
-		ret = handle_entry(entry, flags, maxdepth-1, callback, data, pathchk);
-		if (entry->is_dir)
-		    free(entry->filename);
-		if (entry->statbuf)
-		    free(entry->statbuf);
-		if (ret != CL_SUCCESS)
-		    break;
-	    }
-	    for (i++;i<entries_cnt;i++) {
-		struct dirent_data *entry = &entries[i];
-		free(entry->filename);
-		free(entry->statbuf);
-	    }
-	    free(entries);
-	}
+        closedir(dd);
+        ret = CL_SUCCESS;
+        if(err) {
+            char errs[128];
+            cli_errmsg("Unable to readdir() directory %s: %s\n", dirname,
+                       cli_strerror(errno, errs, sizeof(errs)));
+            /* report error to callback using error_stat */
+            ret = callback(NULL, NULL, dirname, error_stat, data);
+            if(ret != CL_SUCCESS) {
+                if(entries) {
+                    for(i = 0; i < entries_cnt; i++) {
+                        struct dirent_data* entry = &entries[i];
+                        free(entry->filename);
+                        free(entry->statbuf);
+                    }
+                    free(entries);
+                }
+                return ret;
+            }
+        }
+
+        if(entries) {
+            cli_qsort(entries, entries_cnt, sizeof(*entries), ftw_compare);
+            for(i = 0; i < entries_cnt; i++) {
+                struct dirent_data* entry = &entries[i];
+                ret                       = handle_entry(entry, flags, maxdepth - 1, callback, data, pathchk);
+                if(entry->is_dir)
+                    free(entry->filename);
+                if(entry->statbuf)
+                    free(entry->statbuf);
+                if(ret != CL_SUCCESS)
+                    break;
+            }
+            for(i++; i < entries_cnt; i++) {
+                struct dirent_data* entry = &entries[i];
+                free(entry->filename);
+                free(entry->statbuf);
+            }
+            free(entries);
+        }
     } else {
-	ret = callback(NULL, NULL, dirname, error_stat, data);
+        ret = callback(NULL, NULL, dirname, error_stat, data);
     }
     return ret;
 }
@@ -806,39 +799,39 @@
 /* strerror_r is not available everywhere, (and when it is there are two variants,
  * the XSI, and the GNU one, so provide a wrapper to make sure correct one is
  * used */
-const char* cli_strerror(int errnum, char *buf, size_t len)
+const char* cli_strerror(int errnum, char* buf, size_t len)
 {
-    char *err;
-# ifdef CL_THREAD_SAFE
+    char* err;
+#ifdef CL_THREAD_SAFE
     pthread_mutex_lock(&cli_strerror_mutex);
 #endif
     err = strerror(errnum);
     strncpy(buf, err, len);
-    buf[len-1] = '\0'; /* just in case */
-# ifdef CL_THREAD_SAFE
+    buf[len - 1] = '\0'; /* just in case */
+#ifdef CL_THREAD_SAFE
     pthread_mutex_unlock(&cli_strerror_mutex);
 #endif
     return buf;
 }
 
-static char *cli_md5buff(const unsigned char *buffer, unsigned int len, unsigned char *dig)
+static char* cli_md5buff(const unsigned char* buffer, unsigned int len, unsigned char* dig)
 {
-	unsigned char digest[16];
-	char *md5str, *pt;
-	int i;
+    unsigned char digest[16];
+    char *md5str, *pt;
+    int i;
 
     cl_hash_data("md5", buffer, len, digest, NULL);
 
     if(dig)
-	memcpy(dig, digest, 16);
+        memcpy(dig, digest, 16);
 
-    if(!(md5str = (char *) cli_calloc(32 + 1, sizeof(char))))
-	return NULL;
+    if(!(md5str = (char*)cli_calloc(32 + 1, sizeof(char))))
+        return NULL;
 
     pt = md5str;
     for(i = 0; i < 16; i++) {
-	sprintf(pt, "%02x", digest[i]);
-	pt += 2;
+        sprintf(pt, "%02x", digest[i]);
+        pt += 2;
     }
 
     return md5str;
@@ -847,30 +840,148 @@
 unsigned int cli_rndnum(unsigned int max)
 {
     if(name_salt[0] == 16) { /* minimizes re-seeding after the first call to cli_gentemp() */
-	    struct timeval tv;
-	gettimeofday(&tv, (struct timezone *) 0);
-	srand(tv.tv_usec+clock()+rand());
+        struct timeval tv;
+        gettimeofday(&tv, (struct timezone*)0);
+        srand(tv.tv_usec + clock() + rand());
     }
 
-    return 1 + (unsigned int) (max * (rand() / (1.0 + RAND_MAX)));
+    return 1 + (unsigned int)(max * (rand() / (1.0 + RAND_MAX)));
 }
 
-char* cli_genfname(const char * prefix)
+char* cli_sanitize_filepath(const char* filepath, size_t filepath_len)
 {
-	char* fname;
+    uint32_t depth           = 0;
+    size_t index             = 0;
+    size_t sanitized_index   = 0;
+    char* sanitized_filepath = NULL;
+
+    if((NULL == filepath) || (0 == filepath_len) || (MAX_PATH < filepath_len)) {
+        goto done;
+    }
+
+    sanitized_filepath = cli_calloc(filepath_len + 1, sizeof(unsigned char));
+    if(NULL == sanitized_filepath) {
+        cli_dbgmsg("cli_sanitize_filepath: out of memory\n");
+        goto done;
+    }
+
+    while(index < filepath_len) {
+        char* next_pathsep = NULL;
+
+        if(0 == strncmp(filepath + index, PATHSEP, strlen(PATHSEP))) {
+            /*
+             * Is "/" (or "\\" on Windows)
+             */
+            /* Skip leading pathsep in absolute path, or extra pathsep) */
+            index += strlen(PATHSEP);
+            continue;
+        } else if(0 == strncmp(filepath + index, "." PATHSEP, strlen("." PATHSEP))) {
+            /*
+             * Is "./" (or ".\\" on Windows)
+             */
+            /* Current directory indicator is meaningless and should not add to the depth. Skip it. */
+            index += strlen("." PATHSEP);
+            continue;
+        } else if(0 == strncmp(filepath + index, ".." PATHSEP, strlen(".." PATHSEP))) {
+            /*
+             * Is "../" (or "..\\" on Windows)
+             */
+            if(depth == 0) {
+                /* Relative path would traverse parent directory. Skip it. */
+                index += strlen(".." PATHSEP);
+                continue;
+            } else {
+                /* Relative path is safe. Allow it. */
+                strncpy(sanitized_filepath + sanitized_index, filepath + index, strlen(".." PATHSEP));
+                sanitized_index += strlen(".." PATHSEP);
+                index += strlen(".." PATHSEP);
+                depth--;
+            }
+        }
+#ifdef _WIN32
+        /*
+         * Windows' POSIX style API's accept both "/" and "\\" style path separators.
+         * The following checks using POSIX style path separators on Windows.
+         */
+        else if(0 == strncmp(filepath + index, "/", strlen("/"))) {
+            /*
+             * Is "/".
+             */
+            /* Skip leading pathsep in absolute path, or extra pathsep) */
+            index += strlen("/");
+            continue;
+        } else if(0 == strncmp(filepath + index, "./", strlen("./"))) {
+            /*
+             * Is "./"
+             */
+            /* Current directory indicator is meaningless and should not add to the depth. Skip it. */
+            index += strlen("./");
+            continue;
+        } else if(0 == strncmp(filepath + index, "../", strlen("../"))) {
+            /*
+             * Is "../"
+             */
+            if(depth == 0) {
+                /* Relative path would traverse parent directory. Skip it. */
+                index += strlen("../");
+                continue;
+            } else {
+                /* Relative path is safe. Allow it. */
+                strncpy(sanitized_filepath + sanitized_index, filepath + index, strlen("../"));
+                sanitized_index += strlen("../");
+                index += strlen("../");
+                depth--;
+            }
+        }
+#endif
+        else {
+            /*
+             * Is not "/", "./", or "../".
+             */
+            /* Find the next path separator. */
+            next_pathsep = cli_strnstr(filepath + index, PATHSEP, filepath_len - index);
+            if(NULL == next_pathsep) {
+                /* No more path separators, copy the rest (filename) into the sanitized path */
+                strncpy(sanitized_filepath + sanitized_index, filepath + index, filepath_len - index);
+                break;
+            }
+            next_pathsep += strlen(PATHSEP); /* Include the path separator in the copy */
+
+            /* Copy next directory name into the sanitized path */
+            strncpy(sanitized_filepath + sanitized_index, filepath + index, next_pathsep - (filepath + index));
+            sanitized_index += next_pathsep - (filepath + index);
+            index += next_pathsep - (filepath + index);
+            depth++;
+        }
+    }
+
+done:
+    if((NULL != sanitized_filepath) && (0 == strlen(sanitized_filepath))) {
+        free(sanitized_filepath);
+        sanitized_filepath = NULL;
+    }
+
+    return sanitized_filepath;
+}
+
+char* cli_genfname(const char* prefix)
+{
+    char* sanitized_prefix = NULL;
+    char* fname            = NULL;
     unsigned char salt[16 + 32];
     char* tmp;
     int i;
-	size_t len;
+    size_t len;
 
-	if (prefix && (strlen(prefix) > 0)) {
-    	len = strlen(prefix) + 1 + 5 + 1;  /* {prefix}.{5}\0 */
-	} else {
-    	len = 6 + 1 + 48 + 4 + 1;  /* clamav-{48}.tmp\0 */
-	}
+    if(prefix && (strlen(prefix) > 0)) {
+        sanitized_prefix = cli_sanitize_filepath(prefix, strlen(prefix));
+        len              = strlen(sanitized_prefix) + 1 + 5 + 1; /* {prefix}.{5}\0 */
+    } else {
+        len = 6 + 1 + 48 + 4 + 1; /* clamav-{48}.tmp\0 */
+    }
 
     fname = (char*)cli_calloc(len, sizeof(char));
-    if (!fname) {
+    if(!fname) {
         cli_dbgmsg("cli_genfname: out of memory\n");
         return NULL;
     }
@@ -881,7 +992,7 @@
 
     memcpy(salt, name_salt, 16);
 
-    for (i = 16; i < 48; i++)
+    for(i = 16; i < 48; i++)
         salt[i] = cli_rndnum(255);
 
     tmp = cli_md5buff(salt, 48, name_salt);
@@ -890,18 +1001,19 @@
     pthread_mutex_unlock(&cli_gentemp_mutex);
 #endif
 
-    if (!tmp) {
+    if(!tmp) {
         free(fname);
         cli_dbgmsg("cli_genfname: out of memory\n");
         return NULL;
     }
 
-	if (prefix && (strlen(prefix) > 0)) {
-		fname[5] = '\0';
-    	snprintf(fname, len, "%s.%s", prefix, tmp);
-	} else {
-    	snprintf(fname, len, "clamav-%s.tmp", tmp);
-	}
+    if(sanitized_prefix && (strlen(sanitized_prefix) > 0)) {
+        fname[5] = '\0';
+        snprintf(fname, len, "%s.%s", sanitized_prefix, tmp);
+        free(sanitized_prefix);
+    } else {
+        snprintf(fname, len, "clamav-%s.tmp", tmp);
+    }
 
     free(tmp);
 
@@ -910,7 +1022,7 @@
 
 char* cli_gentemp_with_prefix(const char* dir, const char* prefix)
 {
-	char* fname;
+    char* fname;
     char* fullpath;
     const char* mdir;
     int i;
@@ -918,32 +1030,32 @@
 
     mdir = dir ? dir : cli_gettmpdir();
 
-	fname = cli_genfname(prefix);
-    if (!fname) {
+    fname = cli_genfname(prefix);
+    if(!fname) {
         cli_dbgmsg("cli_gentemp('%s'): out of memory\n", mdir);
         return NULL;
     }
 
-    len = strlen(mdir) + strlen(PATHSEP) + strlen(fname) + 1; /* mdir/fname\0 */
+    len      = strlen(mdir) + strlen(PATHSEP) + strlen(fname) + 1; /* mdir/fname\0 */
     fullpath = (char*)cli_calloc(len, sizeof(char));
-    if (!fullpath) {
+    if(!fullpath) {
         free(fname);
         cli_dbgmsg("cli_gentemp('%s'): out of memory\n", mdir);
         return NULL;
     }
 
     snprintf(fullpath, len, "%s" PATHSEP "%s", mdir, fname);
-	free(fname);
+    free(fname);
 
     return (fullpath);
 }
 
 char* cli_gentemp(const char* dir)
 {
-	return cli_gentemp_with_prefix(dir, NULL);
+    return cli_gentemp_with_prefix(dir, NULL);
 }
 
-cl_error_t cli_gentempfd(const char *dir, char **name, int *fd)
+cl_error_t cli_gentempfd(const char* dir, char** name, int* fd)
 {
     return cli_gentempfd_with_prefix(dir, NULL, name, fd);
 }
@@ -951,7 +1063,7 @@
 cl_error_t cli_gentempfd_with_prefix(const char* dir, char* prefix, char** name, int* fd)
 {
     *name = cli_gentemp_with_prefix(dir, prefix);
-    if (!*name)
+    if(!*name)
         return CL_EMEM;
 
     *fd = open(*name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, S_IRWXU);
@@ -959,15 +1071,15 @@
      * EEXIST is almost impossible to occur, so we just treat it as other
      * errors
      */
-    if (*fd == -1) {
-        if ((EILSEQ == errno) || (EINVAL == errno) || (ENAMETOOLONG == errno)) {
+    if(*fd == -1) {
+        if((EILSEQ == errno) || (EINVAL == errno) || (ENAMETOOLONG == errno)) {
             cli_dbgmsg("cli_gentempfd_with_prefix: Can't create temp file using prefix. Using a randomly generated name instead.\n");
             free(*name);
             *name = cli_gentemp(dir);
-            if (!*name)
+            if(!*name)
                 return CL_EMEM;
             *fd = open(*name, O_RDWR | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, S_IRWXU);
-            if (*fd == -1) {
+            if(*fd == -1) {
                 cli_errmsg("cli_gentempfd_with_prefix: Can't create temporary file %s: %s\n", *name, strerror(errno));
                 free(*name);
                 *name = NULL;
@@ -984,11 +1096,11 @@
     return CL_SUCCESS;
 }
 
-int cli_regcomp(regex_t *preg, const char *pattern, int cflags)
+int cli_regcomp(regex_t* preg, const char* pattern, int cflags)
 {
-    if (!strncmp(pattern, "(?i)", 4)) {
-	pattern += 4;
-	cflags |= REG_ICASE;
+    if(!strncmp(pattern, "(?i)", 4)) {
+        pattern += 4;
+        cflags |= REG_ICASE;
     }
     return cli_regcomp_real(preg, pattern, cflags);
 }
@@ -997,7 +1109,7 @@
 {
     cl_error_t status = CL_EARG;
 
-    if (NULL == filepath) {
+    if(NULL == filepath) {
         cli_errmsg("cli_get_filepath_from_filedesc: Invalid args.\n");
         goto done;
     }
@@ -1013,77 +1125,77 @@
     snprintf(link, sizeof(link), "/proc/self/fd/%u", desc);
     link[sizeof(link) - 1] = '\0';
 
-    if (-1 == (linksz = readlink(link, fname, PATH_MAX - 1))) {
+    if(-1 == (linksz = readlink(link, fname, PATH_MAX - 1))) {
         cli_errmsg("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d (%s)\n", desc, link);
         status = CL_EOPEN;
         goto done;
     }
 
-	/* Success. Add null terminator */
-	fname[linksz] = '\0';
+    /* Success. Add null terminator */
+    fname[linksz] = '\0';
 
     *filepath = cli_strndup(fname, cli_strnlen(fname, PATH_MAX));
-	if (NULL == *filepath) {
-		cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate memory to store filename\n");
-		status = CL_EMEM;
-		goto done;
-	}
+    if(NULL == *filepath) {
+        cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate memory to store filename\n");
+        status = CL_EMEM;
+        goto done;
+    }
 
 #elif __APPLE__
     char fname[PATH_MAX];
     memset(&fname, 0, PATH_MAX);
 
-    if (fcntl(desc, F_GETPATH, &fname) < 0) {
+    if(fcntl(desc, F_GETPATH, &fname) < 0) {
         printf("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d\n", desc);
         status = CL_EOPEN;
         goto done;
     }
 
     *filepath = cli_strndup(fname, cli_strnlen(fname, PATH_MAX));
-	if (NULL == *filepath) {
-		cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate memory to store filename\n");
-		status = CL_EMEM;
-		goto done;
-	}
+    if(NULL == *filepath) {
+        cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate memory to store filename\n");
+        status = CL_EMEM;
+        goto done;
+    }
 
 #elif _WIN32
     DWORD dwRet = 0;
     intptr_t hFile = _get_osfhandle(desc);
 
     dwRet = GetFinalPathNameByHandleA((HANDLE)hFile, NULL, 0, VOLUME_NAME_NT);
-    if (dwRet == 0) {
+    if(dwRet == 0) {
         cli_errmsg("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d\n", desc);
-		status = CL_EOPEN;
-		goto done;
+        status = CL_EOPEN;
+        goto done;
     }
 
-	*filepath = calloc(dwRet + 1, 1);
-	if (NULL == *filepath) {
-		cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate %u bytes to store filename\n", dwRet + 1);
-		status = CL_EMEM;
-		goto done;
-	}
-
-	dwRet = GetFinalPathNameByHandleA((HANDLE)hFile, *filepath, dwRet + 1, VOLUME_NAME_NT);
-	if (dwRet == 0) {
-		cli_errmsg("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d\n", desc);
-		free(*filepath);
-		*filepath = NULL;
-		status = CL_EOPEN;
-		goto done;
-	}
+    *filepath = calloc(dwRet + 1, 1);
+    if(NULL == *filepath) {
+        cli_errmsg("cli_get_filepath_from_filedesc: Failed to allocate %u bytes to store filename\n", dwRet + 1);
+        status = CL_EMEM;
+        goto done;
+    }
+
+    dwRet = GetFinalPathNameByHandleA((HANDLE)hFile, *filepath, dwRet + 1, VOLUME_NAME_NT);
+    if(dwRet == 0) {
+        cli_errmsg("cli_get_filepath_from_filedesc: Failed to resolve filename for descriptor %d\n", desc);
+        free(*filepath);
+        *filepath = NULL;
+        status = CL_EOPEN;
+        goto done;
+    }
 
 #else
 
-	cli_dbgmsg("cli_get_filepath_from_filedesc: No mechanism implemented to determine filename from file descriptor.\n");
-	*filepath = NULL;
-	status = CL_BREAK;
-	goto done;
+    cli_dbgmsg("cli_get_filepath_from_filedesc: No mechanism implemented to determine filename from file descriptor.\n");
+    *filepath = NULL;
+    status    = CL_BREAK;
+    goto done;
 
 #endif
 
-	cli_dbgmsg("cli_get_filepath_from_filedesc: File path for fd [%d] is: %s\n", desc, *filepath);
-	status = CL_SUCCESS;
+    cli_dbgmsg("cli_get_filepath_from_filedesc: File path for fd [%d] is: %s\n", desc, *filepath);
+    status = CL_SUCCESS;
 
 done:
 
diff -Nru clamav-0.101.1+dfsg/libclamav/others.h clamav-0.101.2+dfsg/libclamav/others.h
--- clamav-0.101.1+dfsg/libclamav/others.h	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/others.h	2019-03-13 22:13:01.000000000 +0100
@@ -496,6 +496,7 @@
 #define SCAN_COLLECT_METADATA                   (ctx->options->general & CL_SCAN_GENERAL_COLLECT_METADATA)
 #define SCAN_HEURISTICS                         (ctx->options->general & CL_SCAN_GENERAL_HEURISTICS)
 #define SCAN_HEURISTIC_PRECEDENCE               (ctx->options->general & CL_SCAN_GENERAL_HEURISTIC_PRECEDENCE)
+#define SCAN_UNPRIVILEGED                       (ctx->options->general & CL_SCAN_GENERAL_UNPRIVILEGED)
 
 #define SCAN_PARSE_ARCHIVE                      (ctx->options->parse & CL_SCAN_PARSE_ARCHIVE)
 #define SCAN_PARSE_ELF                          (ctx->options->parse & CL_SCAN_PARSE_ELF)
@@ -538,7 +539,7 @@
 		     (((v) & 0x00ff000000000000ULL) >> 40) | \
 		     (((v) & 0xff00000000000000ULL) >> 56))
 
-#ifndef HAVE_ATTRIB_PACKED 
+#ifndef HAVE_ATTRIB_PACKED
 #define __attribute__(x)
 #endif
 #ifdef HAVE_PRAGMA_PACK
@@ -750,19 +751,28 @@
 const char *cli_gettmpdir(void);
 
 /**
+ * @brief Sanitize a relative path, so it cannot have a negative depth.
+ *
+ * Caller is responsible for freeing the filename.
+ *
+ * @return char* filename or NULL.
+ */
+char *cli_sanitize_filepath(const char *filepath, size_t filepath_len);
+
+/**
  * @brief Generate tempfile filename (no path) with a random MD5 hash.
- * 
+ *
  * Caller is responsible for freeing the filename.
- * 
+ *
  * @return char* filename or NULL.
  */
 char *cli_genfname(const char *prefix);
 
 /**
  * @brief Generate a full tempfile filepath with a random MD5 hash and prefix the name, if provided.
- * 
+ *
  * Caller is responsible for freeing the filename.
- * 
+ *
  * @param dir 	 Alternative temp directory. (optional)
  * @return char* filename or NULL.
  */
diff -Nru clamav-0.101.1+dfsg/libclamav/pdf.c clamav-0.101.2+dfsg/libclamav/pdf.c
--- clamav-0.101.1+dfsg/libclamav/pdf.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/pdf.c	2019-03-13 22:13:01.000000000 +0100
@@ -134,14 +134,14 @@
     if (xref + 4 >= eof)
         return -1;
 
-    if (!memcmp(xref, "xref", 4)) {
+    if (!memcmp(xref, "xref", strlen("xref"))) {
         cli_dbgmsg("cli_pdf: found xref\n");
         return 0;
     }
 
     /* could be xref stream */
     for (q=xref; q+5 < eof; q++) {
-        if (!memcmp(q,"/XRef",4)) {
+        if (!memcmp(q,"/XRef", strlen("/XRef"))) {
             cli_dbgmsg("cli_pdf: found /XRef\n");
             return 0;
         }
@@ -163,10 +163,10 @@
 
 /**
  * @brief   Searching BACKwards, find the next character that is not a whitespace.
- * 
+ *
  * @param q         Index to start from (at the end of the search space)
- * @param start     Beginning of the search space. 
- * 
+ * @param start     Beginning of the search space.
+ *
  * @return const char*  Address of the final non-whitespace character OR the same address as the start.
  */
 static const char *findNextNonWSBack(const char *q, const char *start)
@@ -195,101 +195,116 @@
 
 /**
  * @brief   Find bounds of stream.
- * 
+ *
  * PDF streams are prefixed with "stream" and suffixed with "endstream".
  * Return value indicates success or failure.
- * 
+ *
  * @param start             start address of search space.
- * @param bytesleft         size of search space for "stream"
- * @param bytesleft2        size of search space for "endstream"
+ * @param size              size of search space
  * @param[out] stream       output param, address of start of stream data
- * @param[out] endstream    output param, address of end of stream data
+ * @param[out] stream_size  output param, size of stream data
  * @param newline_hack      hack to support newlines that are \r\n, and not just \n or just \r.
- * 
- * @return int  1 if stream bounds were found. 
- * @return int  0 if stream bounds could not be found. 
+ *
+ * @return cl_error_t       CL_SUCCESS if stream bounds were found.
+ * @return cl_error_t       CL_BREAK if stream bounds could not be found.
+ * @return cl_error_t       CL_EFORMAT if stream start was found, but not end. (truncated)
+ * @return cl_error_t       CL_EARG if invalid args were provided.
  */
-static int find_stream_bounds(
-    const char *start, 
-    off_t bytesleft, 
-    off_t bytesleft2, 
-    off_t *stream, 
-    off_t *endstream, 
+static cl_error_t find_stream_bounds(
+    const char *start,
+    size_t size,
+    const char **stream,
+    size_t *stream_size,
     int newline_hack)
 {
-    const char *q2, *q;
+    cl_error_t status = CL_BREAK;
+
+    const char *idx;
+    const char *stream_begin;
+    const char *endstream_begin;
+    size_t bytesleft = size;
+
+    if ((NULL == start) || (0 == bytesleft) || (NULL == stream) || (NULL == stream_size)) {
+        status = CL_EARG;
+        return status;
+    }
+
+    *stream = NULL;
+    *stream_size = 0;
 
     /* Begin by finding the "stream" string that prefixes stream data. */
-    if ((q2 = cli_memstr(start, bytesleft, "stream", 6))) {
-        q2 += 6;
-        bytesleft -= q2 - start;
+    if ((stream_begin = cli_memstr(start, bytesleft, "stream", strlen("stream")))) {
+        idx = stream_begin + strlen("stream");
+        bytesleft -= idx - start;
         if (bytesleft < 0)
-            return 0;
+            goto done;
 
         /* Skip any new line charcters. */
-        if (bytesleft >= 2 && q2[0] == '\xd' && q2[1] == '\xa') {
-            q2 += 2;
-            if (newline_hack && (bytesleft > 2) && q2[0] == '\xa')
-                q2++;
-        } else if (bytesleft && q2[0] == '\xa') {
-            q2++;
+        if (bytesleft >= 2 && idx[0] == '\xd' && idx[1] == '\xa') {
+            idx += 2;
+            if (newline_hack && (bytesleft > 2) && idx[0] == '\xa')
+                idx++;
+        } else if (bytesleft && idx[0] == '\xa') {
+            idx++;
         }
 
-        *stream = q2 - start;
+        /* Pass back start of the stream data. */
+        *stream = idx;
 
-        bytesleft2 -= q2 - start;
-        if (bytesleft2 <= 0)
-            return 0;
+        bytesleft = size - (idx - start);
+        if (bytesleft <= 0)
+            goto done;
 
-        /* Now find the "endstream" string that suffixes stream data */
-        q = q2;
-        q2 = cli_memstr(q, bytesleft2, "endstream", 9);
-        if (!q2) {
+        /* Now find the "endstream" string that suffixes stream data. */
+        endstream_begin = cli_memstr(idx, bytesleft, "endstream", strlen("endstream"));
+        if (!endstream_begin) {
             /* Couldn't find "endstream", but that's ok --
-             * -- we'll just count the data we have until EOF. */
-            q2 = q + bytesleft2-9; /* till EOF */
+             * -- we'll just count the rest of the provided buffer. */
+            cli_dbgmsg("find_stream_bounds: Truncated stream found!\n");
+            endstream_begin = start + size;
+            status = CL_EFORMAT;
         }
 
-        *endstream = q2 - start;
+        /* Pass back end of the stream data, as offset from start. */
+        *stream_size = endstream_begin - *stream;
 
-        /* Double-check that endstream >= stream */
-        if (*endstream < *stream)
-            *endstream = *stream;
-
-        return 1;
+        if (CL_EFORMAT != status)
+            status = CL_SUCCESS;
     }
 
-    return 0;
+done:
+
+    return status;
 }
 
 /**
- * @brief Find the next *indirect* object in an object stream, adds it to our list of 
+ * @brief Find the next *indirect* object in an object stream, adds it to our list of
  *        objects, and increments nobj.
- * 
+ *
  * Indirect objects in a stream DON'T begin with "obj" and end with "endobj".
  * Instead, they have an obj ID and an offset from the first object to point you
  * right at them.
- * 
+ *
  * If found, objstm->current will be updated to the next obj id.
- * 
- * All objects in an object stream are indirect and thus do not begin or start 
- * with "obj" or "endobj".  Instead, the object stream takes the following 
+ *
+ * All objects in an object stream are indirect and thus do not begin or start
+ * with "obj" or "endobj".  Instead, the object stream takes the following
  * format.
- * 
+ *
  *      <dictionary describing stream> objstm content endobjstm
- * 
+ *
  * where content looks something like the following:
- * 
+ *
  *      15 0 16 3 17 46 (ab)<</IDS 8 0 R/JavaScript 27 0 R/URLS 9 0 R>><</Names[(Test)28 0 R]>>
- * 
- * In the above example, the literal string (ab) is indirect object # 15, and 
- * begins at offset 0 of the set of objects.  The next object, # 16 begis at 
- * offset 3 is a dictionary.  The final object is also a dictionary, beginning 
+ *
+ * In the above example, the literal string (ab) is indirect object # 15, and
+ * begins at offset 0 of the set of objects.  The next object, # 16 begis at
+ * offset 3 is a dictionary.  The final object is also a dictionary, beginning
  * at offset 46.
- * 
- * @param pdf   Pdf struct that keeps track of all information found in the PDF. 
+ *
+ * @param pdf   Pdf struct that keeps track of all information found in the PDF.
  * @param objstm
- * 
+ *
  * @return CL_SUCCESS  if success
  * @return CL_EPARSE   if parsing error
  * @return CL_EMEM     if error allocating memory
@@ -299,7 +314,8 @@
 {
     cl_error_t status = CL_EPARSE;
     struct pdf_obj *obj = NULL;
-    unsigned long objid = 0, objsize = 0, objoff = 0;
+    unsigned long objid = 0, objoff = 0;
+    long temp_long         = 0;
     const char *index = NULL;
     size_t bytes_remaining = 0;
 
@@ -324,12 +340,17 @@
     obj->objstm = objstm;
 
     /* objstm->current_pair points directly to the obj id */
-    if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &objid)) {
+    if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
         /* Failed to find objid */
         cli_dbgmsg("pdf_findobj_in_objstm: Failed to find objid for obj in object stream\n");
         status = CL_EPARSE;
         goto done;
+    } else if (temp_long < 0) {
+        cli_dbgmsg("pdf_findobj_in_objstm: Encountered invalid negative objid (%ld).\n", temp_long);
+        status = CL_EPARSE;
+        goto done;
     }
+    objid = (unsigned long)temp_long;
 
     /* Find the obj offset that appears just after the obj id*/
     while ((index < objstm->streambuf + objstm->streambuf_len) && isdigit(*index)) {
@@ -339,11 +360,23 @@
     index = findNextNonWS(index, objstm->streambuf + objstm->first);
     bytes_remaining = objstm->streambuf + objstm->streambuf_len - index;
 
-    if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &objoff)) {
+    if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
         /* Failed to find obj offset */
         cli_dbgmsg("pdf_findobj_in_objstm: Failed to find obj offset for obj in object stream\n");
         status = CL_EPARSE;
         goto done;
+    } else if (temp_long < 0) {
+        cli_dbgmsg("pdf_findobj_in_objstm: Encountered invalid negative obj offset (%ld).\n", temp_long);
+        status = CL_EPARSE;
+        goto done;
+    }
+    objoff = (unsigned long)temp_long;
+
+    if ((size_t)objstm->first + (size_t)objoff > objstm->streambuf_len) {
+        /* Alleged obj location is further than the length of the stream */
+        cli_dbgmsg("pdf_findobj_in_objstm: obj offset found is greater than the length of the stream.\n");
+        status = CL_EPARSE;
+        goto done;
     }
 
     objstm->current = objstm->first + objoff;
@@ -366,22 +399,27 @@
     {
         unsigned long next_objid = 0, next_objoff = 0;
 
-        /* 
-         * While we're at it, 
+        /*
+         * While we're at it,
          *   lets record the size as running up to the next object offset.
-         * 
+         *
          * To do so, we will need to parse the next obj pair.
          */
         /* objstm->current_pair points directly to the obj id */
         index = objstm->streambuf + objstm->current_pair;
         bytes_remaining = objstm->streambuf + objstm->streambuf_len - index;
 
-        if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &next_objid)) {
+        if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
             /* Failed to find objid for next obj */
             cli_dbgmsg("pdf_findobj_in_objstm: Failed to find next objid for obj in object stream though there should be {%u} more.\n", objstm->n - objstm->nobjs_found);
             status = CL_EPARSE;
             goto done;
+        } else if (temp_long < 0) {
+            cli_dbgmsg("pdf_findobj_in_objstm: Encountered invalid negative objid (%ld).\n", temp_long);
+            status = CL_EPARSE;
+            goto done;
         }
+        next_objid = (unsigned long)temp_long;
 
         /* Find the obj offset that appears just after the obj id*/
         while ((index < objstm->streambuf + objstm->streambuf_len) && isdigit(*index)) {
@@ -391,13 +429,19 @@
         index = findNextNonWS(index, objstm->streambuf + objstm->first);
         bytes_remaining = objstm->streambuf + objstm->streambuf_len - index;
 
-        if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &next_objoff)) {
+        if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
             /* Failed to find obj offset for next obj */
             cli_dbgmsg("pdf_findobj_in_objstm: Failed to find next obj offset for obj in object stream though there should be {%u} more.\n", objstm->n - objstm->nobjs_found);
             status = CL_EPARSE;
             goto done;
+        } else if (temp_long < 0) {
+            cli_dbgmsg("pdf_findobj_in_objstm: Encountered invalid negative obj offset (%ld).\n", temp_long);
+            status = CL_EPARSE;
+            goto done;
         }
-        else if (next_objoff <= objoff) {
+        next_objoff = (unsigned long)temp_long;
+
+        if (next_objoff <= objoff) {
             /* Failed to find obj offset for next obj */
             cli_dbgmsg("pdf_findobj_in_objstm: Found next obj offset for obj in object stream but it's less than or equal to the current one!\n");
             status = CL_EPARSE;
@@ -411,14 +455,14 @@
         }
 
         obj->size = next_objoff - objoff;
-    } 
-    else 
+    }
+    else
     {
         /*
          * Should be no more objects. We should verify.
-         * 
+         *
          * Either way...
-         *   obj->size should be the rest of the buffer. 
+         *   obj->size should be the rest of the buffer.
          */
         if (objstm->nobjs_found < objstm->n) {
             cli_warnmsg("pdf_findobj_in_objstm: Fewer objects found in object stream than expected!\n");
@@ -471,10 +523,15 @@
 cl_error_t pdf_findobj(struct pdf_struct *pdf)
 {
     cl_error_t status = CL_EPARSE;
-    const char *start, *q, *q2, *q3, *eof;
+    const char *start, *idx, *genid_search_index, *objid_search_index;
+
+    const char *obj_begin = NULL, *obj_end = NULL;
+    const char *endobj_begin = NULL, *endobj_end = NULL;
+
     struct pdf_obj *obj = NULL;
-    off_t bytesleft;
+    size_t bytesleft;
     unsigned long genid, objid;
+    long temp_long;
 
     pdf->nobjs++;
     pdf->objs = cli_realloc2(pdf->objs, sizeof(struct pdf_obj*) * pdf->nobjs);
@@ -495,169 +552,166 @@
     start = pdf->map + pdf->offset;
     bytesleft = pdf->size - pdf->offset;
 
-    /* Indirect objects located outside of an object stream are prefaced with "obj"
-     * and suffixed with "endobj".  Find the "obj" preface. */
-    while (bytesleft > 0)
-    {
-        q2 = cli_memstr(start, bytesleft, "obj", 3);
-        if (!q2) {
-            status = CL_BREAK; /* no more objs */
-            goto done;
-        }
-
-        /* verify that "obj" has a whitespace before it, and is not the end of 
-         * a previous string like... "globj" */
-        q2--;
-        bytesleft -= q2 - start;
+    /*
+     * Start by searching for "obj"
+     */
+    idx = start + 1;
+    while (bytesleft > 1 + strlen("obj")) {
+        /* `- 1` accounts for size of white space before obj */
+        idx = cli_memstr(idx, bytesleft - 1, "obj", strlen("obj"));
+        if (NULL == idx) {
+            status = CL_BREAK;
+            goto done; /* No more objs. */
+        }
+
+        /* verify that the word has a whitespace before it, and is not the end of
+         * a previous word */
+        idx--;
+        bytesleft = (pdf->size - pdf->offset) - (size_t)(idx - start);
 
-        if (*q2 != 0 && *q2 != 9 && *q2 != 0xa && *q2 != 0xc && *q2 != 0xd && *q2 != 0x20) {
-            /* This instance of the "obj" string appears to be part of another string.
+        if (*idx != 0 && *idx != 9 && *idx != 0xa && *idx != 0xc && *idx != 0xd && *idx != 0x20) {
+            /* This instance of "obj" appears to be part of a longer string.
              * Skip it, and keep searching for an object. */
-            start = q2+4;
-            bytesleft -= 4;
+            idx += 1 + strlen("obj");
+            bytesleft -= 1 + strlen("obj");
             continue;
         }
 
-        break; /* Found it. q2 should point to the whitespace before the "obj" string */
-    }
+        /* Found the beginning of the word */
+        obj_begin = idx;
+        obj_end = idx + 1 + strlen("obj");
 
-    if (bytesleft <= 0) {
-        status = CL_BREAK; /* No "obj" found. */
-        goto done;
+        break;
     }
 
-    /* "obj" found! */
+    if ((NULL == obj_begin) || (NULL == obj_end)) {
+        status = CL_BREAK;
+        goto done; /* No more objs. */
+    }
 
     /* Find the generation id (genid) that appears before the "obj" */
-    q = findNextNonWSBack(q2-1, start);
-    while (q > start && isdigit(*q))
-        q--;
+    genid_search_index = findNextNonWSBack(obj_begin - 1, start);
+    while (genid_search_index > start && isdigit(*genid_search_index))
+        genid_search_index--;
 
-    if (CL_SUCCESS != cli_strntoul_wrap(q, (size_t)(bytesleft + (q2-q)), 0, 10, &genid)) {
+    if (CL_SUCCESS != cli_strntol_wrap(genid_search_index, (size_t)((obj_begin) - genid_search_index), 0, 10, &temp_long)) {
         cli_dbgmsg("pdf_findobj: Failed to parse object genid (# objects found: %u)\n", pdf->nobjs);
         /* Failed to parse, probably not a real object.  Skip past the "obj" thing, and continue. */
-        pdf->offset = q2 + 4 - pdf->map;
+        pdf->offset = obj_end - pdf->map;
         status = CL_EPARSE;
         goto done;
+    } else if (temp_long < 0) {
+        cli_dbgmsg("pdf_findobj: Encountered invalid negative obj genid (%ld).\n", temp_long);
+        pdf->offset = obj_end - pdf->map;
+        status      = CL_EPARSE;
+        goto done;
     }
+    genid = (unsigned long)temp_long;
 
-    /* Find the object id (objid) that appers before the genid */
-    q = findNextNonWSBack(q-1,start);
-    while (q > start && isdigit(*q))
-        q--;
+    /* Find the object id (objid) that appears before the genid */
+    objid_search_index = findNextNonWSBack(genid_search_index - 1, start);
+    while (objid_search_index > start && isdigit(*objid_search_index))
+        objid_search_index--;
 
-    if (CL_SUCCESS != cli_strntoul_wrap(q, (size_t)(bytesleft + (q2-q)), 0, 10, &objid)) {
+    if (CL_SUCCESS != cli_strntol_wrap(objid_search_index, (size_t)((genid_search_index) - objid_search_index), 0, 10, &temp_long)) {
         /*
-         * PDFs with multiple revisions will have %%EOF before the end of the file, 
-         * followed by the next revision of the PDF.  If this is the case, we can 
-         * detect it and continue parsing after the %%EOF.
+         * Edge case:
+         *
+         * PDFs with multiple revisions will have %%EOF before the end of the file,
+         * followed by the next revision of the PDF, which will probably be an immediate objid.
+         *
+         * Example:
+         *   %%EOF1 1 obj <blah> endobj
+         *
+         * If this is the case, we can detect it and continue parsing after the %%EOF.
          */
-        if (q - 4 > start) {
-            const char* lastfile = q - 4;
+        if (objid_search_index - strlen("\%\%EO") > start) {
+            const char* lastfile = objid_search_index - strlen("\%\%EO");
             if (0 != strncmp(lastfile, "\%\%EOF", 5)) {
                 /* Nope, wasn't %%EOF */
                 cli_dbgmsg("pdf_findobj: Failed to parse object objid (# objects found: %u)\n", pdf->nobjs);
                 /* Skip past the "obj" thing, and continue. */
-                pdf->offset = q2 + 4 - pdf->map;
-                status = CL_EPARSE;
+                pdf->offset = obj_end - pdf->map;
+                status      = CL_EPARSE;
                 goto done;
             }
-            /* Yup, Looks, like the file continues after %%EOF.  
+            /* Yup, Looks, like the file continues after %%EOF.
              * Probably another revision.  Keep parsing... */
-            q++;
-            cli_dbgmsg("pdf_findobj: \%\%EOF detected before end of file, at %zu\n", (size_t)q);
+            objid_search_index++;
+            cli_dbgmsg("pdf_findobj: \%\%EOF detected before end of file, at offset: %zu\n", (size_t)(objid_search_index - pdf->map));
         } else {
             /* Failed parsing at the very beginning */
             cli_dbgmsg("pdf_findobj: Failed to parse object objid (# objects found: %u)\n", pdf->nobjs);
             /* Probably not a real object.  Skip past the "obj" thing, and continue. */
-            pdf->offset = q2 + 4 - pdf->map;
-            status = CL_EPARSE;
+            pdf->offset = obj_end - pdf->map;
+            status      = CL_EPARSE;
             goto done;
         }
         /* Try again, with offset slightly adjusted */
-        if (CL_SUCCESS != cli_strntoul_wrap(q, (size_t)(bytesleft + (q2-q)), 0, 10, &objid)) {
+        if (CL_SUCCESS != cli_strntol_wrap(objid_search_index, (size_t)((genid_search_index - 1) - objid_search_index), 0, 10, &temp_long)) {
             cli_dbgmsg("pdf_findobj: Failed to parse object objid (# objects found: %u)\n", pdf->nobjs);
             /* Still failed... Probably not a real object.  Skip past the "obj" thing, and continue. */
-            pdf->offset = q2 + 4 - pdf->map;
-            status = CL_EPARSE;
+            pdf->offset = obj_end - pdf->map;
+            status      = CL_EPARSE;
+            goto done;
+        } else if (temp_long < 0) {
+            cli_dbgmsg("pdf_findobj: Encountered invalid negative objid (%ld).\n", temp_long);
+            pdf->offset = obj_end - pdf->map;
+            status      = CL_EPARSE;
             goto done;
         }
+
         cli_dbgmsg("pdf_findobj: There appears to be an additional revision. Continuing to parse...\n");
+    } else if (temp_long < 0) {
+        cli_dbgmsg("pdf_findobj: Encountered invalid negative objid (%ld).\n", temp_long);
+        pdf->offset = obj_end - pdf->map;
+        status      = CL_EPARSE;
+        goto done;
     }
+    objid = (unsigned long)temp_long;
 
-    /*
-     * Ok so we have the objid, genid, and "obj" string.
-     *   Time to store that information and then ...
-     *     ... investigate what kind of object this is.
-     */
     obj->id = (objid << 8) | (genid & 0xff);
-    obj->start = q2+4 - pdf->map; /* obj start begins just after the "obj" string */
+    obj->start = obj_end - pdf->map; /* obj start begins just after the "obj" string */
     obj->flags = 0;
 
-    bytesleft -= 4;
-    eof = pdf->map + pdf->size;
-    q = pdf->map + obj->start;
-
-    while (q < eof && bytesleft > 0)
-    {
-        off_t p_stream, p_endstream;
-        q2 = pdf_nextobject(q, bytesleft);
-        if (!q2)
-            q2 = pdf->map + pdf->size; /* No interesting objects found, fast-forward to eof */
-
-        bytesleft -= q2 - q;
-        if (find_stream_bounds(q-1, q2-q, bytesleft + (q2-q), &p_stream, &p_endstream, 1)) {
-            /*
-             * Found obj that contains a stream.
-             */
-            obj->flags |= 1 << OBJ_STREAM;
-            q2 = q-1 + p_endstream + 9;
-            bytesleft -= q2 - q + 1;
-
-            if (bytesleft < 0) {
-                /* ... and the stream is truncated.  Hmm... */
-                obj->flags |= 1 << OBJ_TRUNCATED;
-                pdf->offset = pdf->size;
-
-                status = CL_SUCCESS;
-                goto done; /* Truncated file, no end to obj/stream. 
-                            * The next call to pdf_findobj() will return no more objects. */
-            }
-        } else if ((q3 = cli_memstr(q-1, q2-q+1, "endobj", 6))) {
-            /*
-             * obj found and offset positioned. ideal return case
-             */
-            q2 = q3 + 6;
-            pdf->offset = q2 - pdf->map; /* update the offset to just after the endobj */
-
-            status = CL_SUCCESS;
-            goto done; 
-        } else {
-            q2++;
-            bytesleft--;
-        }
+    /*
+     * We now have the objid, genid, and object start.
+     * Find the object end ("endobj").
+     */
+    /* `- 1` accounts for size of white space before obj */
+    endobj_begin = cli_memstr(obj_end, pdf->map + pdf->size - obj_end, "endobj", strlen("endobj"));
+    if (NULL == endobj_begin) {
+        /* No end to object.
+         * PDF appears to be malformed or truncated.
+         * Will record the object size as going ot the end of the file.
+         * Will record that the object is truncated.
+         * Will position the pdf offset to the end of the PDF.
+         * The next iteration of this function will find no more objects. */
+        obj->flags |= 1 << OBJ_TRUNCATED;
+        obj->size   = (pdf->map + pdf->size) - obj_end;
+        pdf->offset = pdf->size;
 
-        q = q2;
+        /* Truncated "object" found! */
+        status = CL_SUCCESS;
+        goto done;
     }
+    endobj_end = endobj_begin + strlen("endobj");
 
-    obj->flags |= 1 << OBJ_TRUNCATED;
-    pdf->offset = pdf->size;
+    /* Size of the object goes from "obj" <-> "endobject". */
+    obj->size = endobj_begin - obj_end;
+    pdf->offset = endobj_end - pdf->map;
 
+    /*
+     * Object found!
+     */
     status = CL_SUCCESS; /* truncated file, no end to obj. */
 
 done:
     if (status == CL_SUCCESS) {
-        cli_dbgmsg("pdf_findobj: found %d %d obj @%lld\n", obj->id >> 8, obj->id&0xff, (long long)(obj->start + pdf->startoff));
+        cli_dbgmsg("pdf_findobj: found %d %d obj @%lld, size: %zu bytes.\n", obj->id >> 8, obj->id&0xff, (long long)(obj->start + pdf->startoff), obj->size);
     }
     else
     {
-        if(status == CL_BREAK) {
-            cli_dbgmsg("pdf_findobj: No more objects (# objects found: %u)\n", pdf->nobjs);
-        } else if(status == CL_EMEM) {
-            cli_warnmsg("pdf_findobj: Error allocating memory (# objects found: %u)\n", pdf->nobjs);
-        } else {
-            cli_dbgmsg("pdf_findobj: Unexpected status code %d.\n", status);
-        }
         /* Remove the unused obj reference from our list of objects found */
         /* No need to realloc pdf->objs back down.  It won't leak. */
         pdf->objs[pdf->nobjs-1] = NULL;
@@ -666,9 +720,17 @@
         /* Free up the obj struct. */
         if (NULL != obj)
             free(obj);
+
+        if(status == CL_BREAK) {
+            cli_dbgmsg("pdf_findobj: No more objects (# objects found: %u)\n", pdf->nobjs);
+        } else if(status == CL_EMEM) {
+            cli_warnmsg("pdf_findobj: Error allocating memory (# objects found: %u)\n", pdf->nobjs);
+        } else {
+            cli_dbgmsg("pdf_findobj: Unexpected status code %d.\n", status);
+        }
     }
 
-    return status; 
+    return status;
 }
 
 static size_t filter_writen(struct pdf_struct *pdf, struct pdf_obj *obj, int fout, const char *buf, size_t len, size_t *sum)
@@ -789,14 +851,14 @@
 
 /**
  * @brief   Find and interpret the "/Length" dictionary key value.
- * 
+ *
  * The value may be:
- *  - a direct object (i.e. just a number) 
+ *  - a direct object (i.e. just a number)
  *  - an indirect object, where the value is somewhere else in the document and we have to look it up.
  *    indirect objects are referenced using an object id (objid), generation id (genid) genid, and the letter 'R'.
- * 
+ *
  * Example dictionary with a single key "/Length" that relies direct object for the value.
- * 
+ *
  *      1 0 obj
  *          << /Length 534
  *              /Filter [ /ASCII85Decode /LZWDecode ]
@@ -810,9 +872,9 @@
  *              JD?M$0QP)lKn06l1apKDC@\qJ4B!!(5m+j.7F790m(Vj88l8Q:_CZ(Gm1%X\N1&u!FKHMB~>
  *          endstream
  *      endobj
- * 
+ *
  * Example dictionary with a single key "/Length" that relies on an indirect object for the value.
- * 
+ *
  *      7 0 obj
  *          << /Length 8 0 R >> % An indirect reference to object 8, with generation id 0.
  *          stream
@@ -823,11 +885,11 @@
  *              ET
  *          endstream
  *      endobj
- * 
+ *
  *      8 0 obj
  *          77 % The length of the preceding stream
  *      endobj
- * 
+ *
  * @param pdf       Pdf context structure.
  * @param obj       Pdf object context structure.
  * @param start     Pointer start of the dictionary string.
@@ -839,7 +901,7 @@
     size_t length = 0;
     const char *obj_start = dict_start;
     size_t bytes_remaining = dict_len;
-    unsigned long length_ul = 0;
+    long temp_long         = 0;
     const char *index;
 
     if (bytes_remaining < 8) {
@@ -867,24 +929,27 @@
     if (!obj_start)
         return 0;
 
-    if (bytes_remaining < obj_start - index) {
+    if (bytes_remaining < (size_t)(obj_start - index)) {
         return 0;
     }
     bytes_remaining -= obj_start - index;
     index = obj_start;
-    
+
     /* Read the value.  This could either be the direct length value,
        or the object id of the indirect object that has the length */
-    if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &length_ul)) {
-        cli_dbgmsg("find_length: failed to parse object length\n");
+    if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
+        cli_dbgmsg("find_length: failed to parse object length or objid\n");
+        return 0;
+    } else if (temp_long < 0) {
+        cli_dbgmsg("find_length: Encountered invalid negative object length or objid (%ld).\n", temp_long);
         return 0;
     }
-    length = length_ul; /* length or maybe object id */
+    length = (size_t)temp_long; /* length or maybe object id */
 
-    /* 
-     * Keep parsing, skipping past the first integer that might have been what we wanted. 
-     * If it's an indirect object, we'll find a Generation ID followed by the letter 'R' 
-     * I.e. something like " 0 R" 
+    /*
+     * Keep parsing, skipping past the first integer that might have been what we wanted.
+     * If it's an indirect object, we'll find a Generation ID followed by the letter 'R'
+     * I.e. something like " 0 R"
      */
     while ((bytes_remaining > 0) && isdigit(*index)) {
         index++;
@@ -897,10 +962,14 @@
         index++;
         bytes_remaining--;
 
-        if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &genid)) {
+        if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
             cli_dbgmsg("find_length: failed to parse object genid\n");
             return 0;
+        } else if (temp_long < 0) {
+            cli_dbgmsg("find_length: Encountered invalid negative object genid (%ld).\n", temp_long);
+            return 0;
         }
+        genid = (unsigned long)temp_long;
 
         while((bytes_remaining > 0) && isdigit(*index)) {
             index++;
@@ -912,14 +981,14 @@
         }
 
         if (index[0] == ' ' && index[1] == 'R') {
-            /* 
-             * Ok so we found a genid and that 'R'.  Which means that first value 
+            /*
+             * Ok so we found a genid and that 'R'.  Which means that first value
              * was actually the objid.
              * We can look up the indirect object using this information.
              */
             unsigned long objid = length;
             const char* indirect_obj_start = NULL;
-            
+
             cli_dbgmsg("find_length: length is in indirect object %lu %lu\n", objid, genid);
 
             obj = find_obj(pdf, obj, (length << 8) | (genid&0xff));
@@ -930,29 +999,33 @@
 
             indirect_obj_start = pdf->map + obj->start;
             bytes_remaining = pdf->size - obj->start;
-            
+
             /* Ok so we found the indirect object, lets read the value. */
             index = pdf_nextobject(indirect_obj_start, bytes_remaining);
             if (!index) {
                 cli_dbgmsg("find_length: next object not found\n");
                 return 0;
             }
-            
-            if (bytes_remaining < index - indirect_obj_start) {
+
+            if (bytes_remaining < (size_t)(index - indirect_obj_start)) {
                 return 0;
             }
             bytes_remaining -= index - indirect_obj_start;
 
-            /* Found the value, so lets parse it as an unsigned long */
-            if (CL_SUCCESS != cli_strntoul_wrap(index, bytes_remaining, 0, 10, &length)) {
+            /* Found the value, so lets parse it as a long, but prohibit negative lengths. */
+            if (CL_SUCCESS != cli_strntol_wrap(index, bytes_remaining, 0, 10, &temp_long)) {
                 cli_dbgmsg("find_length: failed to parse object length from indirect object\n");
                 return 0;
+            } else if (temp_long < 0) {
+                cli_dbgmsg("find_length: Encountered invalid negative obj length (%ld).\n", temp_long);
+                return 0;
             }
+            length = (size_t)temp_long;
         }
     }
 
     /* limit length */
-    if (obj_start - pdf->map + length + 5 > pdf->size)
+    if ((size_t)(obj_start - pdf->map) + length + 5 > pdf->size)
         length = pdf->size - (obj_start - pdf->map) - 5;
 
     return length;
@@ -960,102 +1033,6 @@
 
 #define DUMP_MASK ((1 << OBJ_CONTENTS) | (1 << OBJ_FILTER_FLATE) | (1 << OBJ_FILTER_DCT) | (1 << OBJ_FILTER_AH) | (1 << OBJ_FILTER_A85) | (1 << OBJ_EMBEDDED_FILE) | (1 << OBJ_JAVASCRIPT) | (1 << OBJ_OPENACTION) | (1 << OBJ_LAUNCHACTION))
 
-static int obj_size(struct pdf_struct *pdf, struct pdf_obj *obj, int binary)
-{
-    if (0 == obj->size)
-    {
-        /*
-         * Programmatically determine size if not already known.
-         */
-        unsigned i = 0;
-
-        /* Find the index of the current object */
-        for (i = 0; i < pdf->nobjs; i++) {
-            if (pdf->objs[i] == obj)
-                break;
-        }
-
-        /* Find the next object that exists in the same buffer (pdf fmap, or object stream) */
-        if (i < pdf->nobjs) {
-            i++;
-        }
-
-        if (obj->objstm == NULL) {
-            /* Current object isn't in an object stream, we want to find
-             * the next object that also isn't in an object stream. */
-            for ( ; i < pdf->nobjs; i++) {
-                if (pdf->objs[i]->objstm == NULL)
-                    break;
-            }
-        } else {
-            /* Current object is in an object stream, we want to find
-             * the next object that is in the same object stream.
-             *
-             * This really shouldn't happen, so throw a warning and
-             * then see if we can solve it anyhow */
-            cli_warnmsg("obj_size: Encountered pdf object in an object stream that has an unknown size!!\n");
-
-            for ( ; i < pdf->nobjs; i++) {
-                if (pdf->objs[i]->objstm == obj->objstm)
-                    break;
-            }
-        }
-
-        /* Step backwards from the "next" object to find the end of the current object */
-        if (i < pdf->nobjs) {
-            int s = pdf->objs[i]->start - obj->start - 4;
-            if (s > 0) {
-                if (!binary) {
-                    const char *p = NULL;
-                    const char *q = NULL;
-
-                    if (obj->objstm == NULL) {
-                        p = pdf->map + obj->start;
-                    } else {
-                        p = obj->objstm->streambuf + obj->start;
-                    }
-                    q = p + s;
-
-                    while (q > p && (isspace(*q) || isdigit(*q)))
-                        q--;
-
-                    if (q > p+5 && !memcmp(q-5,"endobj",6))
-                        q -= 6;
-
-                    q = findNextNonWSBack(q, p);
-                    q++;
-
-                    obj->size = q - p;
-                    goto done;
-                }
-
-                obj->size = s;
-                goto done;
-            }
-        }
-
-        /* If we've gotten this far, we didn't find a "next" object... so our 
-         * current object must be at the end of the pdf fmap or the end of the 
-         * object stream. */
-        if (obj->objstm == NULL) {
-            /* Current object isn't in an object stream, so we can determine object 
-             * size based on the remaining size of the file (in theory). */
-            if (binary)
-                obj->size = pdf->size - obj->start;
-            else
-                obj->size = pdf->offset - obj->start - 6; /* This hack I think assumes that we reached the end of the file when finding objects. */
-        } else {
-            /* Current object is in an object stream, we want to find 
-             * the next object that is in the same object stream. */
-            obj->size = obj->objstm->streambuf_len - obj->start;
-        }
-    }
-
-done:
-
-    return obj->size;
-}
-
 static int run_pdf_hooks(struct pdf_struct *pdf, enum pdf_phase phase, int fd, int dumpid)
 {
     int ret;
@@ -1424,330 +1401,328 @@
     if (!(flags & PDF_EXTRACT_OBJ_SCAN))
         obj->path = strdup(fullname);
 
-    do {
-        if (obj->flags & (1 << OBJ_STREAM)) {
-            const char *start = pdf->map + obj->start;
-            off_t p_stream = 0, p_endstream = 0;
-            off_t length;
+    if ((NULL == obj->objstm) &&
+        (obj->flags & (1 << OBJ_STREAM))) {
+        /*
+         * Object contains a stream. Parse this now.
+         */
+        cli_dbgmsg("pdf_extract_obj: parsing a stream in obj %u %u\n", obj->id>>8, obj->id&0xff);
 
-            if (NULL != obj->objstm) {
-                cli_warnmsg("pdf_extract_obj: Object found in object stream claims to be an object stream! Skipping.\n");
-                break;
+        const char *start = pdf->map + obj->start;
+
+        size_t length;
+        size_t orig_length;
+        int dict_len = obj->stream - start; /* Dictionary should end where the stream begins */
+
+        const char *pstr;
+        struct pdf_dict *dparams = NULL;
+        struct objstm_struct *objstm = NULL;
+        int xref = 0;
+
+        /* Find and interpret the length dictionary value */
+        length = find_length(pdf, obj, start, dict_len);
+        if (length < 0)
+            length = 0;
+
+        orig_length = length;
+
+        if (length > obj->stream_size) {
+            cli_dbgmsg("cli_pdf: Stream length exceeds object length by %zu bytes. Length truncated to %zu bytes\n", length - obj->stream_size, obj->stream_size);
+            noisy_warnmsg("Stream length exceeds object length by %zu bytes. Length truncated to %zu bytes\n", length - obj->stream_size, obj->stream_size);
+
+            length = obj->stream_size;
+        }
+
+        if (!(obj->flags & (1 << OBJ_FILTER_FLATE)) && (length <= 0)) {
+            /*
+             * If the length is unknown and this doesn't contain a FLATE encoded filter...
+             * Calculate the length using the stream size, and trimming
+             * off any newline/carriage returns from the end of the stream.
+             */
+            const char *q = start + obj->stream_size;
+            length = obj->stream_size;
+            q--;
+
+            if (*q == '\n') {
+                q--;
+                length--;
+
+                if (*q == '\r')
+                    length--;
+            } else if (*q == '\r') {
+                length--;
             }
 
-            find_stream_bounds(start, pdf->size - obj->start,
-                       pdf->size - obj->start,
-                       &p_stream, &p_endstream,
-                       pdf->enc_method_stream <= ENC_IDENTITY &&
-                       pdf->enc_method_embeddedfile <= ENC_IDENTITY);
-
-            if (p_stream && p_endstream) {
-                size_t size = p_endstream - p_stream;
-                off_t orig_length;
-                int len = p_stream;
-                const char *pstr;
-                struct pdf_dict *dparams = NULL;
-                struct objstm_struct *objstm = NULL;
-                int xref = 0;
-
-                length = find_length(pdf, obj, start, p_stream);
-                if (length < 0)
-                    length = 0;
-
-                orig_length = length;
-                if (length > pdf->size || obj->start + p_stream + length > pdf->size) {
-                    cli_dbgmsg("cli_pdf: length out of file: %lld + %lld > %lld\n",
-                           (long long)p_stream, (long long)length, (long long)pdf->size);
-                    noisy_warnmsg("length out of file, truncated: %lld + %lld > %lld\n",
-                           (long long)p_stream, (long long)length, (long long)pdf->size);
-                    length = pdf->size - (obj->start + p_stream);
-                }
+            if (length < 0)
+                length = 0;
 
-                if (!(obj->flags & (1 << OBJ_FILTER_FLATE)) && length <= 0) {
-                    const char *q = start + p_endstream;
-                    length = size;
-                    q--;
+            cli_dbgmsg("pdf_extract_obj: calculated length %lld\n", (long long)length);
+        } else {
+            if (obj->stream_size > (size_t)length + 2) {
+                cli_dbgmsg("cli_pdf: calculated length %zu < %zu\n",
+                            (size_t)length, obj->stream_size);
+                length = obj->stream_size;
+            }
+        }
 
-                    if (*q == '\n') {
-                        q--;
-                        length--;
+        if ((0 != orig_length) && (obj->stream_size > (size_t)orig_length + 20)) {
+            cli_dbgmsg("pdf_extract_obj: orig length: %lld, length: %lld, size: %zu\n",
+                        (long long)orig_length, (long long)length, obj->stream_size);
+            pdfobj_flag(pdf, obj, BAD_STREAMLEN);
+        }
 
-                        if (*q == '\r')
-                            length--;
-                    } else if (*q == '\r') {
-                        length--;
-                    }
+        if (0 == length) {
+            length = obj->stream_size;
+            if (0 == length) {
+                cli_dbgmsg("pdf_extract_obj: Alleged or calculated stream length and stream buffer size both 0\n");
+                goto done; /* Empty stream, nothing to scan */
+            }
+        }
 
-                    if (length < 0)
-                        length = 0;
+        /* Check if XRef is enabled */
+        if (cli_memstr(start, dict_len, "/XRef", strlen("/XRef"))) {
+            xref = 1;
+        }
 
-                    cli_dbgmsg("pdf_extract_obj: calculated length %lld\n", (long long)length);
-                } else {
-                    if (size > (size_t)length+2) {
-                        cli_dbgmsg("cli_pdf: calculated length %zu < %zu\n",
-                                   (size_t)length, size);
-                        length = size;
-                    }
-                }
+        cli_dbgmsg("-------------EXPERIMENTAL-------------\n");
 
-                if (orig_length && size > (size_t)orig_length + 20) {
-                    cli_dbgmsg("pdf_extract_obj: orig length: %lld, length: %lld, size: %zu\n",
-                               (long long)orig_length, (long long)length, size);
-                    pdfobj_flag(pdf, obj, BAD_STREAMLEN);
-                }
+        /*
+         * Identify the DecodeParms, if available.
+         */
+        if (NULL != (pstr = pdf_getdict(start, &dict_len, "/DecodeParms")))
+        {
+            cli_dbgmsg("pdf_extract_obj: Found /DecodeParms\n");
+        }
+        else if (NULL != (pstr = pdf_getdict(start, &dict_len, "/DP")))
+        {
+            cli_dbgmsg("pdf_extract_obj: Found /DP\n");
+        }
 
-                if (!length) {
-                    length = size;
-                    if (!length) {
-                        cli_dbgmsg("pdf_extract_obj: length and size both 0\n");
-                        break; /* Empty stream, nothing to scan */
-                    }
-                }
+        if (pstr) {
+            /* shift pstr left to "<<" for pdf_parse_dict */
+            while ((*pstr == '<') && (pstr > start)) {
+                pstr--;
+                dict_len++;
+            }
 
-                if (cli_memstr(start, p_stream, "/XRef", 5))
-                    xref = 1;
+            /* shift pstr right to "<<" for pdf_parse_dict */
+            while ((*pstr != '<') && (dict_len > 0)) {
+                pstr++;
+                dict_len--;
+            }
 
-                cli_dbgmsg("-------------EXPERIMENTAL-------------\n");
+            if (dict_len > 4)
+                dparams = pdf_parse_dict(pdf, obj, obj->size, (char *)pstr, NULL);
+            else
+                cli_dbgmsg("pdf_extract_obj: failed to locate DecodeParms dictionary start\n");
+        }
 
-                /*
-                 * Identify the DecodeParms, if available.
-                 */
-                if (NULL != (pstr = pdf_getdict(start, &len, "/DecodeParms")))
-                {
-                    cli_dbgmsg("pdf_extract_obj: Found /DecodeParms\n");
+        /*
+         * Go back to the start of the dictionary and check to see if the stream
+         * is an object stream. If so, collect the relevant info.
+         */
+        dict_len = obj->stream - start;
+        if (NULL != (pstr = pdf_getdict(start, &dict_len, "/Type/ObjStm")))
+        {
+            int32_t objstm_first = -1;
+            int32_t objstm_length = -1;
+            int32_t objstm_n = -1;
+
+            cli_dbgmsg("pdf_extract_obj: Found /Type/ObjStm\n");
+
+            dict_len = obj->stream - start;
+            if ((-1 == (objstm_first = pdf_readint(start, dict_len, "/First"))))
+            {
+                cli_warnmsg("pdf_extract_obj: Failed to find offset of first object in object stream\n");
+            }
+            else if ((-1 == (objstm_length = pdf_readint(start, dict_len, "/Length"))))
+            {
+                cli_warnmsg("pdf_extract_obj: Failed to find length of object stream\n");
+            }
+            else if ((-1 == (objstm_n = pdf_readint(start, dict_len, "/N"))))
+            {
+                cli_warnmsg("pdf_extract_obj: Failed to find num objects in object stream\n");
+            }
+            else
+            {
+                /* Add objstm to pdf struct, so it can be freed eventually */
+                pdf->nobjstms++;
+                pdf->objstms = cli_realloc2(pdf->objstms, sizeof(struct objstm_struct*) * pdf->nobjstms);
+                if (!pdf->objstms) {
+                    cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms);
+                    pdf_free_dict(dparams);
+                    return CL_EMEM;
                 }
-                else if (NULL != (pstr = pdf_getdict(start, &len, "/DP")))
-                {
-                    cli_dbgmsg("pdf_extract_obj: Found /DP\n");
+
+                objstm = malloc(sizeof(struct objstm_struct));
+                if (!objstm) {
+                    cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms);
+                    pdf_free_dict(dparams);
+                    return CL_EMEM;
                 }
+                pdf->objstms[pdf->nobjstms-1] = objstm;
 
-                if (pstr) {
-                    unsigned int objsize = obj_size(pdf, obj, 1);
+                memset(objstm, 0, sizeof(*objstm));
 
-                    /* shift pstr left to "<<" for pdf_parse_dict */
-                    while ((*pstr == '<') && (pstr > start)) {
-                        pstr--;
-                        len++;
-                    }
+                objstm->first =         (uint32_t)objstm_first;
+                objstm->current =       (uint32_t)objstm_first;
+                objstm->current_pair =  0;
+                objstm->length =        (uint32_t)objstm_length;
+                objstm->n =             (uint32_t)objstm_n;
 
-                    /* shift pstr right to "<<" for pdf_parse_dict */
-                    while ((*pstr != '<') && (len > 0)) {
-                        pstr++;
-                        len--;
-                    }
+                cli_dbgmsg("pdf_extract_obj: ObjStm first obj at offset %d\n", objstm->first);
+                cli_dbgmsg("pdf_extract_obj: ObjStm length is %d bytes\n", objstm->length);
+                cli_dbgmsg("pdf_extract_obj: ObjStm should contain %d objects\n", objstm->n);
+            }
+        }
 
-                    if (len > 4)
-                        dparams = pdf_parse_dict(pdf, obj, objsize, (char *)pstr, NULL);
-                    else
-                        cli_dbgmsg("pdf_extract_obj: failed to locate DecodeParms dictionary start\n");
-                }
+        sum = pdf_decodestream(pdf, obj, dparams, obj->stream, (uint32_t)length, xref, fout, &rc, objstm);
+        if ((CL_SUCCESS != rc) && (CL_VIRUS != rc)) {
+            cli_dbgmsg("Error decoding stream! Error code: %d\n", rc);
+
+            /* It's ok if we couldn't decode the stream,
+             *   make a best effort to keep parsing. */
+            if (CL_EPARSE == rc)
+                rc = CL_SUCCESS;
 
+            if (NULL != objstm) {
                 /*
-                 * Identify if the stream is an object stream. If so, collect the relevant info. 
+                 * If we were expecting an objstm and there was a failure...
+                 *   discard the memory for last object stream.
                  */
-                len = p_stream;
-                if (NULL != (pstr = pdf_getdict(start, &len, "/Type/ObjStm")))
-                {
-                    int32_t objstm_first = -1;
-                    int32_t objstm_length = -1;
-                    int32_t objstm_n = -1;
-
-                    cli_dbgmsg("pdf_extract_obj: Found /Type/ObjStm\n");
-
-                    len = p_stream;
-                    if ((-1 == (objstm_first = pdf_readint(start, len, "/First"))))
-                    {
-                        cli_warnmsg("pdf_extract_obj: Failed to find offset of first object in object stream\n");
-                    }
-                    else if ((-1 == (objstm_length = pdf_readint(start, len, "/Length"))))
-                    {
-                        cli_warnmsg("pdf_extract_obj: Failed to find length of object stream\n");
-                    }
-                    else if ((-1 == (objstm_n = pdf_readint(start, len, "/N"))))
-                    {
-                        cli_warnmsg("pdf_extract_obj: Failed to find num objects in object stream\n");
-                    }
-                    else
-                    {
-                        /* Add objstm to pdf struct, so it can be freed eventually */
-                        pdf->nobjstms++;
-                        pdf->objstms = cli_realloc2(pdf->objstms, sizeof(struct objstm_struct*) * pdf->nobjstms);
-                        if (!pdf->objstms) {
-                            cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms);
-                            pdf_free_dict(dparams);
-                            return CL_EMEM;
+                if (NULL != pdf->objstms) {
+                    if (NULL != pdf->objstms[pdf->nobjstms - 1]) {
+                        if (NULL != pdf->objstms[pdf->nobjstms - 1]->streambuf) {
+                            free(pdf->objstms[pdf->nobjstms - 1]->streambuf);
+                            pdf->objstms[pdf->nobjstms - 1]->streambuf = NULL;
                         }
-
-                        objstm = malloc(sizeof(struct objstm_struct));
-                        if (!objstm) {
-                            cli_warnmsg("pdf_extract_obj: out of memory parsing object stream (%u)\n", pdf->nobjstms);
-                            pdf_free_dict(dparams);
-                            return CL_EMEM;
-                        }
-                        pdf->objstms[pdf->nobjstms-1] = objstm;
-
-                        memset(objstm, 0, sizeof(*objstm));
-
-                        objstm->first =         (uint32_t)objstm_first;
-                        objstm->current =       (uint32_t)objstm_first;
-                        objstm->current_pair =  0;
-                        objstm->length =        (uint32_t)objstm_length;
-                        objstm->n =             (uint32_t)objstm_n;
-
-                        cli_dbgmsg("pdf_extract_obj: ObjStm first obj at offset %d\n", objstm->first);
-                        cli_dbgmsg("pdf_extract_obj: ObjStm length is %d bytes\n", objstm->length);
-                        cli_dbgmsg("pdf_extract_obj: ObjStm should contain %d objects\n", objstm->n);
+                        free(pdf->objstms[pdf->nobjstms - 1]);
+                        pdf->objstms[pdf->nobjstms - 1] = NULL;
                     }
-                }
 
-                sum = pdf_decodestream(pdf, obj, dparams, start + p_stream, (uint32_t)length, xref, fout, &rc, objstm);
-                if ((CL_SUCCESS != rc) && (CL_VIRUS != rc)) {
-                    cli_dbgmsg("Error decoding stream! Error code: %d\n", rc);
-
-                    /* It's ok if we couldn't decode the stream,
-                     *   make a best effort to keep parsing. */
-                    if (CL_EPARSE == rc)
-                        rc = CL_SUCCESS;
-
-                    if (NULL != objstm) {
-                        /*
-                         * If we were expecting an objstm and there was a failure...
-                         *   discard the memory for last object stream.
-                         */
-                        if (NULL != pdf->objstms) {
-                            if (NULL != pdf->objstms[pdf->nobjstms - 1]) {
-                                if (NULL != pdf->objstms[pdf->nobjstms - 1]->streambuf) {
-                                    free(pdf->objstms[pdf->nobjstms - 1]->streambuf);
-                                    pdf->objstms[pdf->nobjstms - 1]->streambuf = NULL;
-                                }
-                                free(pdf->objstms[pdf->nobjstms - 1]);
-                                pdf->objstms[pdf->nobjstms - 1] = NULL;
-                            }
+                    /* Pop the objstm off the end of the pdf->objstms array. */
+                    if (pdf->nobjstms > 0) {
+                        pdf->nobjstms--;
+                        if (0 == pdf->nobjstms) {
+                            free(pdf->objstms);
+                            pdf->objstms = NULL;
+                        } else {
+                            pdf->objstms = cli_realloc2(pdf->objstms, sizeof(struct objstm_struct*) * pdf->nobjstms);
 
-                            /* Pop the objstm off the end of the pdf->objstms array. */
-                            if (pdf->nobjstms > 0) {
-                                pdf->nobjstms--;
-                                if (0 == pdf->nobjstms) {
-                                    free(pdf->objstms);
-                                    pdf->objstms = NULL;
-                                } else {
-                                    pdf->objstms = cli_realloc2(pdf->objstms, sizeof(struct objstm_struct*) * pdf->nobjstms);
-
-                                    if (!pdf->objstms) {
-                                        cli_warnmsg("pdf_extract_obj: out of memory when shrinking down objstm array\n");
-                                        return CL_EMEM;
-                                    }
-                                }
-                            } else {
-                                /* hm.. this shouldn't happen */
-                                cli_warnmsg("pdf_extract_obj: Failure counting objstms.\n");
+                            if (!pdf->objstms) {
+                                cli_warnmsg("pdf_extract_obj: out of memory when shrinking down objstm array\n");
+                                return CL_EMEM;
                             }
                         }
+                    } else {
+                        /* hm.. this shouldn't happen */
+                        cli_warnmsg("pdf_extract_obj: Failure counting objstms.\n");
                     }
                 }
+            }
+        }
 
-                if (dparams)
-                    pdf_free_dict(dparams);
+        if (dparams)
+            pdf_free_dict(dparams);
 
-                if ((rc == CL_VIRUS) && !SCAN_ALLMATCHES) {
-                    sum = 0; /* prevents post-filter scan */
-                    break;
-                }
+        if ((rc == CL_VIRUS) && !SCAN_ALLMATCHES) {
+            sum = 0; /* prevents post-filter scan */
+            goto done;
+        }
 
-                cli_dbgmsg("-------------EXPERIMENTAL-------------\n");
-            } else {
-                noisy_warnmsg("pdf_extract_obj: cannot find stream bounds for obj %u %u\n", obj->id>>8, obj->id&0xff);
-            }
+        cli_dbgmsg("-------------EXPERIMENTAL-------------\n");
 
-        } else if (obj->flags & (1 << OBJ_JAVASCRIPT)) {
-            const char *q2;
-            const char *q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
-                                          : (const char *)(obj->start + pdf->map);
+    } else if (obj->flags & (1 << OBJ_JAVASCRIPT)) {
+        const char *q2;
+        const char *q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
+                                        : (const char *)(obj->start + pdf->map);
 
-            /* TODO: get obj-endobj size */
-            off_t bytesleft = obj_size(pdf, obj, 0);
+        /* TODO: get obj-endobj size */
+        off_t bytesleft = obj->size;
 
-            if (bytesleft < 0)
-                break;
+        if (bytesleft < 0) {
+            goto done;
+        }
 
-            do {
-                char *js = NULL;
-                size_t js_len = 0;
-                const char *q3;
+        do {
+            char *js = NULL;
+            size_t js_len = 0;
+            const char *q3;
 
-                q2 = cli_memstr(q, bytesleft, "/JavaScript", 11);
-                if (!q2)
-                    break;
+            q2 = cli_memstr(q, bytesleft, "/JavaScript", 11);
+            if (!q2)
+                break;
 
-                bytesleft -= q2 - q + 11;
-                q = q2 + 11;
+            bytesleft -= q2 - q + 11;
+            q = q2 + 11;
 
-                js = pdf_readstring(q, bytesleft,  "/JS", NULL, &q2, !(pdf->flags & (1<<DECRYPTABLE_PDF)));
-                bytesleft -= q2 - q;
-                q = q2;
-
-                if (js) {
-                    char *decrypted = NULL;
-                    const char *out = js;
-                    js_len = strlen(js);
-                    if (pdf->flags & (1 << DECRYPTABLE_PDF)) {
-                        cli_dbgmsg("pdf_extract_obj: encrypted string\n");
-                        decrypted = decrypt_any(pdf, obj->id, js, &js_len, pdf->enc_method_string);
-
-                        if (decrypted) {
-                            noisy_msg(pdf, "pdf_extract_obj: decrypted Javascript string from obj %u %u\n", obj->id>>8,obj->id&0xff);
-                            out = decrypted;
-                        }
+            js = pdf_readstring(q, bytesleft,  "/JS", NULL, &q2, !(pdf->flags & (1<<DECRYPTABLE_PDF)));
+            bytesleft -= q2 - q;
+            q = q2;
+
+            if (js) {
+                char *decrypted = NULL;
+                const char *out = js;
+                js_len = strlen(js);
+                if (pdf->flags & (1 << DECRYPTABLE_PDF)) {
+                    cli_dbgmsg("pdf_extract_obj: encrypted string\n");
+                    decrypted = decrypt_any(pdf, obj->id, js, &js_len, pdf->enc_method_string);
+
+                    if (decrypted) {
+                        noisy_msg(pdf, "pdf_extract_obj: decrypted Javascript string from obj %u %u\n", obj->id>>8,obj->id&0xff);
+                        out = decrypted;
                     }
+                }
 
-                    if (filter_writen(pdf, obj, fout, out, js_len, (size_t*)&sum) != js_len) {
-                        rc = CL_EWRITE;
-                                free(js);
-                        break;
-                    }
+                if (filter_writen(pdf, obj, fout, out, js_len, (size_t*)&sum) != js_len) {
+                    rc = CL_EWRITE;
+                            free(js);
+                    break;
+                }
 
-                    free(decrypted);
-                    free(js);
-                    cli_dbgmsg("pdf_extract_obj: bytesleft: %d\n", (int)bytesleft);
-
-                    if (bytesleft > 0) {
-                        q2 = pdf_nextobject(q, bytesleft);
-                        if (!q2)
-                            q2 = q + bytesleft - 1;
-
-                        /* non-conforming PDFs that don't escape ) properly */
-                        q3 = memchr(q, ')', bytesleft);
-                        if (q3 && q3 < q2)
-                            q2 = q3;
-
-                        while (q2 > q && q2[-1] == ' ')
-                            q2--;
-
-                        if (q2 > q) {
-                            q--;
-                            filter_writen(pdf, obj, fout, q, q2 - q, (size_t*)&sum);
-                            q++;
-                        }
+                free(decrypted);
+                free(js);
+                cli_dbgmsg("pdf_extract_obj: bytesleft: %d\n", (int)bytesleft);
+
+                if (bytesleft > 0) {
+                    q2 = pdf_nextobject(q, bytesleft);
+                    if (!q2)
+                        q2 = q + bytesleft - 1;
+
+                    /* non-conforming PDFs that don't escape ) properly */
+                    q3 = memchr(q, ')', bytesleft);
+                    if (q3 && q3 < q2)
+                        q2 = q3;
+
+                    while (q2 > q && q2[-1] == ' ')
+                        q2--;
+
+                    if (q2 > q) {
+                        q--;
+                        filter_writen(pdf, obj, fout, q, q2 - q, (size_t*)&sum);
+                        q++;
                     }
                 }
+            }
 
-            } while (bytesleft > 0);
-        } else {
-            off_t bytesleft = obj_size(pdf, obj, 0);
+        } while (bytesleft > 0);
+    } else {
+        off_t bytesleft = obj->size;
 
-            if (bytesleft < 0)
-                rc = CL_EFORMAT;
-            else {
-                if (obj->objstm) {
-                    if (filter_writen(pdf, obj, fout , obj->objstm->streambuf + obj->start, bytesleft, (size_t*)&sum) != (size_t)bytesleft)
-                        rc = CL_EWRITE;
-                } else {
-                    if (filter_writen(pdf, obj, fout , pdf->map + obj->start, bytesleft, (size_t*)&sum) != (size_t)bytesleft)
-                        rc = CL_EWRITE;
-                }
+        if (bytesleft < 0)
+            rc = CL_EFORMAT;
+        else {
+            if (obj->objstm) {
+                if (filter_writen(pdf, obj, fout , obj->objstm->streambuf + obj->start, bytesleft, (size_t*)&sum) != (size_t)bytesleft)
+                    rc = CL_EWRITE;
+            } else {
+                if (filter_writen(pdf, obj, fout , pdf->map + obj->start, bytesleft, (size_t*)&sum) != (size_t)bytesleft)
+                    rc = CL_EWRITE;
             }
         }
-    } while (0);
+    }
+
+done:
 
     cli_dbgmsg("pdf_extract_obj: extracted %td bytes %u %u obj\n", sum, obj->id>>8, obj->id&0xff);
     cli_dbgmsg("pdf_extract_obj:         ... to %s\n", fullname);
@@ -1977,6 +1952,7 @@
     const char *q, *q2;
     unsigned long objid;
     unsigned long genid;
+    long temp_long;
 
     if (len >= 16 && !strncmp(enc, "/EncryptMetadata", 16)) {
         q = cli_memstr(enc+16, len-16, "/Encrypt", 8);
@@ -1995,10 +1971,15 @@
     len -= q2 - q;
     q = q2;
 
-    if (CL_SUCCESS != cli_strntoul_wrap(q2, (size_t)len, 0, 10, &objid)) {
+    if (CL_SUCCESS != cli_strntol_wrap(q2, (size_t)len, 0, 10, &temp_long)) {
         cli_dbgmsg("pdf_parse_encrypt: Found Encrypt dictionary but failed to parse objid\n");
         return;
+    } else if (temp_long < 0) {
+        cli_dbgmsg("pdf_parse_encrypt: Encountered invalid negative objid (%ld).\n", temp_long);
+        return;
     }
+    objid = (unsigned long)temp_long;
+
     objid = objid << 8;
     q2 = pdf_nextobject(q, len);
     if (!q2 || !isdigit(*q2))
@@ -2006,11 +1987,16 @@
     len -= q2 - q;
     q = q2;
 
-    if (CL_SUCCESS != cli_strntoul_wrap(q2, (size_t)len, 0, 10, &genid)) {
+    if (CL_SUCCESS != cli_strntol_wrap(q2, (size_t)len, 0, 10, &temp_long)) {
         cli_dbgmsg("pdf_parse_encrypt: Found Encrypt dictionary but failed to parse genid\n");
         return;
+    } else if (temp_long < 0) {
+        cli_dbgmsg("pdf_parse_encrypt: Encountered invalid negative genid (%ld).\n", temp_long);
+        return;
     }
-    objid |= genid & 0xff; 
+    genid = (unsigned long)temp_long;
+
+    objid |= genid & 0xff;
     q2 = pdf_nextobject(q, len);
     if (!q2 || *q2 != 'R')
         return;
@@ -2047,7 +2033,7 @@
     const char *nextobj = NULL, *nextopen = NULL, *nextclose = NULL;
     const char *q = NULL;
     const char *dict = NULL, *enddict = NULL, *start = NULL;
-    off_t dict_length = 0, full_dict_length = 0, objsize = 0, bytesleft = 0;
+    off_t dict_length = 0, full_dict_length = 0, bytesleft = 0;
     size_t i = 0;
     unsigned filters = 0, blockopens = 0;
     enum objstate objstate = STATE_NONE;
@@ -2055,16 +2041,63 @@
     json_object *pdfobj=NULL, *jsonobj=NULL;
 #endif
 
-    q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
-                      : (const char *)(obj->start + pdf->map);
+    if (NULL == pdf || NULL == obj) {
+        cli_warnmsg("pdf_parseobj: invalid arguments\n");
+        return;
+    }
+
+    cli_dbgmsg("pdf_parseobj: Parsing object %u %u\n", obj->id >> 8, obj->id & 0xff);
 
-    objsize = obj_size(pdf, obj, 1);
+    if (obj->objstm) {
+        if ((size_t)obj->start > obj->objstm->streambuf_len) {
+            cli_dbgmsg("pdf_parseobj: %u %u obj: obj start (%u) is greater than size of object stream (%zu).\n",
+                obj->id >> 8, obj->id & 0xff, obj->start, obj->objstm->streambuf_len);
+            return;
+        }
+        q = (const char *)(obj->start + obj->objstm->streambuf);
+    } else {
+        if ((size_t)obj->start > pdf->size) {
+            cli_dbgmsg("pdf_parseobj: %u %u obj: obj start (%u) is greater than size of PDF (%lld).\n",
+                obj->id >> 8, obj->id & 0xff, obj->start, (long long)pdf->size);
+            return;
+        }
+        q = (const char *)(obj->start + pdf->map);
+    }
+    start = q;
 
-    if (objsize < 0)
+    if (obj->size <= 0)
         return;
 
-    start = q;
-    bytesleft = objsize;
+    if (obj->objstm) {
+        bytesleft = MIN(obj->size, obj->objstm->streambuf_len - obj->start);
+    } else {
+        bytesleft = MIN(obj->size, pdf->size - obj->start);
+    }
+
+    /* For objects that aren't already in an object stream^, check if they contain a stream.
+     * ^Objects in object streams aren't supposed to contain streams, so we don't check them. */
+    if (NULL == obj->objstm) {
+        /* Check if object contains stream */
+        cl_error_t has_stream;
+        const char* stream = NULL;
+        size_t stream_size = 0;
+
+        has_stream = find_stream_bounds(
+            start,
+            obj->size,
+            &stream,
+            &stream_size,
+            (pdf->enc_method_stream <= ENC_IDENTITY) && (pdf->enc_method_embeddedfile <= ENC_IDENTITY));
+
+        if ((CL_SUCCESS == has_stream) ||
+            (CL_EFORMAT == has_stream)) {
+            /* Stream found. Store this fact and the stream bounds. */
+            cli_dbgmsg("pdf_parseobj: %u %u contains stream, size: %zu\n", obj->id>>8, obj->id&0xff, stream_size);
+            obj->flags |= (1 << OBJ_STREAM);
+            obj->stream = stream;
+            obj->stream_size = stream_size;
+        }
+    }
 
     /* find start of dictionary */
     do {
@@ -2090,7 +2123,23 @@
             return;
         }
 
+        /*
+         * Opening `<` for object's dictionary may be back 1 character,
+         * provided q is not at the start of the buffer (it shouldn't be).
+         */
+        if (obj->objstm) {
+            if (obj->objstm->streambuf == q) {
+                q3 = memchr(q, '<', nextobj - q);
+            } else {
         q3 = memchr(q-1, '<', nextobj-q+1);
+            }
+        } else {
+            if (pdf->map == q) {
+                q3 = memchr(q, '<', nextobj - q);
+            } else {
+                q3 = memchr(q - 1, '<', nextobj - q + 1);
+            }
+        }
         nextobj++;
         bytesleft--;
         q = nextobj;
@@ -2098,7 +2147,7 @@
     dict = q3+2;
     q = dict;
     blockopens++;
-    bytesleft = objsize - (q - start);
+    bytesleft = obj->size - (q - start);
     enddict = q + bytesleft - 1;
 
     /* find end of dictionary block */
@@ -2249,7 +2298,7 @@
             pdfobj_flag(pdf, obj, LINEARIZED_PDF);
             objstate = STATE_NONE;
             trailer_end = pdf_readint(dict, full_dict_length, "/H");
-            if (trailer_end > 0 && trailer_end < pdf->size) {
+            if ((trailer_end > 0) && ((size_t)trailer_end < pdf->size)) {
                 trailer = trailer_end - 1024;
                 if (trailer < 0)
                     trailer = 0;
@@ -2275,26 +2324,39 @@
                 const char * q2_old = NULL;
                 unsigned long objid;
                 unsigned long genid;
+                long temp_long;
 
                 dict_remaining -= (off_t)(q2 - q);
 
-                if (CL_SUCCESS != cli_strntoul_wrap(q2, (size_t)dict_remaining, 0, 10, &objid)) {
+                if (CL_SUCCESS != cli_strntol_wrap(q2, (size_t)dict_remaining, 0, 10, &temp_long)) {
                     cli_dbgmsg("pdf_parseobj: failed to parse object objid\n");
                     return;
+                } else if (temp_long < 0) {
+                    cli_dbgmsg("pdf_parseobj: Encountered invalid negative genid (%ld).\n", temp_long);
+                    return;
                 }
+                objid = (unsigned long)temp_long;
+
                 objid = objid << 8;
 
-                while (isdigit(*q2))
+                while ((dict_remaining > 0) && isdigit(*q2)) {
                     q2++;
+                    dict_remaining--;
+                }
 
                 q2_old = q2;
                 q2 = pdf_nextobject(q2, dict_remaining);
                 if (q2 && isdigit(*q2)) {
                     dict_remaining -= (off_t)(q2 - q2_old);
-                    if (CL_SUCCESS != cli_strntoul_wrap(q2, (size_t)dict_remaining, 0, 10, &genid)) {
+                    if (CL_SUCCESS != cli_strntol_wrap(q2, (size_t)dict_remaining, 0, 10, &temp_long)) {
                         cli_dbgmsg("pdf_parseobj: failed to parse object genid\n");
                         return;
+                    } else if (temp_long < 0) {
+                        cli_dbgmsg("pdf_parseobj: Encountered invalid negative genid (%ld).\n", temp_long);
+                        return;
                     }
+                    genid = (unsigned long)temp_long;
+
                     objid |= genid & 0xff;
 
                     q2 = pdf_nextobject(q2, dict_remaining);
@@ -2848,7 +2910,7 @@
         return;
     }
 
-    len = obj_size(pdf, obj, 1);
+    len = obj->size;
     q = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
                       : (const char *)(obj->start + pdf->map);
 
@@ -3004,30 +3066,32 @@
 }
 
 /**
- * @brief Search pdf buffer for objects.  Parse each.  
- * 
+ * @brief Search pdf buffer for objects.  Parse each.
+ *
  * Newly found objects will be extracted after completion when the extraction for loop continues.
- * 
- * @param pdf           Pdf struct that keeps track of all information found in the PDF. 
+ *
+ * @param pdf           Pdf struct that keeps track of all information found in the PDF.
  * @param objstm        Pointer to an object stream to parse.
- * 
+ *
  * @return cl_error_t   Error code.
  */
 cl_error_t pdf_find_and_parse_objs_in_objstm(struct pdf_struct *pdf, struct objstm_struct *objstm)
 {
     cl_error_t status = CL_EFORMAT;
     cl_error_t retval = CL_EPARSE;
-    int32_t foundobj = 0, alerts = 0;
+    int32_t alerts = 0;
     uint32_t badobjects = 0;
     size_t i = 0;
 
     struct pdf_obj* obj = NULL;
 
-    char* current_pair = objstm->streambuf;
-    char* current_obj = objstm->streambuf + objstm->first;
+    if ((NULL == objstm) || (NULL == objstm->streambuf)) {
+        status = CL_EARG;
+        goto done;
+    }
 
-    if ((0 == objstm->first) || 
-        (0 == objstm->streambuf_len) || 
+    if ((0 == objstm->first) ||
+        (0 == objstm->streambuf_len) ||
         (0 == objstm->n))
     {
         cli_dbgmsg("pdf_find_and_parse_objs_in_objstm: Empty object stream.\n");
@@ -3053,7 +3117,7 @@
 
         /* Find object */
         retval = pdf_findobj_in_objstm(pdf, objstm, &obj);
-        
+
         if (retval != CL_SUCCESS)
         {
             cli_dbgmsg("pdf_find_and_parse_objs_in_objstm: Fewer objects in stream than expected: %u found, %u expected.\n",
@@ -3083,7 +3147,7 @@
         status = CL_EFORMAT;
         goto done;
     }
-    
+
     status = CL_SUCCESS;
 
 done:
@@ -3092,18 +3156,17 @@
 
 /**
  * @brief Search pdf buffer for objects.  Parse each and then extract each.
- * 
+ *
  * @param pdf               Pdf struct that keeps track of all information found in the PDF.
  * @param alerts[in/out]    The number of alerts, relevant in ALLMATCH mode.
- * 
+ *
  * @return cl_error_t   Error code.
  */
 cl_error_t pdf_find_and_extract_objs(struct pdf_struct *pdf, uint32_t *alerts)
 {
     cl_error_t status = CL_SUCCESS;
     int32_t rv = 0;
-    int foundobj = 0;
-    unsigned int i = 0, j = 0;
+    unsigned int i = 0;
     uint32_t badobjects = 0;
     cli_ctx *ctx = pdf->ctx;
 
@@ -3145,7 +3208,7 @@
          * This doesn't trigger for PDFs that are encrypted but don't need
          * a password to decrypt */
         status = cli_append_virus(pdf->ctx, "Heuristics.Encrypted.PDF");
-        if (status == CL_VIRUS) { 
+        if (status == CL_VIRUS) {
             alerts++;
             if (SCAN_ALLMATCHES)
                 status = CL_CLEAN;
@@ -3204,11 +3267,11 @@
 
 /**
  * @brief Primary function for parsing and scanning a PDF.
- * 
+ *
  * @param dir       Filepath for temp file.
- * @param ctx       clam scan context structure. 
+ * @param ctx       clam scan context structure.
  * @param offset    offset of pdf in ctx->fmap
- * 
+ *
  * @return int      Returns cl_error_t status value.
  */
 int cli_pdf(const char *dir, cli_ctx *ctx, off_t offset)
@@ -3220,6 +3283,7 @@
     off_t versize = size > 1032 ? 1032 : size;
     off_t map_off, bytesleft;
     unsigned long xref;
+    long temp_long;
     const char *pdfver, *tmp, *start, *eofmap, *q, *eof;
     unsigned i, alerts = 0;
     unsigned int objs_found = 0;
@@ -3361,11 +3425,14 @@
 
             while (q < eof && (*q == ' ' || *q == '\n' || *q == '\r')) { q++; }
 
-            if (CL_SUCCESS != cli_strntoul_wrap(q, q - eofmap + map_off, 0, 10, &xref)) {
+            if (CL_SUCCESS != cli_strntol_wrap(q, q - eofmap + map_off, 0, 10, &temp_long)) {
                 cli_dbgmsg("cli_pdf: failed to parse PDF trailer xref\n");
                 pdf.flags |= 1 << BAD_PDF_TRAILER;
-            }
-            else {
+            } else if (temp_long < 0) {
+                cli_dbgmsg("cli_pdf: Encountered invalid negative PDF trailer xref (%ld).\n", temp_long);
+                pdf.flags |= 1 << BAD_PDF_TRAILER;
+            } else {
+                xref      = (unsigned long)temp_long;
                 bytesleft = map->len - offset - xref;
                 if (bytesleft > 4096)
                     bytesleft = 4096;
@@ -3404,7 +3471,7 @@
     }
 
     /*
-     * Find and extract all objects in the PDF. 
+     * Find and extract all objects in the PDF.
      * New experimental recursive methodology that adds objects from object streams.
      */
     objs_found = pdf.nobjs;
@@ -3505,15 +3572,20 @@
 
 /**
  * @brief   Skip the rest of the current line, and find the start of the next line.
- * 
+ *
  * @param ptr   Current offset into buffer.
- * @param len   Remaining bytes in buffer. 
- * 
+ * @param len   Remaining bytes in buffer.
+ *
  * @return const char*  Address of next line, or NULL if no next line in buffer.
  */
 static const char *
 pdf_nextlinestart(const char *ptr, size_t len)
 {
+    if (!ptr || (0 == len)) {
+        /* Invalid args */
+        return NULL;
+    }
+
     while(strchr("\r\n", *ptr) == NULL) {
         if(--len == 0L)
             return NULL;
@@ -3533,13 +3605,13 @@
 
 /**
  * @brief   Return the start of the next PDF object.
- * 
+ *
  * This assumes that we're not in a stream.
- * 
+ *
  * @param ptr   Current offset into buffer.
- * @param len   Remaining bytes in buffer. 
- * 
- * @return const char*  Address of next object in the buffer, or NULL if there is none in the buffer. 
+ * @param len   Remaining bytes in buffer.
+ *
+ * @return const char*  Address of next object in the buffer, or NULL if there is none in the buffer.
  */
 static const char *
 pdf_nextobject(const char *ptr, size_t len)
@@ -3882,7 +3954,7 @@
         pdf->stats.author = cli_calloc(1, sizeof(struct pdf_stats_entry));
         if (!(pdf->stats.author))
             return;
-        pdf->stats.author->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Author", NULL, &(pdf->stats.author->meta));
+        pdf->stats.author->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Author", NULL, &(pdf->stats.author->meta));
     }
 }
 #endif
@@ -3907,7 +3979,7 @@
         pdf->stats.creator = cli_calloc(1, sizeof(struct pdf_stats_entry));
         if (!(pdf->stats.creator))
             return;
-        pdf->stats.creator->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Creator", NULL, &(pdf->stats.creator->meta));
+        pdf->stats.creator->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Creator", NULL, &(pdf->stats.creator->meta));
     }
 }
 #endif
@@ -3932,7 +4004,7 @@
         pdf->stats.modificationdate = cli_calloc(1, sizeof(struct pdf_stats_entry));
         if (!(pdf->stats.modificationdate))
             return;
-        pdf->stats.modificationdate->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/ModDate", NULL, &(pdf->stats.modificationdate->meta));
+        pdf->stats.modificationdate->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/ModDate", NULL, &(pdf->stats.modificationdate->meta));
     }
 }
 #endif
@@ -3957,7 +4029,7 @@
         pdf->stats.creationdate = cli_calloc(1, sizeof(struct pdf_stats_entry));
         if (!(pdf->stats.creationdate))
             return;
-        pdf->stats.creationdate->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/CreationDate", NULL, &(pdf->stats.creationdate->meta));
+        pdf->stats.creationdate->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/CreationDate", NULL, &(pdf->stats.creationdate->meta));
     }
 }
 #endif
@@ -3982,7 +4054,7 @@
         pdf->stats.producer = cli_calloc(1, sizeof(struct pdf_stats_entry));
         if (!(pdf->stats.producer))
             return;
-        pdf->stats.producer->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Producer", NULL, &(pdf->stats.producer->meta));
+        pdf->stats.producer->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Producer", NULL, &(pdf->stats.producer->meta));
     }
 }
 #endif
@@ -4007,7 +4079,7 @@
         pdf->stats.title = cli_calloc(1, sizeof(struct pdf_stats_entry));
         if (!(pdf->stats.title))
             return;
-        pdf->stats.title->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Title", NULL, &(pdf->stats.title->meta));
+        pdf->stats.title->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Title", NULL, &(pdf->stats.title->meta));
     }
 }
 #endif
@@ -4032,7 +4104,7 @@
         pdf->stats.keywords = cli_calloc(1, sizeof(struct pdf_stats_entry));
         if (!(pdf->stats.keywords))
             return;
-        pdf->stats.keywords->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Keywords", NULL, &(pdf->stats.keywords->meta));
+        pdf->stats.keywords->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Keywords", NULL, &(pdf->stats.keywords->meta));
     }
 }
 #endif
@@ -4057,7 +4129,7 @@
         pdf->stats.subject = cli_calloc(1, sizeof(struct pdf_stats_entry));
         if (!(pdf->stats.subject))
             return;
-        pdf->stats.subject->data = pdf_parse_string(pdf, obj, objstart, obj_size(pdf, obj, 1), "/Subject", NULL, &(pdf->stats.subject->meta));
+        pdf->stats.subject->data = pdf_parse_string(pdf, obj, objstart, obj->size, "/Subject", NULL, &(pdf->stats.subject->meta));
     }
 }
 #endif
@@ -4109,8 +4181,8 @@
     const char *objstart = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
                                          : (const char *)(obj->start + pdf->map);
     const char *begin;
-    unsigned int objsize;
     unsigned long npages=0, count;
+    long temp_long;
     struct pdf_array_node *node;
     json_object *pdfobj;
     size_t countsize = 0;
@@ -4123,19 +4195,17 @@
     if (!(SCAN_COLLECT_METADATA))
         return;
 
-    objsize = obj_size(pdf, obj, 1);
-
     pdfobj = cli_jsonobj(pdf->ctx->wrkproperty, "PDFStats");
     if (!(pdfobj))
         return;
 
-    begin = cli_memstr(objstart, objsize, "/Kids", 5);
+    begin = cli_memstr(objstart, obj->size, "/Kids", 5);
     if (!(begin))
         return;
 
     begin += 5;
 
-    array = pdf_parse_array(pdf, obj, objsize, (char *)begin, NULL);
+    array = pdf_parse_array(pdf, obj, obj->size, (char *)begin, NULL);
     if (!(array)) {
         cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
         return;
@@ -4146,27 +4216,33 @@
             if (strchr((char *)(node->data), 'R'))
                 npages++;
 
-    begin = cli_memstr(objstart, objsize, "/Count", 6);
+    begin = cli_memstr(objstart, obj->size, "/Count", 6);
     if (!(begin)) {
         cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
         goto cleanup;
     }
 
     begin += 6;
-    while (begin - objstart <  objsize && isspace(begin[0]))
+    while (((size_t)(begin - objstart) < obj->size) && isspace(begin[0]))
         begin++;
 
-    if (begin - objstart >= objsize) {
+    if ((size_t)(begin - objstart) >= obj->size) {
         goto cleanup;
     }
 
-    countsize = (obj->objstm) ? (size_t)(obj->start + obj->objstm->streambuf + objsize - begin)
-                              : (size_t)(obj->start + pdf->map + objsize - begin);
+    countsize = (obj->objstm) ? (size_t)(obj->start + obj->objstm->streambuf + obj->size - begin)
+                              : (size_t)(obj->start + pdf->map + obj->size - begin);
 
-    if ((CL_SUCCESS != cli_strntoul_wrap(begin, countsize, 0, 10, &count)) ||
-        (count != npages)) {
+    if (CL_SUCCESS != cli_strntol_wrap(begin, countsize, 0, 10, &temp_long)) {
+        cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
+    } else if (temp_long < 0) {
+        cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
+    } else {
+        count = (unsigned long)temp_long;
+        if (count != npages) {
         cli_jsonbool(pdfobj, "IncorrectPagesCount", 1);
     }
+    }
 
 cleanup:
     pdf_free_array(array);
@@ -4179,10 +4255,10 @@
     cli_ctx *ctx = pdf->ctx;
     json_object *colorsobj, *pdfobj;
     unsigned long ncolors;
+    long temp_long;
     char *p1;
     const char *objstart = (obj->objstm) ? (const char *)(obj->start + obj->objstm->streambuf)
                                          : (const char *)(obj->start + pdf->map);
-    size_t objsize;
 
     UNUSEDPARAM(act);
 
@@ -4192,26 +4268,28 @@
     if (!(SCAN_COLLECT_METADATA))
         return;
 
-    objsize = obj_size(pdf, obj, 1);
-
-    p1 = (char *)cli_memstr(objstart, objsize, "/Colors", 7);
+    p1 = (char *)cli_memstr(objstart, obj->size, "/Colors", 7);
     if (!(p1))
         return;
 
     p1 += 7;
 
     /* Ensure that we have at least one whitespace character plus at least one number */
-    if (objsize - (p1 - objstart) < 2)
+    if (obj->size - (size_t)(p1 - objstart) < 2)
         return;
 
-    while (p1 - objstart < objsize && isspace(p1[0]))
+    while (((size_t)(p1 - objstart) < obj->size) && isspace(p1[0]))
         p1++;
 
-    if ((size_t)(p1 - objstart) == objsize)
+    if ((size_t)(p1 - objstart) == obj->size)
         return;
 
-    if (CL_SUCCESS != cli_strntoul_wrap(p1, (size_t)((p1 - objstart) - objsize), 0, 10, &ncolors))
+    if (CL_SUCCESS != cli_strntol_wrap(p1, (size_t)((p1 - objstart) - obj->size), 0, 10, &temp_long)) {
         return;
+    } else if (temp_long < 0) {
+        return;
+    }
+    ncolors = (unsigned long)temp_long;
 
     /* We only care if the number of colors > 2**24 */
     if (ncolors < 1<<24)
diff -Nru clamav-0.101.1+dfsg/libclamav/pdf.h clamav-0.101.2+dfsg/libclamav/pdf.h
--- clamav-0.101.1+dfsg/libclamav/pdf.h	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/pdf.h	2019-03-13 22:13:01.000000000 +0100
@@ -37,12 +37,14 @@
 
 struct pdf_obj {
     uint32_t start;
-    int32_t size;
+    size_t size;
     uint32_t id;
     uint32_t flags;
     uint32_t statsflags;
     uint32_t numfilters;
     uint32_t filterlist[PDF_FILTERLIST_MAX];
+    const char *stream;     // pointer to stream contained in object.
+    size_t stream_size;      // size of stream contained in object.
     struct objstm_struct *objstm;  // Should be NULL unless the obj exists in an object stream (separate buffer)
     char *path;
 };
@@ -146,7 +148,7 @@
     const char *CF;
     long CF_n;
     const char *map;
-    off_t size;
+    size_t size;
     off_t offset;
     off_t startoff;
     cli_ctx *ctx;
diff -Nru clamav-0.101.1+dfsg/libclamav/scanners.c clamav-0.101.2+dfsg/libclamav/scanners.c
--- clamav-0.101.1+dfsg/libclamav/scanners.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/scanners.c	2019-03-13 22:13:01.000000000 +0100
@@ -223,16 +223,15 @@
 
 /**
  * @brief  Scan the metadata using cli_matchmeta()
- * 
+ *
  * @param metadata  unrar metadata structure
  * @param ctx       scanning context structure
- * @param files     
+ * @param files
  * @return cl_error_t  Returns CL_CLEAN if nothing found, CL_VIRUS if something found, CL_EUNPACK if encrypted.
  */
 static cl_error_t cli_unrar_scanmetadata(unrar_metadata_t* metadata, cli_ctx* ctx, unsigned int files)
 {
     cl_error_t status = CL_CLEAN;
-    int virus_found = 0;
 
     cli_dbgmsg("RAR: %s, crc32: 0x%x, encrypted: %u, compressed: %u, normal: %u, method: %u, ratio: %u\n",
         metadata->filename, metadata->crc, metadata->encrypted, (unsigned int)metadata->pack_size,
@@ -246,8 +245,6 @@
         status = CL_EUNPACK;
     }
 
-done:
-
     return status;
 }
 
@@ -255,9 +252,8 @@
 {
     cl_error_t status = CL_EPARSE;
     cl_unrar_error_t unrar_ret = UNRAR_ERR;
-    
+
     char* extract_dir = NULL; /* temp dir to write extracted files to */
-    char* comment_dir = NULL; /* temp dir to write file comments to */
     unsigned int file_count = 0;
     unsigned int viruses_found = 0;
 
@@ -283,7 +279,7 @@
 
     /* Zero out the metadata struct before we read the header */
     memset(&metadata, 0, sizeof(unrar_metadata_t));
-    
+
     /* Determine file basename */
     if (CL_SUCCESS != cli_basename(filepath, strlen(filepath), &filename_base)) {
         status = CL_EARG;
@@ -313,6 +309,9 @@
         if (unrar_ret == UNRAR_EMEM) {
             status = CL_EMEM;
             goto done;
+        } else if (unrar_ret == UNRAR_EOPEN) {
+            status = CL_EOPEN;
+            goto done;
         } else {
             status = CL_EFORMAT;
             goto done;
@@ -360,7 +359,7 @@
     /*
      * Read & scan each file header.
      * Extract & scan each file.
-     * 
+     *
      * Skip files if they will exceed max filesize or max scansize.
      * Count the number of encrypted file headers and encrypted files.
      *  - Alert if there are encrypted files,
@@ -416,7 +415,7 @@
             /* Check if we've already exceeded the scan limit */
             if (cli_checklimits("RAR", ctx, 0, 0, 0))
                 break;
-            
+
             if (metadata.is_dir) {
                 /* Entry is a directory. Skip. */
                 cli_dbgmsg("RAR: Found directory. Skipping to next file.\n");
@@ -427,7 +426,7 @@
                     break;
                 }
             } else if (cli_checklimits("RAR", ctx, metadata.unpack_size, 0, 0)) {
-                /* File size exceeds maxfilesize, must skip extraction. 
+                /* File size exceeds maxfilesize, must skip extraction.
                 * Although we may be able to scan the metadata */
                 nTooLargeFilesFound += 1;
 
@@ -450,9 +449,9 @@
                 }
             } else {
                 /*
-                * Extract the file...
-                */
-                extract_fullpath = cli_gentemp_with_prefix(extract_dir, metadata.filename);
+                 * Extract the file...
+                 */
+                extract_fullpath = cli_gentemp(extract_dir);
                 if (NULL == extract_fullpath) {
                     cli_dbgmsg("RAR: Memory error allocating filename for extracted file.");
                     status = CL_EMEM;
@@ -462,12 +461,12 @@
 
                 unrar_ret = cli_unrar_extract_file(hArchive, extract_fullpath, NULL);
                 if (unrar_ret != UNRAR_OK) {
-                    /* 
+                    /*
                      * Some other error extracting the file
                      */
                     cli_dbgmsg("RAR: Error extracting file: %s\n", metadata.filename);
 
-                    /* TODO: 
+                    /* TODO:
                      *   may need to manually skip the file depending on what, specifically, cli_unrar_extract_file() returned.
                      */
                 } else {
@@ -1216,7 +1215,8 @@
 
 static int cli_vba_scandir(const char *dirname, cli_ctx *ctx, struct uniq *U)
 {
-    int ret = CL_CLEAN, i, j, fd, data_len, hasmacros = 0;
+    cl_error_t ret = CL_CLEAN;
+    int i, j, fd, data_len, hasmacros = 0;
     vba_project_t *vba_project;
     DIR *dd;
     struct dirent *dent;
@@ -1230,25 +1230,30 @@
     char *fullname, vbaname[1024];
     unsigned char *data;
     char *hash;
-    uint32_t hashcnt;
+    uint32_t hashcnt           = 0;
     unsigned int viruses_found = 0;
 
     cli_dbgmsg("VBADir: %s\n", dirname);
-    hashcnt = uniq_get(U, "_vba_project", 12, NULL);
-    while (hashcnt--)
-    {
-        if (!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt)))
+    if (CL_SUCCESS != (ret = uniq_get(U, "_vba_project", 12, NULL, &hashcnt))) {
+        cli_dbgmsg("VBADir: uniq_get('_vba_project') failed with ret code (%d)!\n", ret);
+        return ret;
+    }
+    while (hashcnt) {
+        if (!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) {
+            hashcnt--;
             continue;
+        }
 
         for (i = 0; i < vba_project->count; i++)
         {
-            for (j = 0; (unsigned int)j < vba_project->colls[i]; j++)
+            for (j = 1; (unsigned int)j <= vba_project->colls[i]; j++)
             {
                 snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", vba_project->dir, vba_project->name[i], j);
                 vbaname[sizeof(vbaname) - 1] = '\0';
                 fd = open(vbaname, O_RDONLY | O_BINARY);
-                if (fd == -1)
+                if (fd == -1) {
                     continue;
+                }
                 cli_dbgmsg("VBADir: Decompress VBA project '%s_%u'\n", vba_project->name[i], j);
                 data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
                 close(fd);
@@ -1300,29 +1305,30 @@
             }
         }
 
-        free(vba_project->name);
-        free(vba_project->colls);
-        free(vba_project->dir);
-        free(vba_project->offset);
-        free(vba_project);
+        cli_free_vba_project(vba_project);
+        vba_project = NULL;
+
         if (ret == CL_VIRUS && !SCAN_ALLMATCHES)
             break;
+
+        hashcnt--;
     }
 
-    if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) &&
-        (hashcnt = uniq_get(U, "powerpoint document", 19, &hash)))
-    {
-        while (hashcnt--)
-        {
+    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) {
+        if (CL_SUCCESS != (ret = uniq_get(U, "powerpoint document", 19, &hash, &hashcnt))) {
+            cli_dbgmsg("VBADir: uniq_get('powerpoint document') failed with ret code (%d)!\n", ret);
+            return ret;
+        }
+        while (hashcnt) {
             snprintf(vbaname, 1024, "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
             vbaname[sizeof(vbaname) - 1] = '\0';
             fd = open(vbaname, O_RDONLY | O_BINARY);
-            if (fd == -1)
+            if (fd == -1) {
+                hashcnt--;
                 continue;
-            if ((fullname = cli_ppt_vba_read(fd, ctx)))
-            {
-                if (cli_scandir(fullname, ctx) == CL_VIRUS)
-                {
+            }
+            if ((fullname = cli_ppt_vba_read(fd, ctx))) {
+                if (cli_scandir(fullname, ctx) == CL_VIRUS) {
                     ret = CL_VIRUS;
                     viruses_found++;
                 }
@@ -1331,23 +1337,28 @@
                 free(fullname);
             }
             close(fd);
+            hashcnt--;
         }
     }
 
-    if ((ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) &&
-        (hashcnt = uniq_get(U, "worddocument", 12, &hash)))
-    {
-        while (hashcnt--)
-        {
+    if (ret == CL_CLEAN || (ret == CL_VIRUS && SCAN_ALLMATCHES)) {
+        if (CL_SUCCESS != (ret = uniq_get(U, "worddocument", 12, &hash, &hashcnt))) {
+            cli_dbgmsg("VBADir: uniq_get('worddocument') failed with ret code (%d)!\n", ret);
+            return ret;
+        }
+        while (hashcnt) {
             snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
             vbaname[sizeof(vbaname) - 1] = '\0';
             fd = open(vbaname, O_RDONLY | O_BINARY);
-            if (fd == -1)
+            if (fd == -1) {
+                hashcnt--;
                 continue;
+            }
 
             if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd)))
             {
                 close(fd);
+                hashcnt--;
                 continue;
             }
 
@@ -1380,20 +1391,16 @@
             }
 
             close(fd);
-            free(vba_project->name);
-            free(vba_project->colls);
-            free(vba_project->dir);
-            free(vba_project->offset);
-            free(vba_project->key);
-            free(vba_project->length);
-            free(vba_project);
-            if (ret == CL_VIRUS)
-            {
+            cli_free_vba_project(vba_project);
+            vba_project = NULL;
+
+            if (ret == CL_VIRUS) {
                 if (SCAN_ALLMATCHES)
                     viruses_found++;
                 else
                     break;
             }
+            hashcnt--;
         }
     }
 
@@ -1402,11 +1409,12 @@
 
 #if HAVE_JSON
     /* JSON Output Summary Information */
-    if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL))
-    {
-        hashcnt = uniq_get(U, "_5_summaryinformation", 21, &hash);
-        while (hashcnt--)
-        {
+    if (SCAN_COLLECT_METADATA && (ctx->wrkproperty != NULL)) {
+        if (CL_SUCCESS != (ret = uniq_get(U, "_5_summaryinformation", 21, &hash, &hashcnt))) {
+            cli_dbgmsg("VBADir: uniq_get('_5_summaryinformation') failed with ret code (%d)!\n", ret);
+            return ret;
+        }
+        while (hashcnt) {
             snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
             vbaname[sizeof(vbaname) - 1] = '\0';
 
@@ -1418,11 +1426,14 @@
                 cli_ole2_summary_json(ctx, fd, 0);
                 close(fd);
             }
+            hashcnt--;
         }
 
-        hashcnt = uniq_get(U, "_5_documentsummaryinformation", 29, &hash);
-        while (hashcnt--)
-        {
+        if (CL_SUCCESS != (ret = uniq_get(U, "_5_documentsummaryinformation", 29, &hash, &hashcnt))) {
+            cli_dbgmsg("VBADir: uniq_get('_5_documentsummaryinformation') failed with ret code (%d)!\n", ret);
+            return ret;
+        }
+        while (hashcnt) {
             snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
             vbaname[sizeof(vbaname) - 1] = '\0';
 
@@ -1434,14 +1445,17 @@
                 cli_ole2_summary_json(ctx, fd, 1);
                 close(fd);
             }
+            hashcnt--;
         }
     }
 #endif
 
     /* Check directory for embedded OLE objects */
-    hashcnt = uniq_get(U, "_1_ole10native", 14, &hash);
-    while (hashcnt--)
-    {
+    if (CL_SUCCESS != (ret = uniq_get(U, "_1_ole10native", 14, &hash, &hashcnt))) {
+        cli_dbgmsg("VBADir: uniq_get('_1_ole10native') failed with ret code (%d)!\n", ret);
+        return ret;
+    }
+    while (hashcnt) {
         snprintf(vbaname, sizeof(vbaname), "%s" PATHSEP "%s_%u", dirname, hash, hashcnt);
         vbaname[sizeof(vbaname) - 1] = '\0';
 
@@ -1453,6 +1467,7 @@
             if (ret != CL_CLEAN && !(ret == CL_VIRUS && SCAN_ALLMATCHES))
                 return ret;
         }
+        hashcnt--;
     }
 
     /* ACAB: since we now hash filenames and handle collisions we
@@ -2580,7 +2595,6 @@
 {
     int ret = CL_CLEAN, nret = CL_CLEAN;
     struct cli_matched_type *ftoffset = NULL, *fpt;
-    uint32_t lastrar;
     struct cli_exe_info peinfo;
     unsigned int acmode = AC_SCAN_VIR, break_loop = 0;
     fmap_t *map = *ctx->fmap;
@@ -2660,7 +2674,11 @@
                         cli_set_container(ctx, CL_TYPE_RAR, csize);
                         cli_dbgmsg("RAR/RAR-SFX signature found at %u\n", (unsigned int)fpt->offset);
 
-                        if ((ctx->sub_filepath == NULL) || (fpt->offset != 0)) {
+#ifdef _WIN32
+                        if ((fpt->offset != 0) || (SCAN_UNPRIVILEGED)|| (NULL == ctx->sub_filepath) || (0 != _access_s(ctx->sub_filepath, R_OK))) {
+#else
+                        if ((fpt->offset != 0) || (SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != access(ctx->sub_filepath, R_OK))) {
+#endif
                             /*
                              * If map is not file-backed, or offset is not at the start of the file...
                              * ...have to dump to file for scanrar.
@@ -2683,6 +2701,25 @@
                         /* scan file */
                         nret = cli_scanrar(filepath, fd, ctx);
 
+                        if ((NULL == tmpname) && (CL_EOPEN == nret)) {
+                            /*
+                             * Failed to open the file using the original filename.
+                             * Try writing the file descriptor to a temp file and try again.
+                             */
+                            nret = fmap_dump_to_file(map, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, fpt->offset, fpt->offset + csize);
+                            if (nret != CL_SUCCESS) {
+                                cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
+                                ret = nret;
+                                break_loop = 1;
+                                break;
+                            }
+                            filepath = tmpname;
+                            fd = tmpfd;
+
+                            /* try to scan again */
+                            nret = cli_scanrar(filepath, fd, ctx);
+                        }
+
                         if (tmpfd != -1)
                         {
                             /* If dumped tempfile, need to cleanup */
@@ -3348,7 +3385,11 @@
             char *tmpname = NULL;
             int tmpfd = -1;
 
-            if (ctx->sub_filepath == NULL) {
+#ifdef _WIN32
+            if ((SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != _access_s(ctx->sub_filepath, R_OK))) {
+#else
+            if ((SCAN_UNPRIVILEGED) || (NULL == ctx->sub_filepath) || (0 != access(ctx->sub_filepath, R_OK))) {
+#endif
                 /* If map is not file-backed have to dump to file for scanrar. */
                 ret = fmap_dump_to_file(*ctx->fmap, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, 0, SIZE_MAX);
                 if (ret != CL_SUCCESS) {
@@ -3366,6 +3407,23 @@
             /* scan file */
             ret = cli_scanrar(filepath, fd, ctx);
 
+            if ((NULL == tmpname) && (CL_EOPEN == ret)) {
+                /*
+                 * Failed to open the file using the original filename.
+                 * Try writing the file descriptor to a temp file and try again.
+                 */
+                ret = fmap_dump_to_file(*ctx->fmap, ctx->sub_filepath, ctx->engine->tmpdir, &tmpname, &tmpfd, 0, SIZE_MAX);
+                if (ret != CL_SUCCESS) {
+                    cli_dbgmsg("cli_scanraw: failed to generate temporary file.\n");
+                    break;
+                }
+                filepath = tmpname;
+                fd = tmpfd;
+
+                /* try to scan again */
+                ret = cli_scanrar(filepath, fd, ctx);
+            }
+
             if (tmpfd != -1) {
                 /* If dumped tempfile, need to cleanup */
                 close(tmpfd);
@@ -3786,10 +3844,15 @@
     }
 }
 
-static int cli_base_scandesc(int desc, const char *filepath, cli_ctx *ctx, cli_file_t type)
+static cl_error_t cli_base_scandesc(int desc, const char *filepath, cli_ctx *ctx, cli_file_t type)
 {
     STATBUF sb;
-    int ret;
+    cl_error_t status = CL_CLEAN;
+    cl_error_t ret    = CL_CLEAN;
+
+    if (!ctx) {
+        return CL_EARG;
+    }
 
     const char *parent_filepath = ctx->sub_filepath;
     ctx->sub_filepath = filepath;
@@ -3802,12 +3865,18 @@
     if (FSTAT(desc, &sb) == -1)
     {
         cli_errmsg("magic_scandesc: Can't fstat descriptor %d\n", desc);
-        early_ret_from_magicscan(CL_ESTAT);
+
+        status = CL_ESTAT;
+        cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", status, __AT__);
+        goto done;  
     }
     if (sb.st_size <= 5)
     {
         cli_dbgmsg("Small data (%u bytes)\n", (unsigned int)sb.st_size);
-        early_ret_from_magicscan(CL_CLEAN);
+
+        status = CL_CLEAN;
+        cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", status, __AT__);
+        goto done;  
     }
 
     ctx->fmap++;
@@ -3817,18 +3886,22 @@
         cli_errmsg("CRITICAL: fmap() failed\n");
         ctx->fmap--;
         perf_stop(ctx, PERFT_MAP);
-        early_ret_from_magicscan(CL_EMEM);
+
+        status = CL_EMEM;
+        cli_dbgmsg("cli_magic_scandesc: returning %d %s (no post, no cache)\n", status, __AT__);
+        goto done;  
     }
     perf_stop(ctx, PERFT_MAP);
 
-    ret = magic_scandesc(ctx, type);
+    status = magic_scandesc(ctx, type);
 
     funmap(*ctx->fmap);
     ctx->fmap--;
 
+done:
     ctx->sub_filepath = parent_filepath;
 
-    return ret;
+    return status;
 }
 
 int cli_magic_scandesc(int desc, const char *filepath, cli_ctx *ctx)
@@ -4015,8 +4088,8 @@
 }
 
 /**
- * @brief   The main function to initiate a scan, that may be invoked with a file descriptor or a file map. 
- * 
+ * @brief   The main function to initiate a scan, that may be invoked with a file descriptor or a file map.
+ *
  * @param desc              File descriptor of an open file. The caller must provide this or the map.
  * @param map               File map. The caller must provide this or the desc.
  * @param filepath          (optional, recommended) filepath of the open file descriptor or file map.
@@ -4092,23 +4165,13 @@
         }
     }
 
-    /* Best effort to determine the filename if not provided. 
-     * May still be NULL if filename could not be determined. */
-    if (filepath == NULL)
+    if (filepath != NULL)
     {
-        char *fpath = NULL;
-
-        if (desc >= 0) {
-            (void) cli_get_filepath_from_filedesc(desc, &fpath);
-        }
-
-        ctx.target_filepath = fpath;
-    } else {
         ctx.target_filepath = strdup(filepath);
     }
 
     cli_logg_setup(&ctx);
-    rc = map ? cli_map_scandesc(map, 0, map->len, &ctx, CL_TYPE_ANY) 
+    rc = map ? cli_map_scandesc(map, 0, map->len, &ctx, CL_TYPE_ANY)
              : cli_magic_scandesc(desc, ctx.target_filepath, &ctx);
 
 #if HAVE_JSON
@@ -4237,8 +4300,8 @@
     if (rc == CL_CLEAN)
     {
         if ((ctx.found_possibly_unwanted) ||
-            ((ctx.num_viruses != 0) && 
-               ((ctx.options->general & CL_SCAN_GENERAL_ALLMATCHES) || 
+            ((ctx.num_viruses != 0) &&
+               ((ctx.options->general & CL_SCAN_GENERAL_ALLMATCHES) ||
                 (ctx.options->heuristic & CL_SCAN_HEURISTIC_EXCEEDS_MAX))
             ))
             rc = CL_VIRUS;
@@ -4279,8 +4342,8 @@
             return CL_VIRUS;
         }
         /* heuristic scan isn't taking precedence, keep scanning.
-     * If this is part of an archive, and 
-     * we find a real malware we report that instead of the 
+     * If this is part of an archive, and
+     * we find a real malware we report that instead of the
      * heuristic match */
         ctx->found_possibly_unwanted = 1;
     }
diff -Nru clamav-0.101.1+dfsg/libclamav/str.c clamav-0.101.2+dfsg/libclamav/str.c
--- clamav-0.101.1+dfsg/libclamav/str.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/str.c	2019-03-13 22:13:01.000000000 +0100
@@ -268,7 +268,7 @@
 	return NULL;
 
     for(i = 0, j = 0; i < length; i += 2, j++) {
-       decoded[j] = str[i + 1] << 4;
+        decoded[j] = ((unsigned char) str[i + 1]) << 4;
        decoded[j] += str[i];
     }
 
@@ -400,9 +400,9 @@
     return output;
 }
 
-const char *cli_memstr(const char *haystack, unsigned int hs, const char *needle, unsigned int ns)
+const char *cli_memstr(const char *haystack, size_t hs, const char *needle, size_t ns)
 {
-	unsigned int i, s1, s2;
+	size_t i, s1, s2;
 
     if(!hs || !ns || hs < ns)
 	return NULL;
@@ -496,6 +496,48 @@
 }
 #endif
 
+#if !defined(HAVE_STRNSTR) || defined(HAVE_STRNI)
+/*
+ * @brief Find the first occurrence of find in s.
+ *
+ * The search is limited to the first slen characters of s.
+ *
+ * Copyright (c) 2001 Mike Barcroft <mike at FreeBSD.org>
+ * Copyright (c) 1990, 1993
+ * The Regents of the University of California.  All rights reserved.
+ *
+ * This code is derived from software contributed to Berkeley by
+ * Chris Torek.
+ *
+ * Copyright (c) 1990 The Regents of the University of California.
+ * All rights reserved.
+ *
+ * @param s      haystack
+ * @param find   needle
+ * @param slen   haystack length
+ * @return char* Address of the needle, if found, else NULL.
+ */
+char *cli_strnstr(const char *s, const char *find, size_t slen)
+{
+    char c, sc;
+    size_t len;
+
+    if ((c = *find++) != '\0') {
+        len = strlen(find);
+        do {
+            do {
+                if (slen-- < 1 || (sc = *s++) == '\0')
+                    return (NULL);
+            } while (sc != c);
+            if (len > slen)
+                return (NULL);
+        } while (strncmp(s, find, len) != 0);
+        s--;
+    }
+    return ((char *)s);
+}
+#endif
+
 size_t cli_strtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens)
 {
 	size_t tokens_found, i;
@@ -907,12 +949,14 @@
 			if(k+5 >= len || str[k+1] != 'u' || !isxdigit(str[k+2]) || !isxdigit(str[k+3])
 						|| !isxdigit(str[k+4]) || !isxdigit(str[k+5])) {
 				if(k+2 < len && isxdigit(str[k+1]) && isxdigit(str[k+2])) {
-					c = (cli_hex2int(str[k+1])<<4) | cli_hex2int(str[k+2]);
+                    c = ((cli_hex2int(str[k + 1]) < 0 ? 0 : cli_hex2int(str[k + 1])) << 4) | cli_hex2int(str[k + 2]);
 					k += 2;
 				}
 			} else {
-				uint16_t u = (cli_hex2int(str[k+2])<<12) | (cli_hex2int(str[k+3])<<8) |
-					(cli_hex2int(str[k+4])<<4) | cli_hex2int(str[k+5]);
+                uint16_t u = ((cli_hex2int(str[k + 2]) < 0 ? 0 : cli_hex2int(str[k + 2])) << 12) |
+                             ((cli_hex2int(str[k + 3]) < 0 ? 0 : cli_hex2int(str[k + 3])) << 8)  |
+                             ((cli_hex2int(str[k + 4]) < 0 ? 0 : cli_hex2int(str[k + 4])) << 4)  |
+                               cli_hex2int(str[k + 5]);
 				i += output_utf8(u, (unsigned char*)&R[i]);
 				k += 5;
 				continue;
@@ -958,13 +1002,15 @@
 					break;
 				case 'x':
 					if(i+2 < len)
-						c = (cli_hex2int(str[i+1])<<4)|cli_hex2int(str[i+2]);
+                        c = ((cli_hex2int(str[i + 1]) < 0 ? 0 : cli_hex2int(str[i + 1])) << 4) | cli_hex2int(str[i + 2]);
 					i += 2;
 					break;
 				case 'u':
 					if(i+4 < len) {
-						uint16_t u = (cli_hex2int(str[i+1])<<12) | (cli_hex2int(str[i+2])<<8) |
-							(cli_hex2int(str[i+3])<<4) | cli_hex2int(str[i+4]);
+                        uint16_t u = ((cli_hex2int(str[i + 1]) < 0 ? 0 : cli_hex2int(str[i + 1])) << 12) |
+                                     ((cli_hex2int(str[i + 2]) < 0 ? 0 : cli_hex2int(str[i + 2])) << 8)  |
+                                     ((cli_hex2int(str[i + 3]) < 0 ? 0 : cli_hex2int(str[i + 3])) << 4)  | 
+                                       cli_hex2int(str[i + 4]);
 						if(textbuffer_ensure_capacity(buf, 4) == -1)
 							return -1;
 						buf->pos += output_utf8(u, (unsigned char*)&buf->data[buf->pos]);
diff -Nru clamav-0.101.1+dfsg/libclamav/str.h clamav-0.101.2+dfsg/libclamav/str.h
--- clamav-0.101.1+dfsg/libclamav/str.h	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/str.h	2019-03-13 22:13:01.000000000 +0100
@@ -52,6 +52,12 @@
 size_t cli_strnlen(const char *s, size_t n);
 #endif
 
+#if defined(HAVE_STRNSTR) && !defined(HAVE_STRNI)
+#define cli_strnstr strnstr
+#else
+char *cli_strnstr(const char *s, const char *find, size_t slen);
+#endif
+
 #include <stdio.h>
 #define cli_nocase(val) tolower(val)
 #define cli_nocasei(val) toupper(val)
@@ -68,7 +74,7 @@
 char *cli_str2hex(const char *string, unsigned int len);
 char *cli_utf16toascii(const char *str, unsigned int length);
 char *cli_strtokbuf(const char *input, int fieldno, const char *delim, char *output);
-const char *cli_memstr(const char *haystack, unsigned int hs, const char *needle, unsigned int ns);
+const char *cli_memstr(const char *haystack, size_t hs, const char *needle, size_t ns);
 char *cli_strrcpy(char *dest, const char *source);
 size_t cli_strtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens);
 size_t cli_ldbtokenize(char *buffer, const char delim, const size_t token_count, const char **tokens, int token_skip);
diff -Nru clamav-0.101.1+dfsg/libclamav/unarj.c clamav-0.101.2+dfsg/libclamav/unarj.c
--- clamav-0.101.1+dfsg/libclamav/unarj.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/unarj.c	2019-03-13 22:13:01.000000000 +0100
@@ -163,7 +163,9 @@
 {
         if (decode_data->status == CL_EFORMAT)
 	    return CL_EFORMAT;
-	decode_data->bit_buf = (decode_data->bit_buf << n) & 0xFFFF;
+    if (((uint64_t) decode_data->bit_buf) * (n > 0 ? 2 << (n - 1) : 0) > UINT32_MAX)
+        return CL_EFORMAT;
+    decode_data->bit_buf = (((uint64_t) decode_data->bit_buf) << n) & 0xFFFF;
 	while (n > decode_data->bit_count) {
 		decode_data->bit_buf |= decode_data->sub_bit_buf << (n -= decode_data->bit_count);
 		if (decode_data->comp_size != 0) {
@@ -623,10 +625,34 @@
 	return CL_SUCCESS;
 }
 
-#define ARJ_BFIL(dd) {dd->getbuf|=dd->bit_buf>>dd->getlen;fill_buf(dd,CODE_BIT-dd->getlen);dd->getlen=CODE_BIT;}
-#define ARJ_GETBIT(dd,c) {if(dd->getlen<=0)ARJ_BFIL(dd) c=(dd->getbuf&0x8000)!=0;dd->getbuf<<=1;dd->getlen--;}
-#define ARJ_BPUL(dd,l) {dd->getbuf<<=l;dd->getlen-=l;}
-#define ARJ_GETBITS(dd,c,l) {if(dd->getlen<l)ARJ_BFIL(dd) c=(uint16_t)dd->getbuf>>(CODE_BIT-l);ARJ_BPUL(dd,l)}
+#define ARJ_BFIL(dd)                             \
+    {                                            \
+        dd->getbuf |= dd->bit_buf >> dd->getlen; \
+        fill_buf(dd, CODE_BIT - dd->getlen);     \
+        dd->getlen = CODE_BIT;                   \
+    }
+#define ARJ_GETBIT(dd, c)                                    \
+    {                                                        \
+        if (dd->getlen <= 0) ARJ_BFIL(dd)                    \
+                             c = (dd->getbuf & 0x8000) != 0; \
+        dd->getbuf *= 2;                                    \
+        dd->getlen--;                                        \
+    }
+#define ARJ_BPUL(dd, l)           \
+    do {                          \
+        int i;                    \
+        int j = l;                \
+        for (i = 0; i < j; i++) { \
+            dd->getbuf *= 2;      \
+        }                         \
+        dd->getlen -= l;          \
+    } while(0)
+#define ARJ_GETBITS(dd, c, l)                                           \
+    {                                                                   \
+        if (dd->getlen < l) ARJ_BFIL(dd)                                \
+                            c = (uint16_t)dd->getbuf >> (CODE_BIT - l); \
+        ARJ_BPUL(dd, l);                                                 \
+    }
 
 static uint16_t decode_ptr(arj_decode_t *decode_data)
 {
@@ -689,6 +715,7 @@
 	decode_data.comp_size = metadata->comp_size;
 	ret = init_getbits(&decode_data);
 	if (ret != CL_SUCCESS) {
+        free(decode_data.text);
 	        metadata->offset = decode_data.offset;
 		return ret;
 	}
diff -Nru clamav-0.101.1+dfsg/libclamav/uniq.c clamav-0.101.2+dfsg/libclamav/uniq.c
--- clamav-0.101.1+dfsg/libclamav/uniq.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/uniq.c	2019-03-13 22:13:01.000000000 +0100
@@ -46,6 +46,7 @@
     uniq_free(U);
     return NULL;
   }
+    U->max_unique_items = count;
 
   return U;
 }
@@ -55,18 +56,39 @@
   free(U);
 }
 
-uint32_t uniq_add(struct uniq *U, const char *key, uint32_t key_len, char **rhash) {
+cl_error_t uniq_add(struct uniq *U, const char *item, uint32_t item_len, char **rhash, uint32_t *count)
+{
+  cl_error_t status = CL_EARG;
   unsigned int i;
   uint8_t digest[16];
   struct UNIQMD5 *m = NULL;
 
-  cl_hash_data("md5", key, key_len, digest, NULL);
+    if (!U) {
+        /* Invalid args */
+        goto done;
+    }
+
+    /* Uniq adds are limited by the maximum allocated in uniq_init(). */
+    if (U->cur_unique_items >= U->max_unique_items) {
+        /* Attempted to add more uniq items than may be stored. */
+        status = CL_EMAXSIZE;
+        goto done;
+    }
+
+    /* Make a hash of the item string */
+    if (NULL == cl_hash_data("md5", item, item_len, digest, NULL)) {
+        /* Failed to create hash of item. */
+        status = CL_EFORMAT;
+        goto done;
+    }
 
+    /* Check for md5 digest match in md5 collection */
   if(U->items && U->md5s[U->idx[*digest]].md5[0]==*digest)
     for(m=&U->md5s[U->idx[*digest]]; m; m=m->next)
       if(!memcmp(&digest[1], &m->md5[1], 15)) break;
   
   if(!m) {
+        /* No match. Add new md5 to list */
     const char HEX[] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f' };
 
     m = &U->md5s[U->items];
@@ -85,27 +107,85 @@
       m->md5[i] = digest[i];
     }
     m->name[32] = '\0';
+
+        /* Increment # of unique items. */
+        U->cur_unique_items++;
   }
 
+    /* Increment total # of items. */
   U->items++;
+
+    /* Increment # items matching this md5 digest (probably just this 1). */
+    m->count++;
+
+    /* Pass back the ascii hash, if requested. */
   if(rhash) *rhash = m->name;
-  return m->count++;
+
+    /* Pass back the count, if requested. */
+    if (count) *count = m->count;
+
+    status = CL_SUCCESS;
+
+done:
+    return status;
 }
 
-uint32_t uniq_get(struct uniq *U, const char *key, uint32_t key_len, char **rhash) {
+cl_error_t uniq_get(struct uniq *U, const char *item, uint32_t item_len, char **rhash, uint32_t *count)
+{
+  cl_error_t status = CL_EARG;
   uint8_t digest[16];
   struct UNIQMD5 *m = NULL;
+    uint32_t idx      = 0;
 
-  cl_hash_data("md5", key, key_len, digest, NULL);
+    if (!U || !count) {
+        /* Invalid args */
+        goto done;
+    }
 
-  if(!U->items || U->md5s[U->idx[*digest]].md5[0]!=*digest)
-    return 0;
+    *count = 0;
 
-  for(m=&U->md5s[U->idx[*digest]]; m; m=m->next) {
-    if(memcmp(&digest[1], &m->md5[1], 15)) continue;
-    if(rhash) *rhash = m->name;
-    return m->count;
+    if (!U->items) {
+        goto not_found;
+    }
+
+    /* Make a hash of the item string */
+    if (NULL == cl_hash_data("md5", item, item_len, digest, NULL)) {
+        /* Failed to create hash of item. */
+        status = CL_EFORMAT;
+        goto done;
+    }
+
+    /* Get the md5s array index for the bucket list head. */
+    idx = U->idx[*digest];
+    m   = &U->md5s[idx];
+
+    if (m->md5[0] != *digest) {
+        /*
+         * If the first two bytes in the digest doesn't actually match,
+         * then the item has never been added.
+         * This is a common scenario because the idx table is initialized
+         * to 0's.
+         */
+        goto not_found;
+    }
+
+    do {
+        if (0 == memcmp(&digest[1], &m->md5[1], 15)) {
+            /* The item-hash matched.
+             * Pass back the ascii hash value (if requested).
+             * Return the count of matching items (will be 1+).
+             */
+            if (rhash)
+                *rhash = m->name;
+            *count = m->count;
+            break;
   }
+        m = m->next;
+    } while (NULL != m);
+
+not_found:
+    status = CL_SUCCESS;
 
-  return 0;
+done:
+    return status;
 }
diff -Nru clamav-0.101.1+dfsg/libclamav/uniq.h clamav-0.101.2+dfsg/libclamav/uniq.h
--- clamav-0.101.1+dfsg/libclamav/uniq.h	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/uniq.h	2019-03-13 22:13:01.000000000 +0100
@@ -1,11 +1,59 @@
 /*
  *  md5 based hashtab
  *
- *  Copyright (C) 2015 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
- *  Copyright (C) 2008 Sourcefire, Inc.
+ *  Copyright (C) 2013-2019 Cisco Systems, Inc. and/or its affiliates. All rights reserved.
+ *  Copyright (C) 2008-2013 Sourcefire, Inc.
  *
  *  Authors: aCaB <acab at clamav.net>
  *
+ *  Uniq implements a structure that stores the count of duplicate items.
+ *  The count can be retrieved by item name (if you know it).
+ *  Additionally, you can retrieve the ascii md5 hash at the same time.
+ *
+ *  This is essentially a tiny hash table of hashes.
+ *  The hashes are in an array instead of dynamically added.
+ *  This is faster than alloc'ing for each unique item added, *  but means a max # of unique items must be defined at init.
+ *
+ *  Example where:
+ *   items = 6
+ *   max_unique_items = 5
+ *   cur_unique_items = 4
+ *   md5 #1 has been added 3 times
+ *   Two md5's start with the same 2 bytes (#0 and #3)
+ *
+ *    idx:
+ *      -00--01--02--03--04--05--06--07-...
+ *      | 0 | 0 | 0 | 2 | 1 | 0 | 0 | ...
+ *      ------------------------------...
+ *
+ *    md5s:
+ *      ------------------------------
+ *   0  | next:  Address of #3
+ *      | count: 1
+ *      | md5:   0x01,0x98,0x23,0xa8,0xfd,...
+ *      | name:  "019823a8fd..."
+ *      ------------------------------
+ *   1  | next:  NULL
+ *      | count: 3
+ *      | md5:   0x03,0x98,0x23,0xa8,0xfd,...
+ *      | name:  "019823a8fd..."
+ *      ------------------------------
+ *   2  | next:  NULL
+ *      | count: 1
+ *      | md5:   0x01,0x98,0x23,0xa8,0xfd,...
+ *      | name:  "019823a8fd..."
+ *      ------------------------------
+ *   3  | next:  NULL
+ *      | count: 1
+ *      | md5:   0x01,0xdd,0x2f,0x87,0x6a,...
+ *      | name:  "01dd2f876a..."
+ *      ------------------------------
+ *   4  | next:  NULL
+ *      | count: 0
+ *      | md5:   0x00,0x00,0x00,0x00,0x00,...
+ *      | name:  "\0\0\0\0\0..."
+ *      ------------------------------
+ *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License version 2 as
  *  published by the Free Software Foundation.
@@ -24,25 +72,85 @@
 #ifndef _UNIQ_H
 #define _UNIQ_H
 
+#include "clamav.h"
 #include "clamav-types.h"
 
+/**
+ * @brief Store the count of each unique item.
+ *
+ * These elements are allocated as an array in struct uniq, but they are also
+ * linked together using the `next` pointers to form impromptu buckets,
+ * categorized using the first two bytes of each md5.
+ */
 struct UNIQMD5 {
-  struct UNIQMD5 *next;
-  uint32_t count;
-  uint8_t md5[16];
-  char name[33];
+    struct UNIQMD5 *next; /**< Pointer to next UNIQMD5 where the first two bytes are the same. */
+    uint32_t count;       /**< Number of times this item has been added. (# duplicates). */
+    uint8_t md5[16];      /**< Binary md5 hash of the item. */
+    char name[33];        /**< Ascii md5 hash of the item. */
 };
 
+/**
+ * @brief The main Uniq store structure.
+ *
+ * Includes array of uniq md5 hashes, and an index table to optimize searches
+ * into the hash array, categorized by the first two bytes of the md5.
+ */
 struct uniq {
-  struct UNIQMD5 *md5s;
-  uint32_t items;
-  uint32_t idx[256];
+    struct UNIQMD5 *md5s;      /**< Array of UNIQMD5 structs. */
+    uint32_t items;            /**< Total # of items added (including duplicates) */
+    uint32_t cur_unique_items; /**< The # of md5s currently stored in the array. */
+    uint32_t max_unique_items; /**< The # of md5s that can be stored the array. */
+    uint32_t idx[256];         /**< Array of indices into the md5s array.
+                                    Each index represents a linked-list of md5s
+                                    sharing the common trait that the first two
+                                    bytes are the same. */
 };
 
+/**
+ * @brief Initialize a Uniq store to count the number of uniq string items.
+ *
+ * The Uniq store must be free'd with uniq_free().
+ * uniq_add()'s will fail if they exceed the number of unique strings initialized with count.
+ *
+ * @param count         The max number of unique string items that may be added.
+ * @return struct uniq* A pointer to the Uniq store object. Will return NULL on failure.
+ */
 struct uniq *uniq_init(uint32_t);
+
+/**
+ * @brief Free the Uniq store and associated memory.
+ */
 void uniq_free(struct uniq *);
-uint32_t uniq_add(struct uniq *, const char *, uint32_t, char **);
-uint32_t uniq_get(struct uniq *, const char *, uint32_t, char **);
+
+/**
+ * @brief Add to the uniq (item md5) count.
+ *
+ * Adds an item to the list of known items.
+ * Increments the count if the item has been seen before.
+ * The optional rhash pointer will be valid until `uniq_free()` is called.
+ *
+ * @param U             The Uniq count store.
+ * @param item          (optional) The item to hash and count.
+ * @param item_len      The length, in bytes, of the item. May be 0.
+ * @param[out] rhash    (optional) A pointer to the item's md5 hash (in ascii).
+ * @param[out] count    (optional) The number of times this unique item has been added.
+ * @return cl_error_t   CL_SUCCESS if successful, else an error code.
+ */
+cl_error_t uniq_add(struct uniq *U, const char *item, uint32_t, char **rhash, uint32_t *count);
+
+/**
+ * @brief Retrieve the number of times an item has been added to the Uniq count store.
+ *
+ * The optional rhash pointer will be valid until `uniq_free()` is called.
+ *
+ * @param U             The Uniq count store.
+ * @param item          (optional) The item to hash and count.
+ * @param item_len      The length, in bytes, of the item. May be 0.
+ * @param[out] rhash    (optional) A pointer to the item's md5 hash (in ascii).
+ * @param[out] count    The number of times this unique item has been added.
+ * @return cl_error_t   CL_SUCCESS if successful, else an error code.
+ */
+cl_error_t uniq_get(struct uniq *U, const char *item, uint32_t, char **rhash, uint32_t *count);
 
 
 #endif
diff -Nru clamav-0.101.1+dfsg/libclamav/upx.c clamav-0.101.2+dfsg/libclamav/upx.c
--- clamav-0.101.1+dfsg/libclamav/upx.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/upx.c	2019-03-13 22:13:01.000000000 +0100
@@ -311,12 +311,14 @@
 
     if ( oob == -1 )
       return -1;
-    
+
     backbytes = 1;
 
     while (1) {
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
+      if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+        return -1;
       backbytes = backbytes*2+oob;
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
 	return -1;
@@ -325,11 +327,13 @@
     }
 
     backbytes-=3;
-  
+
     if ( backbytes >= 0 ) {
 
       if (scur>=ssize)
 	return -1;
+            if (backbytes & 0xff000000)
+                return -1;
       backbytes<<=8;
       backbytes+=(unsigned char)(src[scur++]);
       backbytes^=0xffffffff;
@@ -343,16 +347,22 @@
       return -1;
     if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
       return -1;
+        if (backsize + oob > UINT32_MAX / 2)
+            return -1;
     backsize = backsize*2 + oob;
     if (!backsize) {
       backsize++;
       do {
         if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
           return -1;
+                if (backsize + oob > UINT32_MAX / 2)
+                    return -1;
 	backsize = backsize*2 + oob;
       } while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
       if ( oob == -1 )
         return -1;
+            if (backsize + 2 > UINT32_MAX)
+                return -1;
       backsize+=2;
     }
 
@@ -392,6 +402,8 @@
     while (1) {
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
+      if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+        return -1;
       backbytes = backbytes*2+oob;
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
@@ -400,16 +412,20 @@
       backbytes--;
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
+      if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+        return -1;
       backbytes=backbytes*2+oob;
     }
 
     backsize = 0;
     backbytes-=3;
-  
+
     if ( backbytes >= 0 ) {
 
       if (scur>=ssize)
 	return -1;
+            if (backbytes & 0xff000000)
+                return -1;
       backbytes<<=8;
       backbytes+=(unsigned char)(src[scur++]);
       backbytes^=0xffffffff;
@@ -423,23 +439,29 @@
       if ( (backsize = (uint32_t)doubleebx(src, &myebx, &scur, ssize)) == 0xffffffff )
         return -1;
     }
- 
+
     if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
       return -1;
+        if (backsize + oob > UINT32_MAX / 2)
+            return -1;
     backsize = backsize*2 + oob;
     if (!backsize) {
       backsize++;
       do {
         if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
           return -1;
+                if (backsize + oob > UINT32_MAX / 2)
+                    return -1;
 	backsize = backsize*2 + oob;
       } while ( (oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
       if ( oob == -1 )
         return -1;
+            if (backsize + 2 > UINT32_MAX)
+                return -1;
       backsize+=2;
     }
 
-    if ( (uint32_t)unp_offset < 0xfffffb00 ) 
+    if ( (uint32_t)unp_offset < 0xfffffb00 )
       backsize++;
 
     backsize++;
@@ -473,6 +495,8 @@
     for(;;) {
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
+      if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+        return -1;
       backbytes = backbytes*2+oob;
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
@@ -481,15 +505,19 @@
       backbytes--;
       if ( (oob = doubleebx(src, &myebx, &scur, ssize)) == -1 )
         return -1;
+      if (((int64_t) backbytes + oob ) > INT32_MAX / 2)
+        return -1;
       backbytes=backbytes*2+oob;
     }
 
     backbytes-=3;
-  
+
     if ( backbytes >= 0 ) {
 
       if (scur>=ssize)
 	return -1;
+            if (backbytes & 0xff000000)
+                return -1;
       backbytes<<=8;
       backbytes+=(unsigned char)(src[scur++]);
       backbytes^=0xffffffff;
@@ -514,22 +542,30 @@
       if (oob) {
 	if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
 	  return -1;
+                if (backsize + oob > UINT32_MAX / 2)
+                    return -1;
 	  backsize = 2 + oob;
 	} else {
 	  do {
 	    if ((oob = doubleebx(src, &myebx, &scur, ssize)) == -1)
 	      return -1;
+                    if (backsize + oob > UINT32_MAX / 2)
+                        return -1;
 	    backsize = backsize * 2 + oob;
 	  } while ((oob = doubleebx(src, &myebx, &scur, ssize)) == 0);
 	  if (oob == -1)
 	    return -1;
+                if (backsize + 2 > UINT32_MAX)
+                    return -1;
 	  backsize+=2;
 	}
     }
- 
-    if ( (uint32_t)unp_offset < 0xfffffb00 ) 
+
+    if ( (uint32_t)unp_offset < 0xfffffb00 )
       backsize++;
 
+        if (backsize + 2 > UINT32_MAX)
+            return -1;
     backsize+=2;
 
     if (!CLI_ISCONTAINED(dst, *dsize, dst+dcur+unp_offset, backsize) || !CLI_ISCONTAINED(dst, *dsize, dst+dcur, backsize) || unp_offset >=0 )
@@ -551,7 +587,7 @@
   cli_writeint32(fake_lzmahdr + 1, *dsize);
   uint8_t lc = properties & 0xff;
   uint8_t lp = (properties >> 8) & 0xff;
-  uint8_t pb = (properties >> 16) & 0xff; 
+  uint8_t pb = (properties >> 16) & 0xff;
   if (lc >= 9 || lp >= 5 || pb >= 5)
       return -1;
 
diff -Nru clamav-0.101.1+dfsg/libclamav/vba_extract.c clamav-0.101.2+dfsg/libclamav/vba_extract.c
--- clamav-0.101.1+dfsg/libclamav/vba_extract.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/vba_extract.c	2019-03-13 22:13:01.000000000 +0100
@@ -294,6 +294,7 @@
 	struct vba56_header v56h;
 	off_t seekback;
 	char fullname[1024], *hash;
+    uint32_t hashcnt = 0;
 
 	cli_dbgmsg("in cli_vba_readdir()\n");
 
@@ -304,8 +305,13 @@
 	 * _VBA_PROJECT files are embedded within office documents (OLE2)
 	 */
 	
-	if (!uniq_get(U, "_vba_project", 12, &hash))
+    if (CL_SUCCESS != uniq_get(U, "_vba_project", 12, &hash, &hashcnt)) {
+        cli_dbgmsg("vba_readdir: uniq_get('_vba_project') failed. Unable to check # of embedded vba proj files\n");
 		return NULL;
+    }
+    if (hashcnt == 0) {
+        return NULL;
+    }
 	snprintf(fullname, sizeof(fullname), "%s"PATHSEP"%s_%u", dir, hash, which);
 	fullname[sizeof(fullname)-1] = '\0';
 	fd = open(fullname, O_RDONLY|O_BINARY);
@@ -448,7 +454,13 @@
 		}
 		ptr = get_unicode_name((const char *)buf, length, big_endian);
 		if(ptr == NULL) break;
-		if (!(vba_project->colls[i]=uniq_get(U, ptr, strlen(ptr), &hash))) {
+        if (CL_SUCCESS != uniq_get(U, ptr, strlen(ptr), &hash, &hashcnt)) {
+            cli_dbgmsg("vba_readdir: uniq_get('%s') failed.\n", ptr);
+            free(ptr);
+            break;
+        }
+        vba_project->colls[i] = hashcnt;
+        if (0 == vba_project->colls[i]) {
 			cli_dbgmsg("vba_readdir: cannot find project %s (%s)\n", ptr, hash);
 			free(ptr);
 			break;
@@ -1308,7 +1320,7 @@
 {
 	vba_project_t *ret;
 
-	ret = (vba_project_t *) cli_malloc(sizeof(struct vba_project_tag));
+    ret = (vba_project_t *)cli_calloc(1, sizeof(struct vba_project_tag));
 
 	if(ret == NULL) {
         cli_errmsg("create_vba_project: Unable to allocate memory for vba project structure\n");
@@ -1320,16 +1332,8 @@
 	ret->dir = cli_strdup(dir);
 	ret->offset = (uint32_t *)cli_malloc (sizeof(uint32_t) * record_count);
 
-	if((ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) {
-		if(ret->dir)
-			free(ret->dir);
-		if(ret->colls)
-			free(ret->colls);
-		if(ret->name)
-			free(ret->name);
-		if(ret->offset)
-			free(ret->offset);
-		free(ret);
+    if ((ret->colls == NULL) || (ret->name == NULL) || (ret->dir == NULL) || (ret->offset == NULL)) {
+        cli_free_vba_project(ret);
         cli_errmsg("create_vba_project: Unable to allocate memory for vba project elements\n");
 		return NULL;
 	}
@@ -1338,3 +1342,32 @@
 
 	return ret;
 }
+
+/**
+ * @brief Free up the memory associated with the vba_project_t type.
+ *
+ * @param project A vba_project_t type allocated by one of these:
+ *  - create_vba_project()
+ *  - cli_wm_readdir()
+ *  - cli_vba_readdir()
+ */
+void cli_free_vba_project(vba_project_t *vba_project)
+{
+    if (vba_project) {
+        if (vba_project->dir)
+            free(vba_project->dir);
+        if (vba_project->colls)
+            free(vba_project->colls);
+        if (vba_project->name)
+            free(vba_project->name);
+        if (vba_project->offset)
+            free(vba_project->offset);
+        if (vba_project->length)
+            free(vba_project->length);
+        if (vba_project->key)
+            free(vba_project->key);
+        free(vba_project);
+    }
+
+    return;
+}
\ No newline at end of file
diff -Nru clamav-0.101.1+dfsg/libclamav/vba_extract.h clamav-0.101.2+dfsg/libclamav/vba_extract.h
--- clamav-0.101.1+dfsg/libclamav/vba_extract.h	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/vba_extract.h	2019-03-13 22:13:01.000000000 +0100
@@ -41,6 +41,8 @@
 
 vba_project_t	*cli_vba_readdir(const char *dir, struct uniq *U, uint32_t which);
 vba_project_t	*cli_wm_readdir(int fd);
+void 			cli_free_vba_project(vba_project_t *vba_project);
+
 unsigned char	*cli_vba_inflate(int fd, off_t offset, int *size);
 int	cli_scan_ole10(int fd, cli_ctx *ctx);
 char	*cli_ppt_vba_read(int fd, cli_ctx *ctx);
diff -Nru clamav-0.101.1+dfsg/libclamav/version.h clamav-0.101.2+dfsg/libclamav/version.h
--- clamav-0.101.1+dfsg/libclamav/version.h	2018-12-19 21:48:59.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/version.h	2019-03-13 22:13:33.000000000 +0100
@@ -1 +1 @@
-#define REPO_VERSION "devel-clamav-0.101.0-rc-10-g5ee212a7b"
+#define REPO_VERSION "devel-clamav-0.101.1-30-g5e0e479ad"
diff -Nru clamav-0.101.1+dfsg/libclamav/xz_iface.c clamav-0.101.2+dfsg/libclamav/xz_iface.c
--- clamav-0.101.1+dfsg/libclamav/xz_iface.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamav/xz_iface.c	2019-03-13 22:13:01.000000000 +0100
@@ -57,6 +57,8 @@
 }
 	
 void cli_XzShutdown(struct CLI_XZ *XZ) {
+    if (!XZ)
+        return;
     XzUnpacker_Free(&XZ->state);
 }
 
diff -Nru clamav-0.101.1+dfsg/libclamunrar_iface/unrar_iface.cpp clamav-0.101.2+dfsg/libclamunrar_iface/unrar_iface.cpp
--- clamav-0.101.1+dfsg/libclamunrar_iface/unrar_iface.cpp	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamunrar_iface/unrar_iface.cpp	2019-03-13 22:13:01.000000000 +0100
@@ -133,6 +135,7 @@
     }
     case ERAR_EOPEN: {
         unrar_dbgmsg("unrar_retcode: Volume open error.\n");
+        status = UNRAR_EOPEN;
         break;
     }
     case ERAR_ECREATE: {
diff -Nru clamav-0.101.1+dfsg/libclamunrar_iface/unrar_iface.h clamav-0.101.2+dfsg/libclamunrar_iface/unrar_iface.h
--- clamav-0.101.1+dfsg/libclamunrar_iface/unrar_iface.h	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/libclamunrar_iface/unrar_iface.h	2019-03-13 22:13:01.000000000 +0100
@@ -48,7 +50,8 @@
     UNRAR_BREAK,
     UNRAR_ENCRYPTED,
     UNRAR_EMEM,
-    UNRAR_ERR
+    UNRAR_ERR,
+    UNRAR_EOPEN
 } cl_unrar_error_t;
 
 typedef struct unrar_metadata_tag
diff -Nru clamav-0.101.1+dfsg/m4/reorganization/code_checks/fuzz.m4 clamav-0.101.2+dfsg/m4/reorganization/code_checks/fuzz.m4
--- clamav-0.101.1+dfsg/m4/reorganization/code_checks/fuzz.m4	1970-01-01 01:00:00.000000000 +0100
+++ clamav-0.101.2+dfsg/m4/reorganization/code_checks/fuzz.m4	2019-03-13 22:13:01.000000000 +0100
@@ -0,0 +1,11 @@
+AC_ARG_ENABLE(fuzz,
+	      AC_HELP_STRING([--enable-fuzz],
+			     [enable building standalone fuzz targets
+			      @<:@default=no@:>@]),
+[enable_cov=$enableval],[enable_cov="no"])
+
+if test "x$enable_fuzz" = "xyes"; then
+    CXXFLAGS="-std=c++11 -stdlib=libc++ $CXXFLAGS"
+fi
+
+AM_CONDITIONAL(ENABLE_FUZZ, test "x$enable_fuzz" = "xyes")
diff -Nru clamav-0.101.1+dfsg/m4/reorganization/version.m4 clamav-0.101.2+dfsg/m4/reorganization/version.m4
--- clamav-0.101.1+dfsg/m4/reorganization/version.m4	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/m4/reorganization/version.m4	2019-03-13 22:13:01.000000000 +0100
@@ -1,9 +1,9 @@
 dnl change this on a release
 dnl VERSION="devel-`date +%Y%m%d`"
-VERSION="0.101.1"
+VERSION="0.101.2"
 
 LC_CURRENT=9
-LC_REVISION=1
+LC_REVISION=2
 LC_AGE=0
 LIBCLAMAV_VERSION="$LC_CURRENT":"$LC_REVISION":"$LC_AGE"
 AC_SUBST([LIBCLAMAV_VERSION])
diff -Nru clamav-0.101.1+dfsg/Makefile.am clamav-0.101.2+dfsg/Makefile.am
--- clamav-0.101.1+dfsg/Makefile.am	2019-01-07 22:16:54.000000000 +0100
+++ clamav-0.101.2+dfsg/Makefile.am	2019-03-30 14:57:20.000000000 +0100
@@ -31,6 +33,10 @@
 SUBDIRS += libfreshclam
 endif
 
+if ENABLE_FUZZ
+SUBDIRS += fuzz
+endif
+
 pkgconfigdir = $(libdir)/pkgconfig
 pkgconfig_DATA = libclamav.pc
 
@@ -39,11 +45,15 @@
 # don't complain that configuration files and databases are not removed, this is intended
 distuninstallcheck_listfiles = find . -type f ! -name clamd.conf ! -name freshclam.conf ! -name daily.cvd ! -name main.cvd -print
 DISTCLEANFILES = target.h
-DISTCHECK_CONFIGURE_FLAGS=--enable-milter --disable-clamav --enable-all-jit-targets --enable-llvm=yes --with-system-llvm=no --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir)
+DISTCHECK_CONFIGURE_FLAGS=--enable-milter --disable-clamav --enable-all-jit-targets --enable-llvm=yes --with-system-llvm=no --with-systemdsystemunitdir=$$dc_install_base/$(systemdsystemunitdir) CC="$(CC)" CXX="$(CXX)" YACC="$(YACC)" LEX="$(LEX)" AR="$(AR)" AS="$(AS)"
 lcov:
 	($(MAKE); cd unit_tests; $(MAKE) lcov)
 quick-check:
 	($(MAKE); cd unit_tests; $(MAKE) quick-check)
+fuzz-all:
+	($(MAKE); cd fuzz; $(MAKE) all)
+fuzz-check:
+	($(MAKE); cd fuzz; $(MAKE) check)
 
 dist-hook:
 	rm -rf $(distdir)/win32/clamav-for-windows $(distdir)/win32/build
diff -Nru clamav-0.101.1+dfsg/NEWS.md clamav-0.101.2+dfsg/NEWS.md
--- clamav-0.101.1+dfsg/NEWS.md	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/NEWS.md	2019-03-13 22:13:01.000000000 +0100
@@ -3,6 +3,77 @@
 Note: This file refers to the source tarball. Things described here may differ
  slightly from the binary packages.
 
+## 0.101.2
+
+ClamAV 0.101.2 is a patch release to address a handful of security related bugs.
+
+This patch release is being released alongside the 0.100.3 patch so that users
+who are unable to upgrade to 0.101 due to libclamav API changes are protected.
+
+This release includes 3 extra security related bug fixes that do not apply to
+prior versions.  In addition, it includes a number of minor bug fixes and
+improvements.
+
+- Fixes for the following vulnerabilities affecting 0.101.1 and prior:
+  - [CVE-2019-1787](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1787):
+    An out-of-bounds heap read condition may occur when scanning PDF
+    documents. The defect is a failure to correctly keep track of the number
+    of bytes remaining in a buffer when indexing file data.
+  - [CVE-2019-1789](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1789):
+    An out-of-bounds heap read condition may occur when scanning PE files
+    (i.e. Windows EXE and DLL files) that have been packed using Aspack as a
+    result of inadequate bound-checking.
+  - [CVE-2019-1788](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1788):
+    An out-of-bounds heap write condition may occur when scanning OLE2 files
+    such as Microsoft Office 97-2003 documents. The invalid write happens when
+    an invalid pointer is mistakenly used to initialize a 32bit integer to
+    zero. This is likely to crash the application.
+
+- Fixes for the following vulnerabilities affecting 0.101.1 and 0.101.0 only:
+  - [CVE-2019-1786](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1786):
+    An out-of-bounds heap read condition may occur when scanning malformed PDF
+    documents as a result of improper bounds-checking.
+  - [CVE-2019-1785](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1785):
+    A path-traversal write condition may occur as a result of improper input
+    validation when scanning RAR archives. Issue reported by aCaB.
+  - [CVE-2019-1798](https://cve.mitre.org/cgi-bin/cvename.cgi?name=CVE-2019-1798):
+    A use-after-free condition may occur as a result of improper error
+    handling when scanning nested RAR archives. Issue reported by David L.
+
+- Fixes for the following assorted bugs:
+  - Added checks to prevent shifts from causing undefined behavior in HTML
+    normalizer, UPX unpacker, ARJ extractor, CPIO extractor, OLE2 parser,
+    LZW decompressor used in the PDF parser, Xz decompressor, and UTF-16 to
+    ASCII transcoder.
+  - Added checks to prevent integer overflow in UPX unpacker.
+  - Fix for minor memory leak in OLE2 parser.
+  - Fix to speed up PDF parser when handling truncated (or malformed) PDFs.
+  - Fix for memory leak in ARJ decoder failure condition.
+  - Fix for potential memory and file descriptor leak in HTML normalization code.
+
+- Removed use of problematic feature that converted file descriptors to
+  file paths. The feature was intended to improve performance when scanning
+  file types, notably RAR archives, for which the API requires a file path.
+  This feature caused issues in environments where the ClamAV engine is run
+  in a low-permissions or sandboxed process. RAR archives are still supported
+  with this change, but performance may suffer slightly if the file path is not
+  provided in calls to `cl_scandesc_callback()`.
+  - Added filename and tempfile names to scandesc calls in clamd.
+  - Added general scan option `CL_SCAN_GENERAL_UNPRIVILEGED` to treat the scan
+    engine as unprivileged, meaning that the scan engine will not have read
+    access to the file. Provided file paths are for logging purposes only.
+  - Added ability to create a temp file when scanning RAR archives when the
+    process does not have read access to the file path provided (i.e.
+    unprivileged is set, or an access check fails).
+
+Thank you to the Google OSS-Fuzz project for identifying and reporting many of
+the bugs patched in this release.
+
+Additional thanks to the following community members for submitting bug reports:
+
+- aCaB
+- David L.
+
 ## 0.101.1
 
 ClamAV 0.101.1 is an urgent patch release to address an issue in 0.101.0
@@ -99,18 +170,18 @@
     |                                  | `AlertEncryptedArchive`      |
     |                                  | `AlertEncryptedDoc`          |
 
-    | Old `clamscan` option        | *New* `clamscan` option          |
-    | ---------------------------- | -------------------------------- |
-    | `--algorithmic-detection`    | `--heuristic-alerts`             |
-    | `--detect-broken`            | `--alert-broken`                 |
-    | `--phishing-cloak`           | `--alert-phishing-cloak`         |
-    | `--phishing-ssl`             | `--alert-phishing-ssl`           |
-    | `--partition-intersection`   | `--alert-partition-intersection` |
-    | `--block-max`                | `--alert-exceeds-max`            |
-    | `--block-macros`             | `--alert-macros`                 |
-    | `--block-encrypted`          | `--alert-encrypted`              |
-    |                              | `--alert-encrypted-archive`      |
-    |                              | `--alert-encrypted-doc`          |
+    | Old `clamscan` option      | *New* `clamscan` option          |
+    | -------------------------- | -------------------------------- |
+    | `--algorithmic-detection`  | `--heuristic-alerts`             |
+    | `--detect-broken`          | `--alert-broken`                 |
+    | `--phishing-cloak`         | `--alert-phishing-cloak`         |
+    | `--phishing-ssl`           | `--alert-phishing-ssl`           |
+    | `--partition-intersection` | `--alert-partition-intersection` |
+    | `--block-max`              | `--alert-exceeds-max`            |
+    | `--block-macros`           | `--alert-macros`                 |
+    | `--block-encrypted`        | `--alert-encrypted`              |
+    |                            | `--alert-encrypted-archive`      |
+    |                            | `--alert-encrypted-doc`          |
 
 ### Some more subtle improvements
 
diff -Nru clamav-0.101.1+dfsg/sigtool/vba.c clamav-0.101.2+dfsg/sigtool/vba.c
--- clamav-0.101.1+dfsg/sigtool/vba.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/sigtool/vba.c	2019-03-13 22:13:01.000000000 +0100
@@ -1107,8 +1107,10 @@
 
 int sigtool_vba_scandir (const char *dirname, int hex_output, struct uniq *U)
 {
-    int ret = CL_CLEAN, i, fd, data_len;
-    vba_project_t *vba_project;
+    cl_error_t status = CL_CLEAN;
+    cl_error_t ret;
+    int i, fd, data_len;
+    vba_project_t *vba_project = NULL;
     DIR *dd;
     struct dirent *dent;
     STATBUF statbuf;
@@ -1117,14 +1119,22 @@
     uint32_t hashcnt;
     unsigned int j;
 
-    hashcnt = uniq_get(U, "_vba_project", 12, NULL);
-    while(hashcnt--) {
-	if(!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) continue;
+    if (CL_SUCCESS != (ret = uniq_get(U, "_vba_project", 12, NULL, &hashcnt))) {
+        logg("!ScanDir -> uniq_get('_vba_project') failed.\n");
+        return ret;
+    }
+
+    while (hashcnt) {
+        if (!(vba_project = (vba_project_t *)cli_vba_readdir(dirname, U, hashcnt))) {
+            hashcnt--;
+            continue;
+        }
 
 	for(i = 0; i < vba_project->count; i++) {
 	    for(j = 0; j < vba_project->colls[i]; j++) {
 		snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", vba_project->dir, vba_project->name[i], j);
 		vbaname[sizeof(vbaname)-1] = '\0';
+
 		fd = open(vbaname, O_RDONLY|O_BINARY);
 		if(fd == -1) continue;
 		data = (unsigned char *)cli_vba_inflate(fd, vba_project->offset[i], &data_len);
@@ -1139,39 +1149,53 @@
 	    }
 	}
 
-	free(vba_project->name);
-	free(vba_project->colls);
-	free(vba_project->dir);
-	free(vba_project->offset);
-	free(vba_project);
+        cli_free_vba_project(vba_project);
+        vba_project = NULL;
+
+        hashcnt--;
     }
 
+    if (CL_SUCCESS != (ret = uniq_get(U, "powerpoint document", 19, &hash, &hashcnt))) {
+        logg("!ScanDir -> uniq_get('powerpoint document') failed.\n");
+        return ret;
+    }
 
-    if((hashcnt = uniq_get(U, "powerpoint document", 19, &hash))) {
-	while(hashcnt--) {
+    while (hashcnt) {
 	    snprintf(vbaname, 1024, "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
 	    vbaname[sizeof(vbaname)-1] = '\0';
+
 	    fd = open(vbaname, O_RDONLY|O_BINARY);
-	    if (fd == -1) continue;
+        if (fd == -1) {
+            hashcnt--;
+            continue;
+        }
 	    if ((fullname = cli_ppt_vba_read(fd, NULL))) {
 	      sigtool_scandir(fullname, hex_output);
 	      cli_rmdirs(fullname);
 	      free(fullname);
 	    }
 	    close(fd);
+        hashcnt--;
 	}
-    }
 
+    if (CL_SUCCESS != (ret = uniq_get(U, "worddocument", 12, &hash, &hashcnt))) {
+        logg("!ScanDir -> uniq_get('worddocument') failed.\n");
+        return ret;
+    }
 
-    if ((hashcnt = uniq_get(U, "worddocument", 12, &hash))) {
-	while(hashcnt--) {
+    while (hashcnt) {
 	    snprintf(vbaname, sizeof(vbaname), "%s"PATHSEP"%s_%u", dirname, hash, hashcnt);
 	    vbaname[sizeof(vbaname)-1] = '\0';
+
 	    fd = open(vbaname, O_RDONLY|O_BINARY);
-	    if (fd == -1) continue;
+        if (fd == -1) {
+            hashcnt--;
+            continue;
+        }
 	    
 	    if (!(vba_project = (vba_project_t *)cli_wm_readdir(fd))) {
 		close(fd);
+            hashcnt--;
 		continue;
 	    }
 
@@ -1187,14 +1211,9 @@
 	    }
 
 	    close(fd);
-	    free(vba_project->name);
-	    free(vba_project->colls);
-	    free(vba_project->dir);
-	    free(vba_project->offset);
-	    free(vba_project->key);
-	    free(vba_project->length);
-	    free(vba_project);
-	}
+        cli_free_vba_project(vba_project);
+        vba_project = NULL;
+        hashcnt--;
     }
 
     if ((dd = opendir (dirname)) != NULL) {
@@ -1221,5 +1240,5 @@
 
 
     closedir (dd);
-    return ret;
+    return status;
 }
diff -Nru clamav-0.101.1+dfsg/unit_tests/check_clamav.c clamav-0.101.2+dfsg/unit_tests/check_clamav.c
--- clamav-0.101.1+dfsg/unit_tests/check_clamav.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/unit_tests/check_clamav.c	2019-03-13 22:13:01.000000000 +0100
@@ -23,15 +23,16 @@
 #include "../libclamav/version.h"
 #include "../libclamav/dsig.h"
 #include "../libclamav/fpu.h"
+#include "../platform.h"
 #include "checks.h"
 
-static int fpu_words  = FPU_ENDIAN_INITME;
+static int fpu_words = FPU_ENDIAN_INITME;
 #define NO_FPU_ENDIAN (fpu_words == FPU_ENDIAN_UNKNOWN)
 #define EA06_SCAN strstr(file, "clam.ea06.exe")
 #define FALSE_NEGATIVE (EA06_SCAN && NO_FPU_ENDIAN)
 
 /* extern void cl_free(struct cl_engine *engine); */
-START_TEST (test_cl_free)
+START_TEST(test_cl_free)
 /*
     struct cl_engine *engine = NULL;
     cl_free(NULL);
@@ -39,16 +40,16 @@
 END_TEST
 
 /* extern struct cl_engine *cl_dup(struct cl_engine *engine); */
-START_TEST (test_cl_dup)
-    /*
+START_TEST(test_cl_dup)
+/*
     struct cl_engine *engine;
     fail_unless(NULL == cl_dup(NULL), "cl_dup null pointer");
     */
 END_TEST
 
 /* extern int cl_build(struct cl_engine *engine); */
-START_TEST (test_cl_build)
-    /*
+START_TEST(test_cl_build)
+/*
     struct cl_engine *engine;
     fail_unless(CL_ENULLARG == cl_build(NULL), "cl_build null pointer");
     engine = calloc(sizeof(struct cl_engine),1);
@@ -59,7 +60,7 @@
 END_TEST
 
 /* extern void cl_debug(void); */
-START_TEST (test_cl_debug)
+START_TEST(test_cl_debug)
 {
     int old_status = cli_debug_flag;
     cli_debug_flag = 0;
@@ -74,8 +75,8 @@
 END_TEST
 
 /* extern const char *cl_retdbdir(void); */
-START_TEST (test_cl_retdbdir)
-    fail_unless(!strcmp(DATADIR, cl_retdbdir()), "cl_retdbdir");
+START_TEST(test_cl_retdbdir)
+fail_unless(!strcmp(DATADIR, cl_retdbdir()), "cl_retdbdir");
 END_TEST
 
 #ifndef REPO_VERSION
@@ -83,17 +84,17 @@
 #endif
 
 /* extern const char *cl_retver(void); */
-START_TEST (test_cl_retver)
+START_TEST(test_cl_retver)
 {
-    const char *ver = cl_retver();
-    fail_unless(!strcmp(REPO_VERSION""VERSION_SUFFIX, ver),"cl_retver");
-    fail_unless(strcspn(ver,"012345789") < strlen(ver),
-		    "cl_retver must have a number");
+    const char* ver = cl_retver();
+    fail_unless(!strcmp(REPO_VERSION "" VERSION_SUFFIX, ver), "cl_retver");
+    fail_unless(strcspn(ver, "012345789") < strlen(ver),
+                "cl_retver must have a number");
 }
 END_TEST
 
 /* extern void cl_cvdfree(struct cl_cvd *cvd); */
-START_TEST (test_cl_cvdfree)
+START_TEST(test_cl_cvdfree)
 /*
     struct cl_cvd *cvd1, *cvd2;
 
@@ -117,15 +118,15 @@
 END_TEST
 
 /* extern int cl_statfree(struct cl_stat *dbstat); */
-START_TEST (test_cl_statfree)
+START_TEST(test_cl_statfree)
 /*
     struct cl_stat *stat;
     fail_unless(CL_ENULLARG == cl_statfree(NULL), "cl_statfree(NULL)");
-    
+
     stat = malloc(sizeof(struct cl_stat));
     fail_unless(NULL != stat, "malloc");
     fail_unless(CL_SUCCESS == cl_statfree(stat), "cl_statfree(empty_struct)");
-    
+
     stat = malloc(sizeof(struct cl_stat));
     fail_unless(NULL != stat, "malloc");
     stat->stattab = strdup("test");
@@ -140,30 +141,30 @@
 END_TEST
 
 /* extern unsigned int cl_retflevel(void); */
-START_TEST (test_cl_retflevel)
-END_TEST    
+START_TEST(test_cl_retflevel)
+END_TEST
 
 /* extern struct cl_cvd *cl_cvdhead(const char *file); */
-START_TEST (test_cl_cvdhead)
+START_TEST(test_cl_cvdhead)
 /*
     fail_unless(NULL == cl_cvdhead(NULL), "cl_cvdhead(null)");
     fail_unless(NULL == cl_cvdhead("input/cl_cvdhead/1.txt"), "cl_cvdhead(515 byte file, all nulls)");
 */
-    /* the data read from the file is passed to cl_cvdparse, test cases for that are separate */
+/* the data read from the file is passed to cl_cvdparse, test cases for that are separate */
 END_TEST
 
 /* extern struct cl_cvd *cl_cvdparse(const char *head); */
-START_TEST (test_cl_cvdparse)
+START_TEST(test_cl_cvdparse)
 END_TEST
 
-static int get_test_file(int i, char *file, unsigned fsize, unsigned long *size);
-static struct cl_engine *g_engine;
+static int get_test_file(int i, char* file, unsigned fsize, unsigned long* size);
+static struct cl_engine* g_engine;
 
 #ifdef CHECK_HAVE_LOOPS
 /* int cl_scandesc(int desc, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, struct cl_scan_options* options) */
-START_TEST (test_cl_scandesc)
+START_TEST(test_cl_scandesc)
 {
-    const char *virname = NULL;
+    const char* virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
@@ -178,17 +179,17 @@
     ret = cl_scandesc(fd, file, &virname, &scanned, g_engine, &options);
     cli_dbgmsg("scan end (scandesc) %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
     close(fd);
 }
 END_TEST
 
-START_TEST (test_cl_scandesc_allscan)
+START_TEST(test_cl_scandesc_allscan)
 {
-    const char *virname = NULL;
+    const char* virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
@@ -205,18 +206,18 @@
 
     cli_dbgmsg("scan end (scandesc) %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc_allscan failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scandesc_allscan failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
     close(fd);
 }
 END_TEST
 
 //* int cl_scanfile(const char *filename, const char **virname, unsigned long int *scanned, const struct cl_engine *engine, const struct cl_limits *limits, unsigned int options) */
-START_TEST (test_cl_scanfile)
+START_TEST(test_cl_scanfile)
 {
-    const char *virname = NULL;
+    const char* virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
@@ -233,16 +234,16 @@
     ret = cl_scanfile(file, &virname, &scanned, g_engine, &options);
     cli_dbgmsg("scan end (scanfile) %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS , "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
 }
 END_TEST
 
-START_TEST (test_cl_scanfile_allscan)
+START_TEST(test_cl_scanfile_allscan)
 {
-    const char *virname = NULL;
+    const char* virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
@@ -260,16 +261,16 @@
     ret = cl_scanfile(file, &virname, &scanned, g_engine, &options);
     cli_dbgmsg("scan end (scanfile_allscan) %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
 }
 END_TEST
 
-START_TEST (test_cl_scanfile_callback)
+START_TEST(test_cl_scanfile_callback)
 {
-    const char *virname = NULL;
+    const char* virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
@@ -287,16 +288,16 @@
     ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, &options, NULL);
     cli_dbgmsg("scan end (scanfile_cb) %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
 }
 END_TEST
 
-START_TEST (test_cl_scanfile_callback_allscan)
+START_TEST(test_cl_scanfile_callback_allscan)
 {
-    const char *virname = NULL;
+    const char* virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
@@ -315,16 +316,16 @@
     ret = cl_scanfile_callback(file, &virname, &scanned, g_engine, &options, NULL);
     cli_dbgmsg("scan end (scanfile_cb_allscan) %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb_allscan failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_cb_allscan failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
 }
 END_TEST
 
-START_TEST (test_cl_scandesc_callback)
+START_TEST(test_cl_scandesc_callback)
 {
-    const char *virname = NULL;
+    const char* virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
@@ -341,17 +342,17 @@
     ret = cl_scandesc_callback(fd, file, &virname, &scanned, g_engine, &options, NULL);
     cli_dbgmsg("scan end (scandesc_cb) %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
     close(fd);
 }
 END_TEST
 
-START_TEST (test_cl_scandesc_callback_allscan)
+START_TEST(test_cl_scandesc_callback_allscan)
 {
-    const char *virname = NULL;
+    const char* virname = NULL;
     char file[256];
     unsigned long size;
     unsigned long int scanned = 0;
@@ -369,9 +370,9 @@
     ret = cl_scandesc_callback(fd, file, &virname, &scanned, g_engine, &options, NULL);
     cli_dbgmsg("scan end (scandesc_cb_allscan) %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanfile_allscan failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
     close(fd);
 }
@@ -380,30 +381,30 @@
 #endif
 
 /* int cl_load(const char *path, struct cl_engine **engine, unsigned int *signo, unsigned int options) */
-START_TEST (test_cl_load)
+START_TEST(test_cl_load)
 END_TEST
 
 /* int cl_cvdverify(const char *file) */
-START_TEST (test_cl_cvdverify)
+START_TEST(test_cl_cvdverify)
 END_TEST
 
 /* int cl_statinidir(const char *dirname, struct cl_stat *dbstat) */
-START_TEST (test_cl_statinidir)
+START_TEST(test_cl_statinidir)
 END_TEST
 
 /* int cl_statchkdir(const struct cl_stat *dbstat) */
-START_TEST (test_cl_statchkdir)
+START_TEST(test_cl_statchkdir)
 END_TEST
 
 /* void cl_settempdir(const char *dir, short leavetemps) */
-START_TEST (test_cl_settempdir)
+START_TEST(test_cl_settempdir)
 END_TEST
 
 /* const char *cl_strerror(int clerror) */
-START_TEST (test_cl_strerror)
+START_TEST(test_cl_strerror)
 END_TEST
 
-static char **testfiles = NULL;
+static char** testfiles     = NULL;
 static unsigned testfiles_n = 0;
 
 static const int expected_testfiles = 48;
@@ -413,8 +414,8 @@
     unsigned skipped = 0;
 
     /* skip .rar files if unrar is disabled */
-    const char *s = getenv("unrar_disabled");
-    if (s && !strcmp(s, "1")) {
+    const char* s = getenv("unrar_disabled");
+    if(s && !strcmp(s, "1")) {
         skipped += 2;
     }
 
@@ -435,26 +436,26 @@
 
 static void init_testfiles(void)
 {
-    struct dirent *dirent;
+    struct dirent* dirent;
     unsigned i = 0;
     int expect = expected_testfiles;
 
-    DIR *d = opendir(OBJDIR"/../test");
+    DIR* d = opendir(OBJDIR "/../test");
     fail_unless(!!d, "opendir");
-    if (!d)
-	return;
-    testfiles = NULL;
+    if(!d)
+        return;
+    testfiles   = NULL;
     testfiles_n = 0;
-    while ((dirent = readdir(d))) {
-	if (strncmp(dirent->d_name, "clam", 4))
-	    continue;
+    while((dirent = readdir(d))) {
+        if(strncmp(dirent->d_name, "clam", 4))
+            continue;
         i++;
-	testfiles = cli_realloc(testfiles, i*sizeof(*testfiles));
-	fail_unless(!!testfiles, "cli_realloc");
-	testfiles[i-1] = strdup(dirent->d_name);
+        testfiles = cli_realloc(testfiles, i * sizeof(*testfiles));
+        fail_unless(!!testfiles, "cli_realloc");
+        testfiles[i - 1] = strdup(dirent->d_name);
     }
     testfiles_n = i;
-    if (get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
+    if(get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
         expect--;
     expect -= skip_files();
     fail_unless_fmt(testfiles_n == expect, "testfiles: %d != %d", testfiles_n, expect);
@@ -465,11 +466,11 @@
 static void free_testfiles(void)
 {
     unsigned i;
-    for (i=0;i<testfiles_n;i++) {
-	free(testfiles[i]);
+    for(i = 0; i < testfiles_n; i++) {
+        free(testfiles[i]);
     }
     free(testfiles);
-    testfiles = NULL;
+    testfiles   = NULL;
     testfiles_n = 0;
 }
 
@@ -478,12 +479,12 @@
 static void engine_setup(void)
 {
     unsigned int sigs = 0;
-    const char *hdb = OBJDIR"/clamav.hdb";
+    const char* hdb   = OBJDIR "/clamav.hdb";
 
     init_testfiles();
-    if (!inited)
-	fail_unless(cl_init(CL_INIT_DEFAULT) == 0, "cl_init");
-    inited = 1;
+    if(!inited)
+        fail_unless(cl_init(CL_INIT_DEFAULT) == 0, "cl_init");
+    inited   = 1;
     g_engine = cl_engine_new();
     fail_unless(!!g_engine, "engine");
     fail_unless_fmt(cl_load(hdb, g_engine, &sigs, CL_DB_STDOPT) == 0, "cl_load %s", hdb);
@@ -497,13 +498,13 @@
     cl_engine_free(g_engine);
 }
 
-static int get_test_file(int i, char *file, unsigned fsize, unsigned long *size)
+static int get_test_file(int i, char* file, unsigned fsize, unsigned long* size)
 {
     int fd;
     STATBUF st;
 
     fail_unless(i < testfiles_n, "%i < %i %s", i, testfiles_n, file);
-    snprintf(file, fsize, OBJDIR"/../test/%s", testfiles[i]);
+    snprintf(file, fsize, OBJDIR "/../test/%s", testfiles[i]);
 
     fd = open(file, O_RDONLY);
     fail_unless(fd > 0, "open");
@@ -513,16 +514,16 @@
 }
 #ifdef CHECK_HAVE_LOOPS
 
-static off_t pread_cb(void *handle, void *buf, size_t count, off_t offset)
+static off_t pread_cb(void* handle, void* buf, size_t count, off_t offset)
 {
     return pread(*((int*)handle), buf, count, offset);
 }
 
-START_TEST (test_cl_scanmap_callback_handle)
+START_TEST(test_cl_scanmap_callback_handle)
 {
-    const char *virname = NULL;
+    const char* virname       = NULL;
     unsigned long int scanned = 0;
-    cl_fmap_t *map;
+    cl_fmap_t* map;
     int ret;
     char file[256];
     unsigned long size;
@@ -540,19 +541,19 @@
     ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
     cli_dbgmsg("scan end (handle) %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
     close(fd);
 }
 END_TEST
 
-START_TEST (test_cl_scanmap_callback_handle_allscan)
+START_TEST(test_cl_scanmap_callback_handle_allscan)
 {
-    const char *virname = NULL;
+    const char* virname       = NULL;
     unsigned long int scanned = 0;
-    cl_fmap_t *map;
+    cl_fmap_t* map;
     int ret;
     char file[256];
     unsigned long size;
@@ -571,21 +572,21 @@
     ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
     cli_dbgmsg("scan end (handle) allscan %s\n", file);
 
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s", virname);
     }
     close(fd);
 }
 END_TEST
 
-START_TEST (test_cl_scanmap_callback_mem)
+START_TEST(test_cl_scanmap_callback_mem)
 {
-    const char *virname = NULL;
+    const char* virname       = NULL;
     unsigned long int scanned = 0;
-    cl_fmap_t *map;
+    cl_fmap_t* map;
     int ret;
-    void *mem;
+    void* mem;
     unsigned long size;
     char file[256];
     struct cl_scan_options options;
@@ -605,9 +606,9 @@
     cli_dbgmsg("scanning (mem) %s\n", file);
     ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
     cli_dbgmsg("scan end (mem) %s\n", file);
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
     }
     close(fd);
     cl_fmap_close(map);
@@ -616,13 +617,13 @@
 }
 END_TEST
 
-START_TEST (test_cl_scanmap_callback_mem_allscan)
+START_TEST(test_cl_scanmap_callback_mem_allscan)
 {
-    const char *virname = NULL;
+    const char* virname       = NULL;
     unsigned long int scanned = 0;
-    cl_fmap_t *map;
+    cl_fmap_t* map;
     int ret;
-    void *mem;
+    void* mem;
     unsigned long size;
     char file[256];
     struct cl_scan_options options;
@@ -643,9 +644,9 @@
     cli_dbgmsg("scanning (mem) allscan %s\n", file);
     ret = cl_scanmap_callback(map, file, &virname, &scanned, g_engine, &options, NULL);
     cli_dbgmsg("scan end (mem) allscan %s\n", file);
-    if (!FALSE_NEGATIVE) {
-      fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
-      fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
+    if(!FALSE_NEGATIVE) {
+        fail_unless_fmt(ret == CL_VIRUS, "cl_scanmap_callback allscan failed for %s: %s", file, cl_strerror(ret));
+        fail_unless_fmt(virname && !strcmp(virname, "ClamAV-Test-File.UNOFFICIAL"), "virusname: %s for %s", virname, file);
     }
     close(fd);
     cl_fmap_close(map);
@@ -654,14 +655,14 @@
 END_TEST
 #endif
 
-static Suite *test_cl_suite(void)
+static Suite* test_cl_suite(void)
 {
-    Suite *s = suite_create("cl_api");
-    TCase *tc_cl = tcase_create("cl_dup");
-    TCase *tc_cl_scan = tcase_create("cl_scan");
-    char *user_timeout = NULL;
-    int expect = expected_testfiles;
-    suite_add_tcase (s, tc_cl);
+    Suite* s           = suite_create("cl_api");
+    TCase* tc_cl       = tcase_create("cl_dup");
+    TCase* tc_cl_scan  = tcase_create("cl_scan");
+    char* user_timeout = NULL;
+    int expect         = expected_testfiles;
+    suite_add_tcase(s, tc_cl);
     tcase_add_test(tc_cl, test_cl_free);
     tcase_add_test(tc_cl, test_cl_dup);
     tcase_add_test(tc_cl, test_cl_build);
@@ -681,9 +682,9 @@
     tcase_add_test(tc_cl, test_cl_strerror);
 
     suite_add_tcase(s, tc_cl_scan);
-    tcase_add_checked_fixture (tc_cl_scan, engine_setup, engine_teardown);
+    tcase_add_checked_fixture(tc_cl_scan, engine_setup, engine_teardown);
 #ifdef CHECK_HAVE_LOOPS
-    if (get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
+    if(get_fpu_endian() == FPU_ENDIAN_UNKNOWN)
         expect--;
     expect -= skip_files();
     tcase_add_loop_test(tc_cl_scan, test_cl_scandesc, 0, expect);
@@ -700,307 +701,402 @@
     tcase_add_loop_test(tc_cl_scan, test_cl_scanmap_callback_mem_allscan, 0, expect);
 
     user_timeout = getenv("T");
-    if (user_timeout) {
+    if(user_timeout) {
         int timeout = atoi(user_timeout);
         tcase_set_timeout(tc_cl_scan, timeout);
-	printf("Using test case timeout of %d seconds set by user\n", timeout);
+        printf("Using test case timeout of %d seconds set by user\n", timeout);
     } else {
-	printf("Using default test timeout; alter by setting 'T' env var (in seconds)\n");
+        printf("Using default test timeout; alter by setting 'T' env var (in seconds)\n");
     }
 #endif
     return s;
 }
 
-static uint8_t le_data[4] = {0x67,0x45,0x23,0x01};
-static int32_t le_expected[4] = { 0x01234567, 0x67012345, 0x45670123, 0x23456701};
-uint8_t *data = NULL;
-uint8_t *data2 = NULL;
+static uint8_t le_data[4]     = {0x67, 0x45, 0x23, 0x01};
+static int32_t le_expected[4] = {0x01234567, 0x67012345, 0x45670123, 0x23456701};
+uint8_t* data                 = NULL;
+uint8_t* data2                = NULL;
 #define DATA_REP 100
 
 static void data_setup(void)
 {
-        uint8_t *p;
-        size_t i;
+    uint8_t* p;
+    size_t i;
 
-	data = malloc(sizeof(le_data)*DATA_REP);
-	data2 = malloc(sizeof(le_data)*DATA_REP);
-	fail_unless(!!data, "unable to allocate memory for fixture");
-        fail_unless(!!data2, "unable to allocate memory for fixture");
-        p = data;
-        /* make multiple copies of le_data, we need to run readint tests in a loop, so we need
+    data  = malloc(sizeof(le_data) * DATA_REP);
+    data2 = malloc(sizeof(le_data) * DATA_REP);
+    fail_unless(!!data, "unable to allocate memory for fixture");
+    fail_unless(!!data2, "unable to allocate memory for fixture");
+    p = data;
+    /* make multiple copies of le_data, we need to run readint tests in a loop, so we need
          * to give it some data to run it on */
-        for(i=0; i<DATA_REP;i++) {
-                memcpy(p, le_data, sizeof(le_data));
-                p += sizeof(le_data);
-        }
-        memset(data2, 0, DATA_REP*sizeof(le_data));
+    for(i = 0; i < DATA_REP; i++) {
+        memcpy(p, le_data, sizeof(le_data));
+        p += sizeof(le_data);
+    }
+    memset(data2, 0, DATA_REP * sizeof(le_data));
 }
 
 static void data_teardown(void)
 {
-        free(data);
-	free(data2);
+    free(data);
+    free(data2);
 }
 
 #ifdef CHECK_HAVE_LOOPS
 /* test reading with different alignments, _i is parameter from tcase_add_loop_test */
-START_TEST (test_cli_readint16)
+START_TEST(test_cli_readint16)
 {
     size_t j;
     int16_t value;
     /* read 2 bytes apart, start is not always aligned*/
-    for(j=_i;j <= DATA_REP*sizeof(le_data)-2;j += 2) {
-        value = le_expected[j&3];
+    for(j = _i; j <= DATA_REP * sizeof(le_data) - 2; j += 2) {
+        value = le_expected[j & 3];
         fail_unless(cli_readint16(&data[j]) == value, "(1) data read must be little endian");
     }
     /* read 2 bytes apart, always aligned*/
-    for(j=0;j <= DATA_REP*sizeof(le_data)-2;j += 2) {
-        value = le_expected[j&3];
+    for(j = 0; j <= DATA_REP * sizeof(le_data) - 2; j += 2) {
+        value = le_expected[j & 3];
         fail_unless(cli_readint16(&data[j]) == value, "(2) data read must be little endian");
     }
 }
 END_TEST
 
 /* test reading with different alignments, _i is parameter from tcase_add_loop_test */
-START_TEST (test_cli_readint32)
+START_TEST(test_cli_readint32)
 {
     size_t j;
-    int32_t value = le_expected[_i&3];
+    int32_t value = le_expected[_i & 3];
     /* read 4 bytes apart, start is not always aligned*/
-    for(j=_i;j < DATA_REP*sizeof(le_data)-4;j += 4) {
+    for(j = _i; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
         fail_unless(cli_readint32(&data[j]) == value, "(1) data read must be little endian");
     }
     value = le_expected[0];
     /* read 4 bytes apart, always aligned*/
-    for(j=0;j < DATA_REP*sizeof(le_data)-4;j += 4) {
+    for(j = 0; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
         fail_unless(cli_readint32(&data[j]) == value, "(2) data read must be little endian");
     }
 }
 END_TEST
 
 /* test writing with different alignments, _i is parameter from tcase_add_loop_test */
-START_TEST (test_cli_writeint32)
+START_TEST(test_cli_writeint32)
 {
     size_t j;
     /* write 4 bytes apart, start is not always aligned*/
-    for(j=_i;j < DATA_REP*sizeof(le_data) - 4;j += 4) {
+    for(j = _i; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
         cli_writeint32(&data2[j], 0x12345678);
     }
-    for(j=_i;j < DATA_REP*sizeof(le_data) - 4;j += 4) {
+    for(j = _i; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
         fail_unless(cli_readint32(&data2[j]) == 0x12345678, "write/read mismatch");
     }
     /* write 4 bytes apart, always aligned*/
-    for(j=0;j < DATA_REP*sizeof(le_data) - 4;j += 4) {
+    for(j = 0; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
         cli_writeint32(&data2[j], 0x12345678);
     }
-    for(j=0;j < DATA_REP*sizeof(le_data) - 4;j += 4) {
+    for(j = 0; j < DATA_REP * sizeof(le_data) - 4; j += 4) {
         fail_unless(cli_readint32(&data2[j]) == 0x12345678, "write/read mismatch");
     }
 }
 END_TEST
 
 static struct dsig_test {
-    const char *md5;
-    const char *dsig;
+    const char* md5;
+    const char* dsig;
     int result;
-} dsig_tests [] = {
-    {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe", 
-	CL_SUCCESS},
+} dsig_tests[] = {
+    {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
+     CL_SUCCESS},
     {"96b7feb3b2a863846438809fe481906f", "Zh5gmf09Zfj6V4gmRKu/NURzhFiE9VloI7w1G33BgDdGSs0Xhscx6sjPUpFSCPsjOalyS4L8q7RS+NdGvNCsLymiIH6RYItlOZsygFhcGuH4jt15KAaAkvEg2TwmqR8z41nUaMlZ0c8q1MXYCLvQJyFARsfzIxS3PAoN2Y3HPoe",
-	CL_SUCCESS},
+     CL_SUCCESS},
     {"ae307614434715274c60854c931a26de", "Zh5gmf09Zfj6V4gmRKu/NURzhFiE9VloI7w1G33BgDdGSs0Xhscx6sjPUpFSCPsjOalyS4L8q7RS+NdGvNCsLymiIH6RYItlOZsygFhcGuH4jt15KAaAkvEg2TwmqR8z41nUaMlZ0c8q1MXYCLvQJyFARsfzIxS3PAoN2Y3HPoe",
-	CL_EVERIFY},
+     CL_EVERIFY},
     {"96b7feb3b2a863846438809fe481906f", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
-	CL_EVERIFY},
+     CL_EVERIFY},
     {"ae307614434715274060854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
-	CL_EVERIFY},
+     CL_EVERIFY},
     {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaatinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
-	CL_EVERIFY},
+     CL_EVERIFY},
     {"96b7feb3b2a863846438809fe481906f", "Zh5gmf09Zfj6V4gmRKu/NURzhFiE9VloI7w1G33BgDdGSs0Xhscx6sjPUpFSCPsjOalyS4L8q7RS+NdGvNCsLymiIH6RYItlOZsygFhcGuH4jt15KAaAkvEg2TwmqR8z41nUaMlZ0c8q1MYYCLvQJyFARsfzIxS3PAoN2Y3HPoe",
-	CL_EVERIFY},
-    {"ge307614434715274c60854c931a26dee","60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
-	CL_EVERIFY},
-    {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGee", 
-	CL_EVERIFY},
-    {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+", 
-	CL_EVERIFY}
-};
+     CL_EVERIFY},
+    {"ge307614434715274c60854c931a26dee", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGe",
+     CL_EVERIFY},
+    {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+60VhQcuXfb0iV1O+sCEyMiRXt/iYF6vXtPXHVd6DiuZ4Gfrry7sVQqNTt3o1/KwU1rc0l5FHgX/nC99fdr/fjaFtinMtRnUXHLeu0j8e6HK+7JLBpD37fZ60GC9YY86EclYGee",
+     CL_EVERIFY},
+    {"ae307614434715274c60854c931a26de", "60uhCFmiN48J8r6c7coBv9Q1mehAWEGh6GPYA+",
+     CL_EVERIFY}};
 
-static const size_t dsig_tests_cnt = sizeof(dsig_tests)/sizeof(dsig_tests[0]);
+static const size_t dsig_tests_cnt = sizeof(dsig_tests) / sizeof(dsig_tests[0]);
 
-START_TEST (test_cli_dsig)
+START_TEST(test_cli_dsig)
 {
     fail_unless(cli_versig(dsig_tests[_i].md5, dsig_tests[_i].dsig) == dsig_tests[_i].result,
-		"digital signature verification test failed");
+                "digital signature verification test failed");
 }
 END_TEST
 
 static uint8_t tv1[3] = {
-  0x61, 0x62, 0x63
-};
+    0x61, 0x62, 0x63};
 
 static uint8_t tv2[56] = {
-  0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65,
-  0x63, 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67,
-  0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69,
-  0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b,
-  0x69, 0x6a, 0x6b, 0x6c, 0x6a, 0x6b, 0x6c, 0x6d,
-  0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f,
-  0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71
-};
+    0x61, 0x62, 0x63, 0x64, 0x62, 0x63, 0x64, 0x65,
+    0x63, 0x64, 0x65, 0x66, 0x64, 0x65, 0x66, 0x67,
+    0x65, 0x66, 0x67, 0x68, 0x66, 0x67, 0x68, 0x69,
+    0x67, 0x68, 0x69, 0x6a, 0x68, 0x69, 0x6a, 0x6b,
+    0x69, 0x6a, 0x6b, 0x6c, 0x6a, 0x6b, 0x6c, 0x6d,
+    0x6b, 0x6c, 0x6d, 0x6e, 0x6c, 0x6d, 0x6e, 0x6f,
+    0x6d, 0x6e, 0x6f, 0x70, 0x6e, 0x6f, 0x70, 0x71};
 
 static uint8_t res256[3][SHA256_HASH_SIZE] = {
-  { 0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
-    0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
-    0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad },
-  { 0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93,
-    0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
-    0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1 },
-  { 0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2,
-    0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e,
-    0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0 }
-};
+    {0xba, 0x78, 0x16, 0xbf, 0x8f, 0x01, 0xcf, 0xea, 0x41, 0x41, 0x40, 0xde,
+     0x5d, 0xae, 0x22, 0x23, 0xb0, 0x03, 0x61, 0xa3, 0x96, 0x17, 0x7a, 0x9c,
+     0xb4, 0x10, 0xff, 0x61, 0xf2, 0x00, 0x15, 0xad},
+    {0x24, 0x8d, 0x6a, 0x61, 0xd2, 0x06, 0x38, 0xb8, 0xe5, 0xc0, 0x26, 0x93,
+     0x0c, 0x3e, 0x60, 0x39, 0xa3, 0x3c, 0xe4, 0x59, 0x64, 0xff, 0x21, 0x67,
+     0xf6, 0xec, 0xed, 0xd4, 0x19, 0xdb, 0x06, 0xc1},
+    {0xcd, 0xc7, 0x6e, 0x5c, 0x99, 0x14, 0xfb, 0x92, 0x81, 0xa1, 0xc7, 0xe2,
+     0x84, 0xd7, 0x3e, 0x67, 0xf1, 0x80, 0x9a, 0x48, 0xa4, 0x97, 0x20, 0x0e,
+     0x04, 0x6d, 0x39, 0xcc, 0xc7, 0x11, 0x2c, 0xd0}};
 
-START_TEST (test_sha256)
+START_TEST(test_sha256)
 {
-    void *sha256;
+    void* sha256;
     uint8_t hsha256[SHA256_HASH_SIZE];
     uint8_t buf[1000];
     int i;
 
-    memset (buf, 0x61, sizeof (buf));
+    memset(buf, 0x61, sizeof(buf));
 
     cl_sha256(tv1, sizeof(tv1), hsha256, NULL);
-    fail_unless(!memcmp (hsha256, res256[0], sizeof (hsha256)), "sha256 test vector #1 failed");
+    fail_unless(!memcmp(hsha256, res256[0], sizeof(hsha256)), "sha256 test vector #1 failed");
 
     cl_sha256(tv2, sizeof(tv2), hsha256, NULL);
-    fail_unless(!memcmp (hsha256, res256[1], sizeof (hsha256)), "sha256 test vector #2 failed");
+    fail_unless(!memcmp(hsha256, res256[1], sizeof(hsha256)), "sha256 test vector #2 failed");
 
     sha256 = cl_hash_init("sha256");
     fail_unless(sha256 != NULL, "Could not create EVP_MD_CTX for sha256");
 
-    for (i = 0; i < 1000; i++)
-        cl_update_hash (sha256, buf, sizeof (buf));
+    for(i = 0; i < 1000; i++)
+        cl_update_hash(sha256, buf, sizeof(buf));
     cl_finish_hash(sha256, hsha256);
-    fail_unless(!memcmp (hsha256, res256[2], sizeof (hsha256)), "sha256 test vector #3 failed");
+    fail_unless(!memcmp(hsha256, res256[2], sizeof(hsha256)), "sha256 test vector #3 failed");
 }
 END_TEST
 
-static Suite *test_cli_suite(void)
+START_TEST(test_sanitize_path)
 {
-    Suite *s = suite_create("cli");
-    TCase *tc_cli_others = tcase_create("byteorder_macros");
-    TCase *tc_cli_dsig = tcase_create("digital signatures");
+    char* sanitized         = NULL;
+    const char* unsanitized = NULL;
+
+    unsanitized = "";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL != sanitized, "sanitize_path: Empty path test failed");
+
+    unsanitized = NULL;
+    sanitized   = cli_sanitize_filepath(unsanitized, 0);
+    fail_if(NULL != sanitized, "sanitize_path: NULL path #1 test failed");
+
+    unsanitized = NULL;
+    sanitized   = cli_sanitize_filepath(unsanitized, 50);
+    fail_if(NULL != sanitized, "sanitize_path: NULL path #2 test failed");
+
+    unsanitized = "badlen";
+    sanitized   = cli_sanitize_filepath(unsanitized, 0);
+    fail_if(NULL != sanitized, "sanitize_path: Zero/bad path length test failed");
+
+    unsanitized = ".." PATHSEP;
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL != sanitized, "sanitize_path: sanitized path should have been NULL");
+
+    unsanitized = "." PATHSEP;
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL != sanitized, "sanitize_path: sanitized path should have been NULL (2)");
+
+    unsanitized = PATHSEP;
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL != sanitized, "sanitize_path: sanitized path should have been NULL (3)");
+
+    unsanitized = ".." PATHSEP "relative_bad_1";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "relative_bad_1"), "sanitize_path: bad relative path test #1 failed");
+    free(sanitized);
+
+    unsanitized = "relative" PATHSEP ".." PATHSEP "good";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "relative" PATHSEP ".." PATHSEP "good"), "sanitize_path: good relative path test failed");
+    free(sanitized);
+
+    unsanitized = "relative" PATHSEP ".." PATHSEP ".." PATHSEP "bad_2";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "relative" PATHSEP ".." PATHSEP "bad_2"), "sanitize_path: bad relative path test failed");
+    free(sanitized);
+
+    unsanitized = "relative" PATHSEP "." PATHSEP ".." PATHSEP ".." PATHSEP "bad_current";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "relative" PATHSEP ".." PATHSEP "bad_current"), "sanitize_path: bad relative current path test failed");
+    free(sanitized);
+
+    unsanitized = "relative/../../bad_win_posix_path";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "relative/../bad_win_posix_path"), "sanitize_path: bad relative win posix path test failed");
+    free(sanitized);
+
+    unsanitized = "" PATHSEP "absolute" PATHSEP ".." PATHSEP ".." PATHSEP "bad";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "absolute" PATHSEP ".." PATHSEP "bad"), "sanitize_path: bad absolute path test failed");
+    free(sanitized);
+
+    unsanitized = "" PATHSEP "absolute" PATHSEP ".." PATHSEP "good";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "absolute" PATHSEP ".." PATHSEP "good"), "sanitize_path: good absolute path test failed");
+    free(sanitized);
+
+    unsanitized = "relative" PATHSEP "normal";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "relative" PATHSEP "normal"), "sanitize_path: relative normal path test failed");
+    free(sanitized);
+
+    unsanitized = "relative" PATHSEP PATHSEP "doublesep";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "relative" PATHSEP "doublesep"), "sanitize_path: relative double sep path test failed");
+    free(sanitized);
+
+    unsanitized = "relative" PATHSEP "shortname" PATHSEP "1";
+    sanitized   = cli_sanitize_filepath(unsanitized, strlen(unsanitized));
+    fail_if(NULL == sanitized);
+    fail_unless(!strcmp(sanitized, "relative" PATHSEP "shortname" PATHSEP "1"), "sanitize_path: relative short name path test failed");
+    free(sanitized);
+}
+END_TEST
+
+static Suite* test_cli_suite(void)
+{
+    Suite* s               = suite_create("cli");
+    TCase* tc_cli_others   = tcase_create("byteorder_macros");
+    TCase* tc_cli_dsig     = tcase_create("digital signatures");
+    TCase* tc_cli_assorted = tcase_create("assorted functions");
 
-    suite_add_tcase (s, tc_cli_others);
-    tcase_add_checked_fixture (tc_cli_others, data_setup, data_teardown);
+    suite_add_tcase(s, tc_cli_others);
+    tcase_add_checked_fixture(tc_cli_others, data_setup, data_teardown);
     tcase_add_loop_test(tc_cli_others, test_cli_readint32, 0, 16);
     tcase_add_loop_test(tc_cli_others, test_cli_readint16, 0, 16);
     tcase_add_loop_test(tc_cli_others, test_cli_writeint32, 0, 16);
 
-    suite_add_tcase (s, tc_cli_dsig);
+    suite_add_tcase(s, tc_cli_dsig);
     tcase_add_loop_test(tc_cli_dsig, test_cli_dsig, 0, dsig_tests_cnt);
     tcase_add_test(tc_cli_dsig, test_sha256);
 
+    suite_add_tcase(s, tc_cli_assorted);
+    tcase_add_test(tc_cli_assorted, test_sanitize_path);
+
     return s;
 }
 #endif /* CHECK_HAVE_LOOPS */
 
 void errmsg_expected(void)
 {
-	fputs("cli_errmsg() expected here\n", stderr);
+    fputs("cli_errmsg() expected here\n", stderr);
 }
 
-int open_testfile(const char *name)
+int open_testfile(const char* name)
 {
-	int fd;
-	const char * srcdir = getenv("srcdir");
-	char *str;
-
-	if(!srcdir) {
-		/* when run from automake srcdir is set, but if run manually then not */
-		srcdir = SRCDIR;
-	}
-
-	str = cli_malloc(strlen(name)+strlen(srcdir)+2);
-	fail_unless(!!str, "cli_malloc");
-	sprintf(str, "%s/%s", srcdir, name);
-
-	fd = open(str, O_RDONLY);
-	fail_unless_fmt(fd >= 0, "open() failed: %s", str);
-	free(str);
-	return fd;
-}
-
-void diff_file_mem(int fd, const char *ref, size_t len)
-{
-	char c1,c2;
-	size_t p, reflen = len;
-	char *buf = cli_malloc(len);
-
-	fail_unless_fmt(!!buf, "unable to malloc buffer: %d", len);
-	p = read(fd, buf, len);
-	fail_unless_fmt(p == len,  "file is smaller: %lu, expected: %lu", p, len);
-	p = 0;
-	while(len > 0) {
-		c1 = ref[p];
-		c2 = buf[p];
-		if(c1 != c2)
-			break;
-		p++;
-		len--;
-	}
-	if (len > 0)
-		fail_unless_fmt(c1 == c2, "file contents mismatch at byte: %lu, was: %c, expected: %c", p, c2, c1);
-	free(buf);
-	p = lseek(fd, 0, SEEK_END);
-        fail_unless_fmt(p == reflen, "trailing garbage, file size: %ld, expected: %ld", p, reflen);
-	close(fd);
+    int fd;
+    const char* srcdir = getenv("srcdir");
+    char* str;
+
+    if(!srcdir) {
+        /* when run from automake srcdir is set, but if run manually then not */
+        srcdir = SRCDIR;
+    }
+
+    str = cli_malloc(strlen(name) + strlen(srcdir) + 2);
+    fail_unless(!!str, "cli_malloc");
+    sprintf(str, "%s/%s", srcdir, name);
+
+    fd = open(str, O_RDONLY);
+    fail_unless_fmt(fd >= 0, "open() failed: %s", str);
+    free(str);
+    return fd;
+}
+
+void diff_file_mem(int fd, const char* ref, size_t len)
+{
+    char c1, c2;
+    size_t p, reflen = len;
+    char* buf = cli_malloc(len);
+
+    fail_unless_fmt(!!buf, "unable to malloc buffer: %d", len);
+    p = read(fd, buf, len);
+    fail_unless_fmt(p == len, "file is smaller: %lu, expected: %lu", p, len);
+    p = 0;
+    while(len > 0) {
+        c1 = ref[p];
+        c2 = buf[p];
+        if(c1 != c2)
+            break;
+        p++;
+        len--;
+    }
+    if(len > 0)
+        fail_unless_fmt(c1 == c2, "file contents mismatch at byte: %lu, was: %c, expected: %c", p, c2, c1);
+    free(buf);
+    p = lseek(fd, 0, SEEK_END);
+    fail_unless_fmt(p == reflen, "trailing garbage, file size: %ld, expected: %ld", p, reflen);
+    close(fd);
 }
 
 void diff_files(int fd, int ref_fd)
 {
-	char *ref;
-	ssize_t nread;
-	off_t siz = lseek(ref_fd, 0, SEEK_END);
-	fail_unless_fmt(siz != -1, "lseek failed");
-
-	ref = cli_malloc(siz);
-	fail_unless_fmt(!!ref, "unable to malloc buffer: %d", siz);
-
-	fail_unless_fmt(lseek(ref_fd, 0, SEEK_SET) == 0,"lseek failed");
-	nread = read(ref_fd, ref, siz);
-        fail_unless_fmt(nread == siz, "short read, expected: %ld, was: %ld", siz, nread);
-	close(ref_fd);
-	diff_file_mem(fd, ref, siz);
-	free(ref);
+    char* ref;
+    ssize_t nread;
+    off_t siz = lseek(ref_fd, 0, SEEK_END);
+    fail_unless_fmt(siz != -1, "lseek failed");
+
+    ref = cli_malloc(siz);
+    fail_unless_fmt(!!ref, "unable to malloc buffer: %d", siz);
+
+    fail_unless_fmt(lseek(ref_fd, 0, SEEK_SET) == 0, "lseek failed");
+    nread = read(ref_fd, ref, siz);
+    fail_unless_fmt(nread == siz, "short read, expected: %ld, was: %ld", siz, nread);
+    close(ref_fd);
+    diff_file_mem(fd, ref, siz);
+    free(ref);
 }
 
 #ifdef USE_MPOOL
-static mpool_t *pool;
+static mpool_t* pool;
 #else
-static void *pool;
+static void* pool;
 #endif
-struct cli_dconf *dconf;
+struct cli_dconf* dconf;
 
 void dconf_setup(void)
 {
-	pool = NULL;
-	dconf = NULL;
+    pool  = NULL;
+    dconf = NULL;
 #ifdef USE_MPOOL
-	pool = mpool_create();
-	fail_unless(!!pool, "unable to create pool");
+    pool = mpool_create();
+    fail_unless(!!pool, "unable to create pool");
 #endif
-	dconf = cli_mpool_dconf_init(pool);
-	fail_unless(!!dconf, "failed to init dconf");
+    dconf = cli_mpool_dconf_init(pool);
+    fail_unless(!!dconf, "failed to init dconf");
 }
 
 void dconf_teardown(void)
 {
-	mpool_free(pool, dconf);
+    mpool_free(pool, dconf);
 #ifdef USE_MPOOL
-	if (pool)
-		mpool_destroy(pool);
+    if(pool)
+        mpool_destroy(pool);
 #endif
 }
 
@@ -1009,35 +1105,35 @@
     /* check 0.9.8 is not ABI compatible with 0.9.6,
      * if by accident you compile with check 0.9.6 header
      * and link with 0.9.8 then check will hang/crash. */
-    if ((check_major_version != CHECK_MAJOR_VERSION) ||
-	(check_minor_version != CHECK_MINOR_VERSION) ||
-	(check_micro_version != CHECK_MICRO_VERSION)) {
-	fprintf(stderr, "ERROR: check version mismatch!\n"
-		"\tVersion from header: %u.%u.%u\n"
-		"\tVersion from library: %u.%u.%u\n"
-		"\tMake sure check.h and -lcheck are same version!\n",
-		CHECK_MAJOR_VERSION,
-		CHECK_MINOR_VERSION,
-		CHECK_MICRO_VERSION,
-		check_major_version,
-		check_minor_version,
-		check_micro_version);
-	exit(EXIT_FAILURE);
+    if((check_major_version != CHECK_MAJOR_VERSION) ||
+       (check_minor_version != CHECK_MINOR_VERSION) ||
+       (check_micro_version != CHECK_MICRO_VERSION)) {
+        fprintf(stderr, "ERROR: check version mismatch!\n"
+                        "\tVersion from header: %u.%u.%u\n"
+                        "\tVersion from library: %u.%u.%u\n"
+                        "\tMake sure check.h and -lcheck are same version!\n",
+                CHECK_MAJOR_VERSION,
+                CHECK_MINOR_VERSION,
+                CHECK_MICRO_VERSION,
+                check_major_version,
+                check_minor_version,
+                check_micro_version);
+        exit(EXIT_FAILURE);
     }
 }
 
 int main(void)
 {
     int nf;
-    Suite *s;
-    SRunner *sr;
+    Suite* s;
+    SRunner* sr;
 
     cl_initialize_crypto();
 
-    fpu_words  = get_fpu_endian();
-  
+    fpu_words = get_fpu_endian();
+
     check_version_compatible();
-    s = test_cl_suite();
+    s  = test_cl_suite();
     sr = srunner_create(s);
 #ifdef CHECK_HAVE_LOOPS
     srunner_add_suite(sr, test_cli_suite());
@@ -1053,17 +1149,16 @@
     srunner_add_suite(sr, test_htmlnorm_suite());
     srunner_add_suite(sr, test_bytecode_suite());
 
-
     srunner_set_log(sr, "test.log");
-    if(freopen("test-stderr.log","w+",stderr) == NULL) {
-	    fputs("Unable to redirect stderr!\n",stderr);
+    if(freopen("test-stderr.log", "w+", stderr) == NULL) {
+        fputs("Unable to redirect stderr!\n", stderr);
     }
     cl_debug();
 
     srunner_run_all(sr, CK_NORMAL);
     nf = srunner_ntests_failed(sr);
-    if (nf)
-	printf("NOTICE: Use the 'T' environment variable to adjust testcase timeout\n");
+    if(nf)
+        printf("NOTICE: Use the 'T' environment variable to adjust testcase timeout\n");
     srunner_free(sr);
 
 #if HAVE_LIBXML2
diff -Nru clamav-0.101.1+dfsg/unit_tests/check_uniq.c clamav-0.101.2+dfsg/unit_tests/check_uniq.c
--- clamav-0.101.1+dfsg/unit_tests/check_uniq.c	2018-12-19 21:48:30.000000000 +0100
+++ clamav-0.101.2+dfsg/unit_tests/check_uniq.c	2019-03-13 22:13:01.000000000 +0100
@@ -28,6 +28,7 @@
 #include <stdlib.h>
 #include <string.h>
 
+#include "../libclamav/clamav.h"
 #include "../libclamav/uniq.h"
 #include "checks.h"
 
@@ -59,12 +60,16 @@
   fail_unless(U!=0, "uniq_init");
 
   for(i=0; tests[i].expected; i++) {
-    u = uniq_add(U, tests[i].key, tests[i].key_len, &hash);
-    fail_unless_fmt(u==0 && strcmp(hash, tests[i].expected)==0, "uniq_add(%s) = %u - expected %s, got %s", tests[i].key, u, tests[i].expected, hash);
+        if (CL_SUCCESS != uniq_add(U, tests[i].key, tests[i].key_len, &hash, &u)) {
+            fail("uniq_add(%s) failed.", tests[i].key);
+        }
+        fail_unless_fmt(u == 1 && strcmp(hash, tests[i].expected) == 0, "uniq_add(%s) = %u - expected %s, got %s", tests[i].key, u, tests[i].expected, hash);
   }
 
   for(i=0; tests[i].expected; i++) {
-    u = uniq_get(U, tests[i].key, tests[i].key_len, &hash);
+        if (CL_SUCCESS != uniq_get(U, tests[i].key, tests[i].key_len, &hash, &u)) {
+            fail("uniq_get(%s) failed.", tests[i].key);
+        }
     fail_unless_fmt(u==1 && strcmp(hash, tests[i].expected)==0, "uniq_get(%s) = %u - expected %s, got %s", tests[i].key, u, tests[i].expected, hash);
   }
 
@@ -82,11 +87,16 @@
   fail_unless(U!=0, "uniq_init");
 
   for(j=4; j>0; j--)
-    for (i=0; i<j; i++)
-      u = uniq_add(U, tests[i], strlen(tests[i]), NULL);
+        for (i = 0; i < j; i++) {
+            if (CL_SUCCESS != uniq_add(U, tests[i], strlen(tests[i]), NULL, &u)) {
+                fail("uniq_add(%s) failed.", tests[i]);
+            }
+        }
   
   for (i=0; i<4; i++) {
-    u = uniq_add(U, tests[i], strlen(tests[i]), NULL);
+        if (CL_SUCCESS != uniq_get(U, tests[i], strlen(tests[i]), NULL, &u)) {
+            fail("uniq_get(%s) failed.", tests[i]);
+        }
     fail_unless_fmt(u+i==4, "uniq_get(%s) = %u - expected %u", tests[i], u, 4-i);
   }
 


More information about the Pkg-clamav-devel mailing list