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--;
_______________________________________________
svn-src-all@freebsd.org mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to