[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Bug#926171: marked as done (unblock: clamav/0.101.2+dfsg-1)



Your message dated Mon, 01 Apr 2019 18:29:00 +0000
with message-id <05afa9a2-6321-0373-bd1d-bd35a704d48a@thykier.net>
and subject line Re: Bug#926171: unblock: clamav/0.101.2+dfsg-1
has caused the Debian Bug report #926171,
regarding unblock: clamav/0.101.2+dfsg-1
to be marked as done.

This means that you claim that the problem has been dealt with.
If this is not the case it is now your responsibility to reopen the
Bug report if necessary, and/or fix the problem forthwith.

(NB: If you are a system administrator and have no idea what this
message is talking about, this may indicate a serious mail system
misconfiguration somewhere. Please contact owner@bugs.debian.org
immediately.)


-- 
926171: https://bugs.debian.org/cgi-bin/bugreport.cgi?bug=926171
Debian Bug Tracking System
Contact owner@bugs.debian.org with problems
--- Begin Message ---
Package: release.debian.org
User: release.debian.org@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
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@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@CLAMAV_PRIVATE 0.101.1
+ CLAMAV_PRIVATE@CLAMAV_PRIVATE 0.101.2
  CLAMAV_PUBLIC@CLAMAV_PUBLIC 0.101.0
- base64Flush@CLAMAV_PRIVATE 0.101.1
- blobAddData@CLAMAV_PRIVATE 0.101.1
- blobCreate@CLAMAV_PRIVATE 0.101.1
- blobDestroy@CLAMAV_PRIVATE 0.101.1
- cl_ASN1_GetTimeT@CLAMAV_PRIVATE 0.101.1
+ base64Flush@CLAMAV_PRIVATE 0.101.2
+ blobAddData@CLAMAV_PRIVATE 0.101.2
+ blobCreate@CLAMAV_PRIVATE 0.101.2
+ blobDestroy@CLAMAV_PRIVATE 0.101.2
+ cl_ASN1_GetTimeT@CLAMAV_PRIVATE 0.101.2
  cl_always_gen_section_hash@CLAMAV_PUBLIC 0.101.0
- cl_base64_decode@CLAMAV_PRIVATE 0.101.1
- cl_base64_encode@CLAMAV_PRIVATE 0.101.1
- cl_cleanup_crypto@CLAMAV_PRIVATE 0.101.1
+ cl_base64_decode@CLAMAV_PRIVATE 0.101.2
+ cl_base64_encode@CLAMAV_PRIVATE 0.101.2
+ cl_cleanup_crypto@CLAMAV_PRIVATE 0.101.2
  cl_countsigs@CLAMAV_PUBLIC 0.101.0
  cl_cvdfree@CLAMAV_PUBLIC 0.101.0
  cl_cvdhead@CLAMAV_PUBLIC 0.101.0
@@ -50,19 +50,19 @@
  cl_fmap_close@CLAMAV_PUBLIC 0.101.0
  cl_fmap_open_handle@CLAMAV_PUBLIC 0.101.0
  cl_fmap_open_memory@CLAMAV_PUBLIC 0.101.0
- cl_get_pkey_file@CLAMAV_PRIVATE 0.101.1
- cl_get_x509_from_mem@CLAMAV_PRIVATE 0.101.1
- cl_hash_data@CLAMAV_PRIVATE 0.101.1
+ cl_get_pkey_file@CLAMAV_PRIVATE 0.101.2
+ cl_get_x509_from_mem@CLAMAV_PRIVATE 0.101.2
+ cl_hash_data@CLAMAV_PRIVATE 0.101.2
  cl_hash_destroy@CLAMAV_PUBLIC 0.101.0
- cl_hash_file_fd@CLAMAV_PRIVATE 0.101.1
- cl_hash_file_fd_ctx@CLAMAV_PRIVATE 0.101.1
- cl_hash_file_fp@CLAMAV_PRIVATE 0.101.1
+ cl_hash_file_fd@CLAMAV_PRIVATE 0.101.2
+ cl_hash_file_fd_ctx@CLAMAV_PRIVATE 0.101.2
+ cl_hash_file_fp@CLAMAV_PRIVATE 0.101.2
  cl_hash_init@CLAMAV_PUBLIC 0.101.0
  cl_init@CLAMAV_PUBLIC 0.101.0
- cl_initialize_crypto@CLAMAV_PRIVATE 0.101.1
+ cl_initialize_crypto@CLAMAV_PRIVATE 0.101.2
  cl_load@CLAMAV_PUBLIC 0.101.0
- cl_load_cert@CLAMAV_PRIVATE 0.101.1
- cl_load_crl@CLAMAV_PRIVATE 0.101.1
+ cl_load_cert@CLAMAV_PRIVATE 0.101.2
+ cl_load_crl@CLAMAV_PRIVATE 0.101.2
  cl_retdbdir@CLAMAV_PUBLIC 0.101.0
  cl_retflevel@CLAMAV_PUBLIC 0.101.1
  cl_retver@CLAMAV_PUBLIC 0.101.0
@@ -72,182 +72,185 @@
  cl_scanfile_callback@CLAMAV_PUBLIC 0.101.0
  cl_scanmap_callback@CLAMAV_PUBLIC 0.101.0
  cl_set_clcb_msg@CLAMAV_PUBLIC 0.101.0
- cl_sha1@CLAMAV_PRIVATE 0.101.1
- cl_sha256@CLAMAV_PRIVATE 0.101.1
- cl_sign_data@CLAMAV_PRIVATE 0.101.1
- cl_sign_data_keyfile@CLAMAV_PRIVATE 0.101.1
- cl_sign_file_fd@CLAMAV_PRIVATE 0.101.1
- cl_sign_file_fp@CLAMAV_PRIVATE 0.101.1
+ cl_sha1@CLAMAV_PRIVATE 0.101.2
+ cl_sha256@CLAMAV_PRIVATE 0.101.2
+ cl_sign_data@CLAMAV_PRIVATE 0.101.2
+ cl_sign_data_keyfile@CLAMAV_PRIVATE 0.101.2
+ cl_sign_file_fd@CLAMAV_PRIVATE 0.101.2
+ cl_sign_file_fp@CLAMAV_PRIVATE 0.101.2
  cl_statchkdir@CLAMAV_PUBLIC 0.101.0
  cl_statfree@CLAMAV_PUBLIC 0.101.0
  cl_statinidir@CLAMAV_PUBLIC 0.101.0
  cl_strerror@CLAMAV_PUBLIC 0.101.0
  cl_update_hash@CLAMAV_PUBLIC 0.101.0
- cl_validate_certificate_chain@CLAMAV_PRIVATE 0.101.1
- cl_validate_certificate_chain_ts_dir@CLAMAV_PRIVATE 0.101.1
- cl_verify_signature@CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_fd@CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_fd_x509@CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_fd_x509_keyfile@CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_hash@CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_hash_x509@CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_hash_x509_keyfile@CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_x509@CLAMAV_PRIVATE 0.101.1
- cl_verify_signature_x509_keyfile@CLAMAV_PRIVATE 0.101.1
- cli_ac_buildtrie@CLAMAV_PRIVATE 0.101.1
- cli_ac_chklsig@CLAMAV_PRIVATE 0.101.1
- cli_ac_free@CLAMAV_PRIVATE 0.101.1
- cli_ac_freedata@CLAMAV_PRIVATE 0.101.1
- cli_ac_init@CLAMAV_PRIVATE 0.101.1
- cli_ac_initdata@CLAMAV_PRIVATE 0.101.1
- cli_ac_scanbuff@CLAMAV_PRIVATE 0.101.1
- cli_bm_free@CLAMAV_PRIVATE 0.101.1
- cli_bm_init@CLAMAV_PRIVATE 0.101.1
- cli_bm_scanbuff@CLAMAV_PRIVATE 0.101.1
- cli_build_regex_list@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_alloc@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_clear@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_destroy@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_getresult_int@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_set_trace@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setfile@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setfuncid@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setparam_int@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_context_setparam_ptr@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_debug@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_debug_printsrc@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_describe@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_destroy@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_done@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_init@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_load@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_prepare2@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_printversion@CLAMAV_PRIVATE 0.101.1
- cli_bytecode_run@CLAMAV_PRIVATE 0.101.1
- cli_bytefunc_describe@CLAMAV_PRIVATE 0.101.1
- cli_byteinst_describe@CLAMAV_PRIVATE 0.101.1
- cli_bytetype_describe@CLAMAV_PRIVATE 0.101.1
- cli_bytevalue_describe@CLAMAV_PRIVATE 0.101.1
- cli_calloc@CLAMAV_PRIVATE 0.101.1
- cli_checkfp_pe@CLAMAV_PRIVATE 0.101.1
- cli_chomp@CLAMAV_PRIVATE 0.101.1
- cli_ctime@CLAMAV_PRIVATE 0.101.1
- cli_cvdunpack@CLAMAV_PRIVATE 0.101.1
- cli_dbgmsg_internal@CLAMAV_PRIVATE 0.101.1
- cli_dconf_init@CLAMAV_PRIVATE 0.101.1
- cli_debug_flag@CLAMAV_PRIVATE 0.101.1
- cli_detect_environment@CLAMAV_PRIVATE 0.101.1
- cli_disasm_one@CLAMAV_PRIVATE 0.101.1
- cli_errmsg@CLAMAV_PRIVATE 0.101.1
- cli_filecopy@CLAMAV_PRIVATE 0.101.1
- cli_fmap_scandesc@CLAMAV_PRIVATE 0.101.1
- cli_ftw@CLAMAV_PRIVATE 0.101.1
- cli_genhash_pe@CLAMAV_PRIVATE 0.101.1
- cli_gentemp@CLAMAV_PRIVATE 0.101.1
- cli_gentempfd@CLAMAV_PRIVATE 0.101.1
- cli_gettmpdir@CLAMAV_PRIVATE 0.101.1
- cli_hashfile@CLAMAV_PRIVATE 0.101.1
- cli_hashset_destroy@CLAMAV_PRIVATE 0.101.1
- cli_hashstream@CLAMAV_PRIVATE 0.101.1
- cli_hex2str@CLAMAV_PRIVATE 0.101.1
- cli_hex2ui@CLAMAV_PRIVATE 0.101.1
- cli_initroots@CLAMAV_PRIVATE 0.101.1
- cli_isnumber@CLAMAV_PRIVATE 0.101.1
- cli_js_destroy@CLAMAV_PRIVATE 0.101.1
- cli_js_init@CLAMAV_PRIVATE 0.101.1
- cli_js_output@CLAMAV_PRIVATE 0.101.1
- cli_js_parse_done@CLAMAV_PRIVATE 0.101.1
- cli_js_process_buffer@CLAMAV_PRIVATE 0.101.1
- cli_ldbtokenize@CLAMAV_PRIVATE 0.101.1
- cli_malloc@CLAMAV_PRIVATE 0.101.1
- cli_memstr@CLAMAV_PRIVATE 0.101.1
- cli_ole2_extract@CLAMAV_PRIVATE 0.101.1
- cli_parse_add@CLAMAV_PRIVATE 0.101.1
- cli_pcre_build@CLAMAV_PRIVATE 0.101.1
- cli_pcre_freeoff@CLAMAV_PRIVATE 0.101.1
- cli_pcre_init@CLAMAV_PRIVATE 0.101.1
- cli_pcre_perf_events_destroy@CLAMAV_PRIVATE 0.101.1
- cli_pcre_perf_print@CLAMAV_PRIVATE 0.101.1
- cli_pcre_recaloff@CLAMAV_PRIVATE 0.101.1
- cli_pcre_scanbuf@CLAMAV_PRIVATE 0.101.1
- cli_ppt_vba_read@CLAMAV_PRIVATE 0.101.1
- cli_printcxxver@CLAMAV_PRIVATE 0.101.1
- cli_readn@CLAMAV_PRIVATE 0.101.1
- cli_realloc@CLAMAV_PRIVATE 0.101.1
- cli_regcomp@CLAMAV_PRIVATE 0.101.1
- cli_regex2suffix@CLAMAV_PRIVATE 0.101.1
- cli_regexec@CLAMAV_PRIVATE 0.101.1
- cli_regfree@CLAMAV_PRIVATE 0.101.1
- cli_rmdirs@CLAMAV_PRIVATE 0.101.1
- cli_rndnum@CLAMAV_PRIVATE 0.101.1
- cli_scanbuff@CLAMAV_PRIVATE 0.101.1
- cli_sigopts_handler@CLAMAV_PRIVATE 0.101.1
- cli_sigperf_events_destroy@CLAMAV_PRIVATE 0.101.1
- cli_sigperf_print@CLAMAV_PRIVATE 0.101.1
- cli_str2hex@CLAMAV_PRIVATE 0.101.1
- cli_strbcasestr@CLAMAV_PRIVATE 0.101.1
- cli_strdup@CLAMAV_PRIVATE 0.101.1
- cli_strerror@CLAMAV_PRIVATE 0.101.1
- cli_strlcat@CLAMAV_PRIVATE 0.101.1
- cli_strlcpy@CLAMAV_PRIVATE 0.101.1
- cli_strrcpy@CLAMAV_PRIVATE 0.101.1
- cli_strtok@CLAMAV_PRIVATE 0.101.1
- cli_strtokbuf@CLAMAV_PRIVATE 0.101.1
- cli_strtokenize@CLAMAV_PRIVATE 0.101.1
- cli_textbuffer_append_normalize@CLAMAV_PRIVATE 0.101.1
- cli_unescape@CLAMAV_PRIVATE 0.101.1
- cli_unlink@CLAMAV_PRIVATE 0.101.1
- cli_url_canon@CLAMAV_PRIVATE 0.101.1
- cli_utf16_to_utf8@CLAMAV_PRIVATE 0.101.1
- cli_utf16toascii@CLAMAV_PRIVATE 0.101.1
- cli_vba_inflate@CLAMAV_PRIVATE 0.101.1
- cli_vba_readdir@CLAMAV_PRIVATE 0.101.1
- cli_versig2@CLAMAV_PRIVATE 0.101.1
- cli_versig@CLAMAV_PRIVATE 0.101.1
- cli_warnmsg@CLAMAV_PRIVATE 0.101.1
- cli_wm_decrypt_macro@CLAMAV_PRIVATE 0.101.1
- cli_wm_readdir@CLAMAV_PRIVATE 0.101.1
- cli_writen@CLAMAV_PRIVATE 0.101.1
- decodeLine@CLAMAV_PRIVATE 0.101.1
- disasmbuf@CLAMAV_PRIVATE 0.101.1
- fmap@CLAMAV_PRIVATE 0.101.1
- get_fpu_endian@CLAMAV_PRIVATE 0.101.1
- have_clamjit@CLAMAV_PRIVATE 0.101.1
- have_rar@CLAMAV_PRIVATE 0.101.1
- html_normalise_map@CLAMAV_PRIVATE 0.101.1
- html_normalise_mem@CLAMAV_PRIVATE 0.101.1
- html_screnc_decode@CLAMAV_PRIVATE 0.101.1
- html_tag_arg_free@CLAMAV_PRIVATE 0.101.1
- init_domainlist@CLAMAV_PRIVATE 0.101.1
- init_regex_list@CLAMAV_PRIVATE 0.101.1
- init_whitelist@CLAMAV_PRIVATE 0.101.1
- is_regex_ok@CLAMAV_PRIVATE 0.101.1
- load_regex_matcher@CLAMAV_PRIVATE 0.101.1
+ cl_validate_certificate_chain@CLAMAV_PRIVATE 0.101.2
+ cl_validate_certificate_chain_ts_dir@CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature@CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_fd@CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_fd_x509@CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_fd_x509_keyfile@CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_hash@CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_hash_x509@CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_hash_x509_keyfile@CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_x509@CLAMAV_PRIVATE 0.101.2
+ cl_verify_signature_x509_keyfile@CLAMAV_PRIVATE 0.101.2
+ cli_ac_buildtrie@CLAMAV_PRIVATE 0.101.2
+ cli_ac_chklsig@CLAMAV_PRIVATE 0.101.2
+ cli_ac_free@CLAMAV_PRIVATE 0.101.2
+ cli_ac_freedata@CLAMAV_PRIVATE 0.101.2
+ cli_ac_init@CLAMAV_PRIVATE 0.101.2
+ cli_ac_initdata@CLAMAV_PRIVATE 0.101.2
+ cli_ac_scanbuff@CLAMAV_PRIVATE 0.101.2
+ cli_bm_free@CLAMAV_PRIVATE 0.101.2
+ cli_bm_init@CLAMAV_PRIVATE 0.101.2
+ cli_bm_scanbuff@CLAMAV_PRIVATE 0.101.2
+ cli_build_regex_list@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_alloc@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_clear@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_destroy@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_getresult_int@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_set_trace@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setfile@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setfuncid@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setparam_int@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_context_setparam_ptr@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_debug@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_debug_printsrc@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_describe@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_destroy@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_done@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_init@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_load@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_prepare2@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_printversion@CLAMAV_PRIVATE 0.101.2
+ cli_bytecode_run@CLAMAV_PRIVATE 0.101.2
+ cli_bytefunc_describe@CLAMAV_PRIVATE 0.101.2
+ cli_byteinst_describe@CLAMAV_PRIVATE 0.101.2
+ cli_bytetype_describe@CLAMAV_PRIVATE 0.101.2
+ cli_bytevalue_describe@CLAMAV_PRIVATE 0.101.2
+ cli_calloc@CLAMAV_PRIVATE 0.101.2
+ cli_checkfp_pe@CLAMAV_PRIVATE 0.101.2
+ cli_chomp@CLAMAV_PRIVATE 0.101.2
+ cli_ctime@CLAMAV_PRIVATE 0.101.2
+ cli_cvdunpack@CLAMAV_PRIVATE 0.101.2
+ cli_dbgmsg_internal@CLAMAV_PRIVATE 0.101.2
+ cli_dconf_init@CLAMAV_PRIVATE 0.101.2
+ cli_debug_flag@CLAMAV_PRIVATE 0.101.2
+ cli_detect_environment@CLAMAV_PRIVATE 0.101.2
+ cli_disasm_one@CLAMAV_PRIVATE 0.101.2
+ cli_errmsg@CLAMAV_PRIVATE 0.101.2
+ cli_filecopy@CLAMAV_PRIVATE 0.101.2
+ cli_fmap_scandesc@CLAMAV_PRIVATE 0.101.2
+ cli_free_vba_project@CLAMAV_PRIVATE 0.101.2
+ cli_ftw@CLAMAV_PRIVATE 0.101.2
+ cli_genhash_pe@CLAMAV_PRIVATE 0.101.2
+ cli_gentemp@CLAMAV_PRIVATE 0.101.2
+ cli_gentempfd@CLAMAV_PRIVATE 0.101.2
+ cli_gettmpdir@CLAMAV_PRIVATE 0.101.2
+ cli_hashfile@CLAMAV_PRIVATE 0.101.2
+ cli_hashset_destroy@CLAMAV_PRIVATE 0.101.2
+ cli_hashstream@CLAMAV_PRIVATE 0.101.2
+ cli_hex2str@CLAMAV_PRIVATE 0.101.2
+ cli_hex2ui@CLAMAV_PRIVATE 0.101.2
+ cli_initroots@CLAMAV_PRIVATE 0.101.2
+ cli_isnumber@CLAMAV_PRIVATE 0.101.2
+ cli_js_destroy@CLAMAV_PRIVATE 0.101.2
+ cli_js_init@CLAMAV_PRIVATE 0.101.2
+ cli_js_output@CLAMAV_PRIVATE 0.101.2
+ cli_js_parse_done@CLAMAV_PRIVATE 0.101.2
+ cli_js_process_buffer@CLAMAV_PRIVATE 0.101.2
+ cli_ldbtokenize@CLAMAV_PRIVATE 0.101.2
+ cli_malloc@CLAMAV_PRIVATE 0.101.2
+ cli_memstr@CLAMAV_PRIVATE 0.101.2
+ cli_ole2_extract@CLAMAV_PRIVATE 0.101.2
+ cli_parse_add@CLAMAV_PRIVATE 0.101.2
+ cli_pcre_build@CLAMAV_PRIVATE 0.101.2
+ cli_pcre_freeoff@CLAMAV_PRIVATE 0.101.2
+ cli_pcre_init@CLAMAV_PRIVATE 0.101.2
+ cli_pcre_perf_events_destroy@CLAMAV_PRIVATE 0.101.2
+ cli_pcre_perf_print@CLAMAV_PRIVATE 0.101.2
+ cli_pcre_recaloff@CLAMAV_PRIVATE 0.101.2
+ cli_pcre_scanbuf@CLAMAV_PRIVATE 0.101.2
+ cli_ppt_vba_read@CLAMAV_PRIVATE 0.101.2
+ cli_printcxxver@CLAMAV_PRIVATE 0.101.2
+ cli_readn@CLAMAV_PRIVATE 0.101.2
+ cli_realloc@CLAMAV_PRIVATE 0.101.2
+ cli_regcomp@CLAMAV_PRIVATE 0.101.2
+ cli_regex2suffix@CLAMAV_PRIVATE 0.101.2
+ cli_regexec@CLAMAV_PRIVATE 0.101.2
+ cli_regfree@CLAMAV_PRIVATE 0.101.2
+ cli_rmdirs@CLAMAV_PRIVATE 0.101.2
+ cli_rndnum@CLAMAV_PRIVATE 0.101.2
+ cli_sanitize_filepath@CLAMAV_PRIVATE 0.101.2
+ cli_scanbuff@CLAMAV_PRIVATE 0.101.2
+ cli_sigopts_handler@CLAMAV_PRIVATE 0.101.2
+ cli_sigperf_events_destroy@CLAMAV_PRIVATE 0.101.2
+ cli_sigperf_print@CLAMAV_PRIVATE 0.101.2
+ cli_str2hex@CLAMAV_PRIVATE 0.101.2
+ cli_strbcasestr@CLAMAV_PRIVATE 0.101.2
+ cli_strdup@CLAMAV_PRIVATE 0.101.2
+ cli_strerror@CLAMAV_PRIVATE 0.101.2
+ cli_strlcat@CLAMAV_PRIVATE 0.101.2
+ cli_strlcpy@CLAMAV_PRIVATE 0.101.2
+ cli_strnstr@CLAMAV_PRIVATE 0.101.2
+ cli_strrcpy@CLAMAV_PRIVATE 0.101.2
+ cli_strtok@CLAMAV_PRIVATE 0.101.2
+ cli_strtokbuf@CLAMAV_PRIVATE 0.101.2
+ cli_strtokenize@CLAMAV_PRIVATE 0.101.2
+ cli_textbuffer_append_normalize@CLAMAV_PRIVATE 0.101.2
+ cli_unescape@CLAMAV_PRIVATE 0.101.2
+ cli_unlink@CLAMAV_PRIVATE 0.101.2
+ cli_url_canon@CLAMAV_PRIVATE 0.101.2
+ cli_utf16_to_utf8@CLAMAV_PRIVATE 0.101.2
+ cli_utf16toascii@CLAMAV_PRIVATE 0.101.2
+ cli_vba_inflate@CLAMAV_PRIVATE 0.101.2
+ cli_vba_readdir@CLAMAV_PRIVATE 0.101.2
+ cli_versig2@CLAMAV_PRIVATE 0.101.2
+ cli_versig@CLAMAV_PRIVATE 0.101.2
+ cli_warnmsg@CLAMAV_PRIVATE 0.101.2
+ cli_wm_decrypt_macro@CLAMAV_PRIVATE 0.101.2
+ cli_wm_readdir@CLAMAV_PRIVATE 0.101.2
+ cli_writen@CLAMAV_PRIVATE 0.101.2
+ decodeLine@CLAMAV_PRIVATE 0.101.2
+ disasmbuf@CLAMAV_PRIVATE 0.101.2
+ fmap@CLAMAV_PRIVATE 0.101.2
+ get_fpu_endian@CLAMAV_PRIVATE 0.101.2
+ have_clamjit@CLAMAV_PRIVATE 0.101.2
+ have_rar@CLAMAV_PRIVATE 0.101.2
+ html_normalise_map@CLAMAV_PRIVATE 0.101.2
+ html_normalise_mem@CLAMAV_PRIVATE 0.101.2
+ html_screnc_decode@CLAMAV_PRIVATE 0.101.2
+ html_tag_arg_free@CLAMAV_PRIVATE 0.101.2
+ init_domainlist@CLAMAV_PRIVATE 0.101.2
+ init_regex_list@CLAMAV_PRIVATE 0.101.2
+ init_whitelist@CLAMAV_PRIVATE 0.101.2
+ is_regex_ok@CLAMAV_PRIVATE 0.101.2
+ load_regex_matcher@CLAMAV_PRIVATE 0.101.2
  lsig_sub_matched@CLAMAV_PUBLIC 0.101.0
- messageCreate@CLAMAV_PRIVATE 0.101.1
- messageDestroy@CLAMAV_PRIVATE 0.101.1
- mpool_calloc@CLAMAV_PRIVATE 0.101.1
- mpool_create@CLAMAV_PRIVATE 0.101.1
- mpool_destroy@CLAMAV_PRIVATE 0.101.1
- mpool_free@CLAMAV_PRIVATE 0.101.1
- mpool_getstats@CLAMAV_PRIVATE 0.101.1
- phishingScan@CLAMAV_PRIVATE 0.101.1
- phishing_done@CLAMAV_PRIVATE 0.101.1
- phishing_init@CLAMAV_PRIVATE 0.101.1
- regex_list_add_pattern@CLAMAV_PRIVATE 0.101.1
- regex_list_done@CLAMAV_PRIVATE 0.101.1
- regex_list_match@CLAMAV_PRIVATE 0.101.1
- tableCreate@CLAMAV_PRIVATE 0.101.1
- tableDestroy@CLAMAV_PRIVATE 0.101.1
- tableFind@CLAMAV_PRIVATE 0.101.1
- tableInsert@CLAMAV_PRIVATE 0.101.1
- tableIterate@CLAMAV_PRIVATE 0.101.1
- tableRemove@CLAMAV_PRIVATE 0.101.1
- tableUpdate@CLAMAV_PRIVATE 0.101.1
- text_normalize_init@CLAMAV_PRIVATE 0.101.1
- text_normalize_map@CLAMAV_PRIVATE 0.101.1
- text_normalize_reset@CLAMAV_PRIVATE 0.101.1
- uniq_add@CLAMAV_PRIVATE 0.101.1
- uniq_free@CLAMAV_PRIVATE 0.101.1
- uniq_get@CLAMAV_PRIVATE 0.101.1
- uniq_init@CLAMAV_PRIVATE 0.101.1
+ messageCreate@CLAMAV_PRIVATE 0.101.2
+ messageDestroy@CLAMAV_PRIVATE 0.101.2
+ mpool_calloc@CLAMAV_PRIVATE 0.101.2
+ mpool_create@CLAMAV_PRIVATE 0.101.2
+ mpool_destroy@CLAMAV_PRIVATE 0.101.2
+ mpool_free@CLAMAV_PRIVATE 0.101.2
+ mpool_getstats@CLAMAV_PRIVATE 0.101.2
+ phishingScan@CLAMAV_PRIVATE 0.101.2
+ phishing_done@CLAMAV_PRIVATE 0.101.2
+ phishing_init@CLAMAV_PRIVATE 0.101.2
+ regex_list_add_pattern@CLAMAV_PRIVATE 0.101.2
+ regex_list_done@CLAMAV_PRIVATE 0.101.2
+ regex_list_match@CLAMAV_PRIVATE 0.101.2
+ tableCreate@CLAMAV_PRIVATE 0.101.2
+ tableDestroy@CLAMAV_PRIVATE 0.101.2
+ tableFind@CLAMAV_PRIVATE 0.101.2
+ tableInsert@CLAMAV_PRIVATE 0.101.2
+ tableIterate@CLAMAV_PRIVATE 0.101.2
+ tableRemove@CLAMAV_PRIVATE 0.101.2
+ tableUpdate@CLAMAV_PRIVATE 0.101.2
+ text_normalize_init@CLAMAV_PRIVATE 0.101.2
+ text_normalize_map@CLAMAV_PRIVATE 0.101.2
+ text_normalize_reset@CLAMAV_PRIVATE 0.101.2
+ uniq_add@CLAMAV_PRIVATE 0.101.2
+ uniq_free@CLAMAV_PRIVATE 0.101.2
+ uniq_get@CLAMAV_PRIVATE 0.101.2
+ uniq_init@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@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@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);
   }
 

--- End Message ---
--- Begin Message ---
Sebastian Andrzej Siewior:
> Package: release.debian.org
> User: release.debian.org@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
> 

Unblocked, thanks.
~Niels

--- End Message ---

Reply to: