Skip site navigation (1)Skip section navigation (2)
Date:      Sat, 28 Mar 2009 06:47:05 +0000 (UTC)
From:      Xin LI <delphij@FreeBSD.org>
To:        src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org
Subject:   svn commit: r190494 - head/lib/libc/db/hash
Message-ID:  <200903280647.n2S6l56R087480@svn.freebsd.org>

next in thread | raw e-mail | index | archive | help
Author: delphij
Date: Sat Mar 28 06:47:05 2009
New Revision: 190494
URL: http://svn.freebsd.org/changeset/base/190494

Log:
   - If (keysize+datasize)%(bsize=14)==0, insertion of a `big key' would cause
     an invariant (actually, an ugly hack) to fail, and all Hell would break
     loose.
  
     When deleting a big key, the offset of an empty page should be bsize, not
     bsize-1; otherwise an insertion into the empty page will cause the new key to
     be elongated by 1 byte.
  
     Make the packing more dense in a couple of cases.
  
   - fix NULL dereference exposed on big bsize values;
  
  Obtained from:	NetBSD via OpenBSD

Modified:
  head/lib/libc/db/hash/hash_bigkey.c

Modified: head/lib/libc/db/hash/hash_bigkey.c
==============================================================================
--- head/lib/libc/db/hash/hash_bigkey.c	Sat Mar 28 06:40:48 2009	(r190493)
+++ head/lib/libc/db/hash/hash_bigkey.c	Sat Mar 28 06:47:05 2009	(r190494)
@@ -118,18 +118,30 @@ __big_insert(HTAB *hashp, BUFHEAD *bufp,
 			return (-1);
 		n = p[0];
 		if (!key_size) {
-			if (FREESPACE(p)) {
-				move_bytes = MIN(FREESPACE(p), val_size);
+			space = FREESPACE(p);
+			if (space) {
+				move_bytes = MIN(space, val_size);
+				/*
+				 * If the data would fit exactly in the
+				 * remaining space, we must overflow it to the
+				 * next page; otherwise the invariant that the
+				 * data must end on a page with FREESPACE
+				 * non-zero would fail.
+				 */
+				if (space == val_size && val_size == val->size)
+					goto toolarge;
 				off = OFFSET(p) - move_bytes;
-				p[n] = off;
 				memmove(cp + off, val_data, move_bytes);
 				val_data += move_bytes;
 				val_size -= move_bytes;
+				p[n] = off;
 				p[n - 2] = FULL_KEY_DATA;
 				FREESPACE(p) = FREESPACE(p) - move_bytes;
 				OFFSET(p) = off;
-			} else
+			} else {
+			toolarge:
 				p[n - 2] = FULL_KEY;
+			}
 		}
 		p = (u_int16_t *)bufp->page;
 		cp = bufp->page;
@@ -239,12 +251,12 @@ __big_delete(HTAB *hashp, BUFHEAD *bufp)
 	n -= 2;
 	bp[0] = n;
 	FREESPACE(bp) = hashp->BSIZE - PAGE_META(n);
-	OFFSET(bp) = hashp->BSIZE - 1;
+	OFFSET(bp) = hashp->BSIZE;
 
 	bufp->flags |= BUF_MOD;
 	if (rbufp)
 		__free_ovflpage(hashp, rbufp);
-	if (last_bfp != rbufp)
+	if (last_bfp && last_bfp != rbufp)
 		__free_ovflpage(hashp, last_bfp);
 
 	hashp->NKEYS--;



Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200903280647.n2S6l56R087480>