2f4f5e
diff -Naurp pcp-4.3.2.orig/qa/1280 pcp-4.3.2/qa/1280
2f4f5e
--- pcp-4.3.2.orig/qa/1280	1970-01-01 10:00:00.000000000 +1000
2f4f5e
+++ pcp-4.3.2/qa/1280	2020-11-04 10:58:30.575985524 +1100
2f4f5e
@@ -0,0 +1,86 @@
2f4f5e
+#!/bin/sh
2f4f5e
+# PCP QA Test No. 1280
2f4f5e
+# segv in __pmGetArchiveEnd_ctx()
2f4f5e
+#
2f4f5e
+# Copyright (c) 2020 Ken McDonell.  All Rights Reserved.
2f4f5e
+#
2f4f5e
+
2f4f5e
+if [ $# -eq 0 ]
2f4f5e
+then
2f4f5e
+    seq=`basename $0`
2f4f5e
+    echo "QA output created by $seq"
2f4f5e
+else
2f4f5e
+    # use $seq from caller, unless not set
2f4f5e
+    [ -n "$seq" ] || seq=`basename $0`
2f4f5e
+    echo "QA output created by `basename $0` $*"
2f4f5e
+fi
2f4f5e
+
2f4f5e
+# get standard environment, filters and checks
2f4f5e
+. ./common.product
2f4f5e
+. ./common.filter
2f4f5e
+. ./common.check
2f4f5e
+
2f4f5e
+do_valgrind=false
2f4f5e
+if [ "$1" = "--valgrind" ]
2f4f5e
+then
2f4f5e
+    _check_valgrind
2f4f5e
+    do_valgrind=true
2f4f5e
+fi
2f4f5e
+
2f4f5e
+if which unxz >/dev/null
2f4f5e
+then
2f4f5e
+    :
2f4f5e
+else
2f4f5e
+    _notrun "need unxz application installed"
2f4f5e
+fi
2f4f5e
+
2f4f5e
+_cleanup()
2f4f5e
+{
2f4f5e
+    cd $here
2f4f5e
+    $sudo rm -rf $tmp $tmp.*
2f4f5e
+}
2f4f5e
+
2f4f5e
+status=0	# success is the default!
2f4f5e
+$sudo rm -rf $tmp $tmp.* $seq.full
2f4f5e
+trap "_cleanup; exit \$status" 0 1 2 3 15
2f4f5e
+
2f4f5e
+_doit()
2f4f5e
+{
2f4f5e
+    if $do_valgrind
2f4f5e
+    then
2f4f5e
+	_run_valgrind pmdumplog -z -Dlog -L 20180416.10.00
2f4f5e
+    else
2f4f5e
+	pmdumplog -z -Dlog -L 20180416.10.00 2>>$here/$seq.full
2f4f5e
+    fi
2f4f5e
+}
2f4f5e
+
2f4f5e
+# real QA test starts here
2f4f5e
+mkdir $tmp
2f4f5e
+cp archives/20180416.10.00* $tmp
2f4f5e
+cd $tmp
2f4f5e
+for f in *.xz
2f4f5e
+do
2f4f5e
+    unxz $f
2f4f5e
+done
2f4f5e
+
2f4f5e
+echo "=== full archive ==="
2f4f5e
+_doit
2f4f5e
+
2f4f5e
+echo
2f4f5e
+echo "=== volume 3 missing ==="
2f4f5e
+rm 20180416.10.00.3
2f4f5e
+_doit
2f4f5e
+
2f4f5e
+echo
2f4f5e
+echo "=== volume 2 truncated ==="
2f4f5e
+size=`stat 20180416.10.00.2 | sed -n -e '/Size:/{
2f4f5e
+s/.*Size: *//
2f4f5e
+s/ .*//
2f4f5e
+p
2f4f5e
+}'`
2f4f5e
+size=`expr $size - 8`
2f4f5e
+truncate -s $size 20180416.10.00.2
2f4f5e
+_doit
2f4f5e
+
2f4f5e
+# success, all done
2f4f5e
+exit
2f4f5e
diff -Naurp pcp-4.3.2.orig/qa/1280.out pcp-4.3.2/qa/1280.out
2f4f5e
--- pcp-4.3.2.orig/qa/1280.out	1970-01-01 10:00:00.000000000 +1000
2f4f5e
+++ pcp-4.3.2/qa/1280.out	2020-11-04 10:58:30.575985524 +1100
2f4f5e
@@ -0,0 +1,30 @@
2f4f5e
+QA output created by 1280
2f4f5e
+=== full archive ===
2f4f5e
+Note: timezone set to local timezone of host "brolley-t530" from archive
2f4f5e
+
2f4f5e
+Log Label (Log Format Version 2)
2f4f5e
+Performance metrics from host brolley-t530
2f4f5e
+    commencing Mon Apr 16 10:01:25.325401 2018
2f4f5e
+    ending     Mon Apr 16 14:32:47.409469 2018
2f4f5e
+Archive timezone: EDT+4
2f4f5e
+PID for pmlogger: 7047
2f4f5e
+
2f4f5e
+=== volume 3 missing ===
2f4f5e
+Note: timezone set to local timezone of host "brolley-t530" from archive
2f4f5e
+
2f4f5e
+Log Label (Log Format Version 2)
2f4f5e
+Performance metrics from host brolley-t530
2f4f5e
+    commencing Mon Apr 16 10:01:25.325401 2018
2f4f5e
+    ending     Mon Apr 16 14:26:25.396920 2018
2f4f5e
+Archive timezone: EDT+4
2f4f5e
+PID for pmlogger: 7047
2f4f5e
+
2f4f5e
+=== volume 2 truncated ===
2f4f5e
+Note: timezone set to local timezone of host "brolley-t530" from archive
2f4f5e
+
2f4f5e
+Log Label (Log Format Version 2)
2f4f5e
+Performance metrics from host brolley-t530
2f4f5e
+    commencing Mon Apr 16 10:01:25.325401 2018
2f4f5e
+    ending     Mon Apr 16 14:26:25.380430 2018
2f4f5e
+Archive timezone: EDT+4
2f4f5e
+PID for pmlogger: 7047
2f4f5e
diff -Naurp pcp-4.3.2.orig/qa/1281 pcp-4.3.2/qa/1281
2f4f5e
--- pcp-4.3.2.orig/qa/1281	1970-01-01 10:00:00.000000000 +1000
2f4f5e
+++ pcp-4.3.2/qa/1281	2020-11-04 10:58:30.575985524 +1100
2f4f5e
@@ -0,0 +1,52 @@
2f4f5e
+#!/bin/sh
2f4f5e
+# PCP QA Test No. 1281
2f4f5e
+# segv in __pmGetArchiveEnd_ctx()
2f4f5e
+#
2f4f5e
+# -- valgrind version of qa/1280
2f4f5e
+#
2f4f5e
+# Copyright (c) 2020 Ken McDonell.  All Rights Reserved.
2f4f5e
+#
2f4f5e
+
2f4f5e
+if [ $# -eq 0 ]
2f4f5e
+then
2f4f5e
+    seq=`basename $0`
2f4f5e
+    echo "QA output created by $seq"
2f4f5e
+else
2f4f5e
+    # use $seq from caller, unless not set
2f4f5e
+    [ -n "$seq" ] || seq=`basename $0`
2f4f5e
+    echo "QA output created by `basename $0` $*"
2f4f5e
+fi
2f4f5e
+
2f4f5e
+# get standard environment, filters and checks
2f4f5e
+. ./common.product
2f4f5e
+. ./common.filter
2f4f5e
+. ./common.check
2f4f5e
+
2f4f5e
+do_valgrind=false
2f4f5e
+if [ "$1" = "--valgrind" ]
2f4f5e
+then
2f4f5e
+    _check_valgrind
2f4f5e
+    do_valgrind=true
2f4f5e
+fi
2f4f5e
+
2f4f5e
+_cleanup()
2f4f5e
+{
2f4f5e
+    cd $here
2f4f5e
+    $sudo rm -rf $tmp $tmp.*
2f4f5e
+}
2f4f5e
+
2f4f5e
+status=0	# success is the default!
2f4f5e
+$sudo rm -rf $tmp $tmp.* $seq.full
2f4f5e
+trap "_cleanup; exit \$status" 0 1 2 3 15
2f4f5e
+
2f4f5e
+# real QA test starts here
2f4f5e
+export seq
2f4f5e
+./1280 --valgrind \
2f4f5e
+| $PCP_AWK_PROG '
2f4f5e
+skip == 1 && $1 == "==="	{ skip = 0 }
2f4f5e
+/^=== std err ===/		{ skip = 1 }
2f4f5e
+skip == 0		{ print }
2f4f5e
+skip == 1		{ print >"'$here/$seq.full'" }'
2f4f5e
+
2f4f5e
+# success, all done
2f4f5e
+exit
2f4f5e
diff -Naurp pcp-4.3.2.orig/qa/1281.out pcp-4.3.2/qa/1281.out
2f4f5e
--- pcp-4.3.2.orig/qa/1281.out	1970-01-01 10:00:00.000000000 +1000
2f4f5e
+++ pcp-4.3.2/qa/1281.out	2020-11-04 10:58:30.575985524 +1100
2f4f5e
@@ -0,0 +1,55 @@
2f4f5e
+QA output created by 1281
2f4f5e
+QA output created by 1280 --valgrind
2f4f5e
+=== full archive ===
2f4f5e
+=== std out ===
2f4f5e
+Note: timezone set to local timezone of host "brolley-t530" from archive
2f4f5e
+
2f4f5e
+Log Label (Log Format Version 2)
2f4f5e
+Performance metrics from host brolley-t530
2f4f5e
+    commencing Mon Apr 16 10:01:25.325401 2018
2f4f5e
+    ending     Mon Apr 16 14:32:47.409469 2018
2f4f5e
+Archive timezone: EDT+4
2f4f5e
+PID for pmlogger: 7047
2f4f5e
+=== filtered valgrind report ===
2f4f5e
+Memcheck, a memory error detector
2f4f5e
+Command: pmdumplog -z -Dlog -L 20180416.10.00
2f4f5e
+LEAK SUMMARY:
2f4f5e
+definitely lost: 0 bytes in 0 blocks
2f4f5e
+indirectly lost: 0 bytes in 0 blocks
2f4f5e
+ERROR SUMMARY: 0 errors from 0 contexts ...
2f4f5e
+
2f4f5e
+=== volume 3 missing ===
2f4f5e
+=== std out ===
2f4f5e
+Note: timezone set to local timezone of host "brolley-t530" from archive
2f4f5e
+
2f4f5e
+Log Label (Log Format Version 2)
2f4f5e
+Performance metrics from host brolley-t530
2f4f5e
+    commencing Mon Apr 16 10:01:25.325401 2018
2f4f5e
+    ending     Mon Apr 16 14:26:25.396920 2018
2f4f5e
+Archive timezone: EDT+4
2f4f5e
+PID for pmlogger: 7047
2f4f5e
+=== filtered valgrind report ===
2f4f5e
+Memcheck, a memory error detector
2f4f5e
+Command: pmdumplog -z -Dlog -L 20180416.10.00
2f4f5e
+LEAK SUMMARY:
2f4f5e
+definitely lost: 0 bytes in 0 blocks
2f4f5e
+indirectly lost: 0 bytes in 0 blocks
2f4f5e
+ERROR SUMMARY: 0 errors from 0 contexts ...
2f4f5e
+
2f4f5e
+=== volume 2 truncated ===
2f4f5e
+=== std out ===
2f4f5e
+Note: timezone set to local timezone of host "brolley-t530" from archive
2f4f5e
+
2f4f5e
+Log Label (Log Format Version 2)
2f4f5e
+Performance metrics from host brolley-t530
2f4f5e
+    commencing Mon Apr 16 10:01:25.325401 2018
2f4f5e
+    ending     Mon Apr 16 14:26:25.380430 2018
2f4f5e
+Archive timezone: EDT+4
2f4f5e
+PID for pmlogger: 7047
2f4f5e
+=== filtered valgrind report ===
2f4f5e
+Memcheck, a memory error detector
2f4f5e
+Command: pmdumplog -z -Dlog -L 20180416.10.00
2f4f5e
+LEAK SUMMARY:
2f4f5e
+definitely lost: 0 bytes in 0 blocks
2f4f5e
+indirectly lost: 0 bytes in 0 blocks
2f4f5e
+ERROR SUMMARY: 0 errors from 0 contexts ...
2f4f5e
diff -Naurp pcp-4.3.2.orig/qa/417.out pcp-4.3.2/qa/417.out
2f4f5e
--- pcp-4.3.2.orig/qa/417.out	2018-06-19 09:19:05.000000000 +1000
2f4f5e
+++ pcp-4.3.2/qa/417.out	2020-11-04 10:44:15.722280608 +1100
2f4f5e
@@ -253,6 +253,11 @@ Temporal Index
2f4f5e
 === pmdumplog -t, no index ===
2f4f5e
 Note: timezone set to local timezone of host "moomba" from archive
2f4f5e
 
2f4f5e
+pmdumplog: Cannot locate end of archive bad: Corrupted record in a PCP archive log
2f4f5e
+
2f4f5e
+WARNING: This archive is sufficiently damaged that it may not be possible to
2f4f5e
+         produce complete information.  Continuing and hoping for the best.
2f4f5e
+
2f4f5e
 
2f4f5e
 Temporal Index
2f4f5e
 		Log Vol    end(meta)     end(log)
2f4f5e
diff -Naurp pcp-4.3.2.orig/qa/group pcp-4.3.2/qa/group
2f4f5e
--- pcp-4.3.2.orig/qa/group	2020-11-04 10:43:55.184527945 +1100
2f4f5e
+++ pcp-4.3.2/qa/group	2020-11-04 10:58:43.746826907 +1100
2f4f5e
@@ -1614,6 +1614,8 @@ BAD
2f4f5e
 1269 libpcp local kernel
2f4f5e
 1274 pmlogextract pmdumplog labels help local sanity
2f4f5e
 1276 pmmgr containers local
2f4f5e
+1280 archive pmdumplog local
2f4f5e
+1281 archive pmdumplog valgrind local
2f4f5e
 1287 pmda.install pmda.prometheus local python
2f4f5e
 1289 pmval archive multi-archive decompress-xz local pmlogextract
2f4f5e
 1294 libpcp_mmv labels local valgrind
2f4f5e
diff -Naurp pcp-4.3.2.orig/src/libpcp/src/logutil.c pcp-4.3.2/src/libpcp/src/logutil.c
2f4f5e
--- pcp-4.3.2.orig/src/libpcp/src/logutil.c	2019-02-26 07:30:38.000000000 +1100
2f4f5e
+++ pcp-4.3.2/src/libpcp/src/logutil.c	2020-11-04 10:44:15.722280608 +1100
2f4f5e
@@ -2558,6 +2558,11 @@ __pmGetArchiveEnd_ctx(__pmContext *ctxp,
2f4f5e
     found = 0;
2f4f5e
     sts = PM_ERR_LOGREC;	/* default error condition */
2f4f5e
     f = NULL;
2f4f5e
+
2f4f5e
+    /*
2f4f5e
+     * start at last volume and work backwards until success or
2f4f5e
+     * failure
2f4f5e
+     */
2f4f5e
     for (vol = lcp->l_maxvol; vol >= lcp->l_minvol; vol--) {
2f4f5e
 	if (acp->ac_curvol == vol) {
2f4f5e
 	    f = acp->ac_mfp;
2f4f5e
@@ -2571,11 +2576,7 @@ __pmGetArchiveEnd_ctx(__pmContext *ctxp,
2f4f5e
 
2f4f5e
 	if (__pmFstat(f, &sbuf) < 0) {
2f4f5e
 	    /* if we can't stat() this one, then try previous volume(s) */
2f4f5e
-	    if (f != acp->ac_mfp) {
2f4f5e
-		__pmFclose(f);
2f4f5e
-		f = NULL;
2f4f5e
-	    }
2f4f5e
-	    continue;
2f4f5e
+	    goto prior_vol;
2f4f5e
 	}
2f4f5e
 
2f4f5e
 	if (vol == lcp->l_maxvol && sbuf.st_size == lcp->l_physend) {
2f4f5e
@@ -2588,16 +2589,14 @@ __pmGetArchiveEnd_ctx(__pmContext *ctxp,
2f4f5e
 
2f4f5e
 	/* if this volume is empty, try previous volume */
2f4f5e
 	if (sbuf.st_size <= (int)sizeof(__pmLogLabel) + 2*(int)sizeof(int)) {
2f4f5e
-	    if (f != acp->ac_mfp) {
2f4f5e
-		__pmFclose(f);
2f4f5e
-		f = NULL;
2f4f5e
-	    }
2f4f5e
-	    continue;
2f4f5e
+	    goto prior_vol;
2f4f5e
 	}
2f4f5e
 
2f4f5e
 	physend = (__pm_off_t)sbuf.st_size;
2f4f5e
 	if (sizeof(off_t) > sizeof(__pm_off_t)) {
2f4f5e
+	    /* 64-bit off_t */
2f4f5e
 	    if (physend != sbuf.st_size) {
2f4f5e
+		/* oops, 32-bit offset not the same */
2f4f5e
 		pmNotifyErr(LOG_ERR, "pmGetArchiveEnd: PCP archive file"
2f4f5e
 			" (meta) too big (%"PRIi64" bytes)\n",
2f4f5e
 			(uint64_t)sbuf.st_size);
2f4f5e
@@ -2621,18 +2620,17 @@ __pmGetArchiveEnd_ctx(__pmContext *ctxp,
2f4f5e
 	 */
2f4f5e
 	logend = (int)sizeof(__pmLogLabel) + 2*(int)sizeof(int);
2f4f5e
 	for (i = lcp->l_numti - 1; i >= 0; i--) {
2f4f5e
-	    if (lcp->l_ti[i].ti_vol != vol) {
2f4f5e
-		if (f != acp->ac_mfp) {
2f4f5e
-		    __pmFclose(f);
2f4f5e
-		    f = NULL;
2f4f5e
-		}
2f4f5e
+	    if (lcp->l_ti[i].ti_vol != vol)
2f4f5e
 		continue;
2f4f5e
-	    }
2f4f5e
 	    if (lcp->l_ti[i].ti_log <= physend) {
2f4f5e
 		logend = lcp->l_ti[i].ti_log;
2f4f5e
 		break;
2f4f5e
 	    }
2f4f5e
 	}
2f4f5e
+	if (i < 0) {
2f4f5e
+	    /* no dice in the temporal index, try previous volume */
2f4f5e
+	    goto prior_vol;
2f4f5e
+	}
2f4f5e
 
2f4f5e
 	/*
2f4f5e
 	 * Now chase it forwards from the last index entry ...
2f4f5e
@@ -2642,6 +2640,7 @@ __pmGetArchiveEnd_ctx(__pmContext *ctxp,
2f4f5e
 	 *	valid record, so if not at start of volume, back up one
2f4f5e
 	 *	record, then scan forwards.
2f4f5e
 	 */
2f4f5e
+	assert(f != NULL);
2f4f5e
 	__pmFseek(f, (long)logend, SEEK_SET);
2f4f5e
 	if (logend > (int)sizeof(__pmLogLabel) + 2*(int)sizeof(int)) {
2f4f5e
 	    if (paranoidLogRead(ctxp, PM_MODE_BACK, f, &rp) < 0) {
2f4f5e
@@ -2681,10 +2680,17 @@ __pmGetArchiveEnd_ctx(__pmContext *ctxp,
2f4f5e
 	if (found)
2f4f5e
 	    break;
2f4f5e
 
2f4f5e
+prior_vol:
2f4f5e
 	/*
2f4f5e
 	 * this probably means this volume contains no useful records,
2f4f5e
 	 * try the previous volume
2f4f5e
 	 */
2f4f5e
+	if (f != acp->ac_mfp) {
2f4f5e
+	    /* f comes from _logpeek(), close it */
2f4f5e
+	    __pmFclose(f);
2f4f5e
+	    f = NULL;
2f4f5e
+	}
2f4f5e
+
2f4f5e
     }/*for*/
2f4f5e
 
2f4f5e
     if (f == acp->ac_mfp)