Module Name:    src
Committed By:   christos
Date:           Mon Jun 22 21:16:02 UTC 2015

Modified Files:
        src/lib/libc/db/hash: hash.c

Log Message:
Fix hash iteration that deletes the current element under the cursor by
adjusting the position of the iterator appropriately.
XXX: pullup 7


To generate a diff of this commit:
cvs rdiff -u -r1.34 -r1.35 src/lib/libc/db/hash/hash.c

Please note that diffs are not public domain; they are subject to the
copyright notices on the relevant files.

Modified files:

Index: src/lib/libc/db/hash/hash.c
diff -u src/lib/libc/db/hash/hash.c:1.34 src/lib/libc/db/hash/hash.c:1.35
--- src/lib/libc/db/hash/hash.c:1.34	Mon Jun 22 14:50:06 2015
+++ src/lib/libc/db/hash/hash.c	Mon Jun 22 17:16:02 2015
@@ -1,4 +1,4 @@
-/*	$NetBSD: hash.c,v 1.34 2015/06/22 18:50:06 christos Exp $	*/
+/*	$NetBSD: hash.c,v 1.35 2015/06/22 21:16:02 christos Exp $	*/
 
 /*-
  * Copyright (c) 1990, 1993, 1994
@@ -37,7 +37,7 @@
 #endif
 
 #include <sys/cdefs.h>
-__RCSID("$NetBSD: hash.c,v 1.34 2015/06/22 18:50:06 christos Exp $");
+__RCSID("$NetBSD: hash.c,v 1.35 2015/06/22 21:16:02 christos Exp $");
 
 #include "namespace.h"
 #include <sys/param.h>
@@ -690,6 +690,27 @@ found:
 	case HASH_DELETE:
 		if (__delpair(hashp, rbufp, ndx))
 			return (ERROR);
+		/*
+		 * Our index lags 2 behind on the same page when we are
+		 * deleting the element pointed to by the index; otherwise
+		 * deleting randomly from an iterated hash produces undefined
+		 * results.
+		 */
+		if (ndx != hashp->cndx - 2 || rbufp != hashp->cpage)
+			break;
+
+		if (hashp->cndx > 1) {
+			/* Move back one element */
+			hashp->cndx -= 2;
+		} else {
+			/*
+			 * Move back one page, and indicate to go to the last
+			 * element of the previous page by setting cndx to -1
+			 */
+			hashp->cbucket--;
+			hashp->cpage = NULL;
+			hashp->cndx = -1;
+		}
 		break;
 	default:
 		abort();
@@ -725,7 +746,7 @@ next_bucket:
 		if (!(bufp = hashp->cpage)) {
 			for (bucket = hashp->cbucket;
 			    bucket <= (uint32_t)hashp->MAX_BUCKET;
-			    bucket++, hashp->cndx = 1) {
+			    bucket++) {
 				bufp = __get_buf(hashp, bucket, NULL, 0);
 				if (!bufp)
 					return (ERROR);
@@ -739,10 +760,18 @@ next_bucket:
 				hashp->cbucket = -1;
 				return (ABNORMAL);
 			}
+			if (hashp->cndx == -1) {
+				/* move to the last element of the page */
+				hashp->cndx = 1;
+				while (bp[hashp->cndx - 1] != 0)
+					hashp->cndx += 2;
+			} else {
+				/* start on the first element */
+				hashp->cndx = 1;
+			}
 		} else {
 			bp = (uint16_t *)(void *)hashp->cpage->page;
 			if (flag == R_NEXT || flag == 0) {
-				hashp->cndx += 2;
 				if (hashp->cndx > bp[0]) {
 					hashp->cpage = NULL;
 					hashp->cbucket++;
@@ -781,6 +810,7 @@ next_bucket:
 		data->data = (uint8_t *)hashp->cpage->page + bp[ndx + 1];
 		data->size = bp[ndx] - bp[ndx + 1];
 	}
+	hashp->cndx += 2;
 	return (SUCCESS);
 }
 

Reply via email to